Error union payload cannot cast to the same optional error union payload

I’m pretty sure this code should work, right? Type error{Usage}!T should be castable to type error{Usage}!?T.

const std = @import("std");

fn parseValue(comptime T: type, buf: [:0]const u8) error{Usage}!T {
    switch (@typeInfo(T)) {
        .@"enum" => return std.meta.stringToEnum(T, buf) orelse return error.Usage,
        .optional => |info| return parseValue(info.child, buf),
        else => comptime unreachable,
    }
}

test {
    const Level = enum { err, warn, info, debug };
    try std.testing.expectEqual(.debug, parseValue(?Level, "debug"));
}
$ zig test src/argparser/test2.zig 
src/argparser/test2.zig:6:46: error: expected type 'error{Usage}!?test2.test_0.Level', found 'error{Usage}!test2.test_0.Level'
        .optional => |info| return parseValue(info.child, buf),
                                   ~~~~~~~~~~^~~~~~~~~~~~~~~~~
src/argparser/test2.zig:6:46: note: error union payload 'test2.test_0.Level' cannot cast into error union payload '?test2.test_0.Level'
src/argparser/test2.zig:12:19: note: enum declared here
    const Level = enum { err, warn, info, debug };
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/argparser/test2.zig:3:64: note: function return type declared here
fn parseValue(comptime T: type, buf: [:0]const u8) error{Usage}!T {
                                                   ~~~~~~~~~~~~^~

needs a return try:

const std = @import("std");

fn returns2(comptime T: type) error{Usage}!T {
    switch (@typeInfo(T)) {
        .int => return 2,
        .optional => |info| return try returns2(info.child),
        else => return error.Usage,
    }
}

test {
    try std.testing.expectEqual(2, returns2(?i32));
}

https://codeberg.org/ziglang/zig/issues/31631#issue-3909360

1 Like