-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
decl literal cannot be used with catch
operator
#21289
Comments
From the proposal where |
Not a bug per the above. Note that |
So I just tried out master for reasons unrelated to decl literals, but they were the first thing I went to try as I'm very eager to start using them. Unfortunately, literally my first attempted usage hit this limitation. I hope you don't mind me necro-bumping this question; I have a clarification question on the limitations stated in the Specifically, the proposal states that Main question of my post: Is there some aspect of IES makes it inherently work for return types but not for the lhs expression of catch? Let's say that the lhs takes the result type of the outer scope and creates a new "IES context", combining the result type with a to be defined set of errors. Then as the lhs's actual errors are determined (something that's clearly possible because it's done with One note is that even if the rls context outside of the catch expression is an error union, the payload type of that error union should be used to form a new ies error union context. This would be required as the catch expression may change the set of errors, eg: fn wrappedFoo() !SomeStruct {
return .foo() catch |err| switch (err) {
error.Foo => error.Bar,
};
} Actually declaring a local variable/constant with IES syntax is irrelevant to all of this. It may be a reasonable, but I don't have any motivating example so I don't care either way. I do feel that if this is reasonable from a compiler implementation perspective, then it's fairly important from a language usability perspective. The language seems to be relying on RLS more and more which is smoothing over bumps, except it's making Doing things this way would make This has some implications for other proposals: I'm not intending to press this point, but I would like to note that this also solves my concern with removing peer type resolution. Additionally, this seems important if @Result is accepted. Eg if fmt.parseInt is changed to use rls, a catch in that same statement to handle parsing errors immediately would be common. |
I'm aware you have a related comment on #22182 related to this which I have yet to respond to -- sorry, I'll get to that soon! But, essentially, inferred error sets in Zig are much more fundamentally tied to function return types than I think you realise. In particular, IES types are distinct from their resolved variants, i.e.: fn foo() !void {
return error.Foo;
}
test {
const foo_val = foo();
const FooTy = @TypeOf(foo_val);
const FooErr = @typeInfo(FooTy).error_union.error_set;
comptime assert(FooErr != error{Foo});
// equivalently:
comptime assert(FooErr != @Type(@typeInfo(FooErr)));
// this is because `FooErr` is not `error{Foo}`, it's "the inferred error set of `Foo`", which is a
// completely distinct type! `@typeInfo` drops this information, hence the second `assert`.
} In other words, "adding to the IES" is fine here because isn't changing the type; the error set "before" adding an error is That said, I'm actually planning to change I'm not completely satisfied with where decl literals are not allowed today, but solving this will require something of a rehaul to RLS, which I do plan to propose at some point soon. Also, note that #22182 will make it much easier to propagate result types into const my_opt_u16: ?u16 = ...;
const my_u32: u32 = ...;
const x: ?u32 = a: {
// The obvious thing is for this block to have a result type of `?u32`.
// However, `?u16` doesn't coerce to `?u32`, so that fails.
// But it works today without the result type, because we unwrap the optional and apply PTR, and `u16` *can* coerce to `?u32`!
break :a my_opt_u16;
} orelse my_u32; Rest assured that I'm aware of this issue. I've hit it myself, and acknowledge that status quo can feel awkward and inconsistent. I would like to find a language-level solution which is easy to understand and implement whilst allowing use of decl literals in more places; it's just a somewhat hard problem, and my focuses are elsewhere right now. |
No worries. I appreciate your engagement, as it lets me improve my feedback to the project. However I also view my comments as just that - feedback to the project, to be valued or discarded by the Zig core team as they see fit.
Ah so that's how they work, interesting.
Right. Now, I'm not saying this would be an easy change to make in the compiler, but this still doesn't seem to be something that could only ever be implemented for return types and nothing else. Eg, could you not have a
Ah, hm, I see the awkwardness here. The balance between "pure orthogonal interactions of the system providing power", and "just be practical and special case it" is often a delicate balancing act which invites all sorts of bike shedding. But, I'd probably prefer leaving the weirdness in over special casing it.
Rhs of catch seems to work with rls already? I was going to bring it up in my comment above, but I tried it and a decl literal worked there, so it didn't seem worth bringing up. The type is much more easily well defined anyways. Typing that sentence made me realize it seems the fundamental tension here is that many operations, such as pointer de-referencing, have well defined inverse operations that can be applied at the type level. However
👍 |
Zig Version
0.14.0-dev.1409+6d2945f1f
Steps to Reproduce and Observed Behavior
note: extracted from this attempted change in my project when trying out decl literals
Expected Behavior
successful compilation, where
.get
is resolved toA.get
The text was updated successfully, but these errors were encountered: