zig
zig copied to clipboard
Unexpected results with `@typeInfo` on `anyerror!noreturn`
Zig Version
0.11.0-dev.3704+729a051e9
Steps to Reproduce and Observed Behavior
fn main() anyerror!noreturn {
return error.a;
}
test {
switch (@typeInfo(@typeInfo(@TypeOf(main)).Fn.return_type.?)) {
.ErrorUnion => {
const result = main() catch undefined;
// see for yourself: @compileLog(@TypeOf(result));
switch (@TypeOf(result)) {
noreturn => return error.expected,
else => return error.unexpected,
}
},
else => return error.unexpected,
}
}
$ zig test x.zig
Test [1/1] test_0... FAIL (unexpected)
/home/wooster/Desktop/zig/x.zig:12:25: 0x20ebf7 in test_0 (test)
else => return error.unexpected,
^
Expected Behavior
Replace all occurrences of noreturn
with something else like u8
:
$ zig test x.zig
Test [1/1] test_0... FAIL (expected)
/home/wooster/Desktop/zig/x.zig:11:23: 0x20ec17 in test_0 (test)
u8 => return error.expected,
^
As a result of this bug, this program can be zig run
:
pub fn main() !noreturn {
return error.a;
}
$ zig run x.zig
error: a
/home/wooster/Desktop/zig/x.zig:20:5: 0x20b008 in main (x)
return error.a;
^
But I expect https://github.com/ziglang/zig/blob/a72d634b731952ee227d026c27e83c5702dcea4a/lib/std/start.zig#L623 to be hit.
The type of (_!noreturn) catch _
is noreturn
.
Drive-by opinion: The compiler should actually issue a compile error once analysis reaches the instantiation of a value of type noreturn
(in this case via coercion from undefined
), since that is a semantic error: noreturn
means "guaranteed to never be instantiated".
Compare with a more explicitly annotated version:
const result = main() catch
@as(noreturn, block: { //we guarantee this expression diverts control flow, not providing a value
break :block undefined; //we break the guarantee (provide a value without diverting control flow) - this is compile-time checkable illegal behavior
});
(Alternatively it could also translate the expression to a call to @panic("instantiated noreturn")
, but compile errors > runtime crashes.)
See #13807 and #15909