In Zig 0.8.0, When switching over u8 characters to get an enum type, I encountered a strange compiler error from this code:
.op_type = switch(c1) {
'+' => .add, '-' => .sub,
'*' => .mul, '/' => .div,
'%' => .mod, '^' => .exp,
'|' => .bor, '~' => .bxor,
'&' => .band,
'<' => if (is_long) .lte else .lt,
'>' => if (is_long) .gte else .gt,
'=' => if (is_long) .eq else .nop,
'!' => if (is_long) .neq else return TokenError.NotAToken,
else => unreachable
}
The error was:
.\lib.zig:137:36: error: values of type '(enum literal)' must be comptime known
'<' => if (is_long) .lte else .lt,
^
Normally in zig, "must be comptime known
" messages mean that I have left off a type signature on a runtime value, such as const x = 3;
. However, there aren't signatures in a switch expression, and the compiler should know what the type is anyway because the field .op_type
takes an Op
type enum.
I was able to solve the issue by using a switch statement instead of an expression, which I used to assign a placeholder value. The result is atrocious:
var op_type: Op = undefined;
switch(c1) {
'+' => op_type = .add, '-' => op_type = .sub,
'*' => op_type = .mul, '/' => op_type = .div,
'%' => op_type = .mod, '^' => op_type = .exp,
'|' => op_type = .bor, '~' => op_type = .bxor,
'&' => op_type = .band,
'<' => if (is_long) {op_type = .lte;} else {op_type = .lt;},
'>' => if (is_long) {op_type = .gte;} else {op_type = .gt;},
'=' => if (is_long) {op_type = .eq ;} else {op_type = .nop;},
'!' => if (is_long) {op_type = .neq;} else return TokenError.NotAToken,
else => unreachable
}
...
... {
...
.op_type = op_type
}
The reason I'm posting this question is that I don't really understand the problem with the first implementation, and I would like to see if there is a better solution than what I came up with.
What you're experiencing is a quirk of enum literals. When you're writing .sub
, at first that's an enum literal that is yet to be coerced to an actual enum type. Normally this process works transparently but in this case the type system doesn't seem to be able to "reason" through your if
expressions.
It might be that this will be improved in the self-hosted compiler, but in the meantime the solution is to simply be explicit about the enum type when you encounter this problem.
Here's a simplified version of your code snippet that compiles: https://zig.godbolt.org/z/zeTnf3a67