Zig 0.8.0 error: values of type '(enum literal)' must be comptime known

Zig 0.8.0 error: values of type '(enum literal)' must be comptime known

在 Zig 0.8.0 中,当切换 u8 字符以获取枚举类型时,我遇到了一个奇怪的编译器错误,代码如下:

.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
}

错误是:

.\lib.zig:137:36: error: values of type '(enum literal)' must be comptime known
                        '<' => if (is_long) .lte else .lt,
                               ^

通常在 zig 中,“must be comptime known”消息意味着我在运行时值上遗漏了类型签名,例如 const x = 3;。但是,switch 表达式中没有签名,并且编译器无论如何都应该知道类型是什么,因为字段 .op_type 采用 Op 类型枚举。

我能够通过使用 switch 语句而不是用于分配占位符值的表达式来解决问题。结果很糟糕:

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
}

我发布这个问题的原因是我不太了解第一个实现的问题,我想看看是否有比我想出的更好的解决方案。

您遇到的是枚举文字的怪癖。当您编写 .sub 时,首先这是一个尚未被强制转换为实际枚举类型的枚举文字。通常这个过程是透明的,但在这种情况下,类型系统似乎无法通过你的 if 表达式“推理”。

这可能会在自托管编译器中得到改进,但与此同时,解决方案是在遇到此问题时简单地明确枚举类型。

这是编译代码片段的简化版本:https://zig.godbolt.org/z/zeTnf3a67