Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow some cases of error union with error set payload #14698

Open
wooster0 opened this issue Feb 21, 2023 · 0 comments
Open

Allow some cases of error union with error set payload #14698

wooster0 opened this issue Feb 21, 2023 · 0 comments
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone

Comments

@wooster0
Copy link
Contributor

wooster0 commented Feb 21, 2023

I believe #12462 is what made it so that this no longer works:

fn fail(comptime fmt: []const u8, args: anytype) !error{CodegenFail} {
    oom();
    @import("std").debug.print(fmt, args);
    return error.CodegenFail;
}

fn oom() !void {
    return error.OutOfMemory;
}

test {
    _ = fail;
}

And while I can agree with that case, this also no longer works:

const CodegenFail = error{CodegenFail};
fn fail(comptime fmt: []const u8, args: anytype) !CodegenFail {
    oom();
    @import("std").debug.print(fmt, args);
    return @as(CodegenFail, error.CodegenFail);
}

fn oom() !void {
    return error.OutOfMemory;
}

test {
    _ = fail;
}

But I believe that at least this case is something that should be allowed.
Interestingly, this does work (note that the only difference is that the CodegenFail is "optional"):

const CodegenFail = error{CodegenFail};
fn fail(comptime fmt: []const u8, args: anytype) !?CodegenFail {
    oom();
    @import("std").debug.print(fmt, args);
    return @as(?CodegenFail, error.CodegenFail);
}

fn oom() !void {
    return error.OutOfMemory;
}

test {
    _ = fail;
}

But removing the two question marks:

x.zig:2:51: error: error union with payload of error set type 'error{CodegenFail}' not allowed
fn fail(comptime fmt: []const u8, args: anytype) !CodegenFail {
                                                  ^~~~~~~~~~~

I use this fail function to emit compile errors and it thus always returns an error which indicates that codegen failed so you can return with the result of fail and have it propagate correctly.
However, failing itself can also fail: it might run out of memory (in my case I'm allocating an error message).
Here's an example of its usage:

        return try fail("failed lowering unnamed constant: {}", .{err});

I think this communicates intent quite clearly: we want to fail so we try to fail and then if that succeeded we return with an error from the function and make it propagate.
But now I have to change it to return func.fail("", .{}) (no try) which I think doesn't communicate intent as well as before. Failing itself might fail so it might return error.OutOfMemory which has nothing to do with the normally only expected result of fail of error.CodegenFail.

Also, I would like to keep error.OutOfMemory inferred.

@andrewrk andrewrk added the proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. label Apr 10, 2023
@andrewrk andrewrk added this to the 0.12.0 milestone Apr 10, 2023
@andrewrk andrewrk modified the milestones: 0.13.0, 0.12.0 Jul 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Projects
None yet
Development

No branches or pull requests

2 participants