/zig-derive-error-set-example

Example to reproduce unexpected behavior from the zig compiler under `src/main.zig`.

Primary LanguageZig

zig: derived error sets inference

Example to reproduce unexpected behavior from the zig compiler under src/main.zig:

const std = @import("std");

// We want to hide this from the user
const InternalError = error{Internal};

// We want to expose this to the user
pub const PublicError = error{Public};

fn internal_function() !u32 {
    if (true) {
        return error.Internal;
    } else {
        return error.PublicError;
    }
    return 1;
}

// Handles the Internal error but exposes the Public error
fn public_api() PublicError!u32 {
    if (internal_function()) |result| {
        return result;
    } else |err| switch (err) {
        error.Internal => return 0,
        // err can no longer be error.Internal
        else => return err,
    }
}

pub fn main() !void {
    const a = public_api();
    try std.debug.assert(a == 0);
}

test "simple test" {
    const a = public_api();
    try std.testing.expectEqual(a, 0);
}

We get this error when running zig test:

$ zig test src/main.zig

src/main.zig:24:24: error: expected type 'error{Public}', found '@typeInfo(@typeInfo(@TypeOf(main.internal_function)).Fn.return_type.?).ErrorUnion.error_set'
        else => return err,
                       ^~~
src/main.zig:24:24: note: 'error.Internal' not a member of destination error set
referenced by:
    test.simple test: src/main.zig:34:15
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

I would've expected the compiler to figure out that err can no longer be error.Internal and remove that from the derived error set.