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

(?T) orelse (?T) yields different result type with comptime-known arguments #16793

Closed
rohlem opened this issue Aug 12, 2023 · 2 comments
Closed
Labels
question No questions on the issue tracker, please.

Comments

@rohlem
Copy link
Contributor

rohlem commented Aug 12, 2023

Zig Version

0.11.0-dev.4056+996eb0174

Steps to Reproduce and Observed Behavior

Reproducing example:

fn f(argument: ?u32) u32 {
    return (argument orelse argument) orelse 20; //parentheses just for explicitness, same behavior without
}
test "orelse" {
    if (f(30) != 30) unreachable; //works
    if (comptime f(30) != 30) unreachable; //compile error evaluating `comptime f(30)`
}

The second line fails with the following compile error:

main.zig:2:39: error: expected optional type, found 'u32'
    return (argument orelse argument) orelse 20;
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~
main.zig:6:19: note: called from here
    if (comptime f(30) != 30) unreachable; //compile error evaluating `comptime f(30)`
                 ~^~~~

It seems that (x orelse y) can result in a non-optional type if some operands are comptime-known.
Strangely enough, grouping the orelse to be right-associative (argument orelse (argument orelse 20)) fixes the issue in this case (see also #15108).
I think that's even a universal workaround - but maybe there's some edge case I'm not considering.

Expected Behavior

I'd expect (?T) orelse (?T) to always result in (?T), both with comptime-known arguments and without.
However now that I have typed all this out, it does remind me of #16595 , where it was deemed correct behavior to not analyze the RHS, leading to a different deduced result type.
The main difference I see is that there it was about fully knowing the type, whereas here it's about fully knowing the value (or at least, that the value isn't null).
But you decide whether it's a bug or WAI (working as intended).

@rohlem rohlem added the bug Observed behavior contradicts documented or intended behavior label Aug 12, 2023
@rohlem rohlem changed the title orelse yields different result type with comptime arguments (?T) orelse (?T) yields different result type with comptime-known arguments Aug 12, 2023
@jacobly0
Copy link
Member

At runtime, x orelse x performs PTR between an unwrapped x.? and x, which allows the unwrapped non-optional to coerce straight back to an optional. At comptime, the lhs is known non-null so no PTR happens and you end up with the unwrapped value. This can be made consistent between runtime and comptime with an explicit @as(?T, x orelse x).

@jacobly0 jacobly0 added question No questions on the issue tracker, please. and removed bug Observed behavior contradicts documented or intended behavior labels Aug 13, 2023
@jacobly0 jacobly0 closed this as not planned Won't fix, can't repro, duplicate, stale Aug 13, 2023
@rohlem
Copy link
Contributor Author

rohlem commented Aug 13, 2023

@jacobly0 Thank you for the explanation of what's happening.
Why / When is this ever the desired language behavior? What code is possibly improved by this?
If we want to unwrap the optional because we know it's not null we use .?.
I'd like to use Zig to write code that works at both run-time and comptime. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question No questions on the issue tracker, please.
Projects
None yet
Development

No branches or pull requests

2 participants