-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Record pattern promotes fields from void
to Object?
#60609
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
Comments
The promotion also happens even if the pattern is not guaranteed to match, like: case (42, _, _): The matched value type of the next pattern is case (42, _, _) || var _ when s.l("3.s"): // Object? where the first case doesn't match, it still promotes A larger example: void main() {
var s = ("a", "b", "c") as (Object?, void, Object?);
switch (s) {
case var x when x.l("x") || s.l("s"): // void
case Record x when x.l("r.x") || s.l("r.s"): // Record/void
case var x when x.l("x") || s.l("s"): // void
case Triple<dynamic> x when x.l("t.x") || s.l("t.s"): // dynamic
case var x when x.l("x") || s.l("s"): // dynamic
case Triple<Object> x when x.l("t.x") || s.l("t.s"): // Object
case var x when x.l("x") || s.l("s"): // dynamic
case Triple<void> x when x.l("t.x") || s.l("t.s"): // void/dynamic
case var x when x.l("x") || s.l("s"): // void/dynamic
case (42, _, _) || _ when s.l("42.s"): // Object?
case var x when x.l("x") || s.l("s"): // Object?
}
}
typedef Triple<T> = (Object?, T, Object?);
extension <T> on T {
bool l(String name) {
print("$name: $this:$runtimeType @ $T"); // value, runtime and static type
return false;
}
} It seems like a record pattern can perform some kind of promotion on the matched value and the matched variable, even if the pattern match fails due to a It's not consistent. The |
Ok, I've finally tracked down what's happening in the larger example from @lrhn's last comment. Repeating it here: void main() {
var s = ("a", "b", "c") as (Object?, void, Object?);
switch (s) {
case var x when x.l("x") || s.l("s"): // void
case Record x when x.l("r.x") || s.l("r.s"): // Record/void
case var x when x.l("x") || s.l("s"): // void
case Triple<dynamic> x when x.l("t.x") || s.l("t.s"): // dynamic
case var x when x.l("x") || s.l("s"): // dynamic
case Triple<Object> x when x.l("t.x") || s.l("t.s"): // Object
case var x when x.l("x") || s.l("s"): // dynamic
case Triple<void> x when x.l("t.x") || s.l("t.s"): // void/dynamic
case var x when x.l("x") || s.l("s"): // void/dynamic
case (42, _, _) || _ when s.l("42.s"): // Object?
case var x when x.l("x") || s.l("s"): // Object?
}
}
typedef Triple<T> = (Object?, T, Object?);
extension <T> on T {
bool l(String name) {
print("$name: $this:$runtimeType @ $T"); // value, runtime and static type
return false;
}
} It turns out it has nothing to do with LUB or MORETOP. The weird behavior here is caused by two things:
Here's how it all plays out in painstaking detail:
Phew! Ok, I'm going to come back to this tomorrow and try to come up with a suggestion for how we might improve this messy situation. |
Amazing analysis, @stereotype441, as always! It sounds like it is all about #60496. However, one little thing is surprising to me: I would expect promotion to occur when the given variable (including a pseudo-variable known as 'the matched value') has a type which is a proper supertype of the type that we're promoting it with. But all these top types are subtypes of each other, which means that they shouldn't even be eligible for promotion in the first place. Does the promotion machinery actually use the more fine-grained subtype hierarchy which is defined in terms of |
Yeah, I suspect that would be a better rule.
It doesn't currently use the more fine-grained subtype hierarchy of |
My main confusion comes from a rejected case causing promotion. If we only promote to proper subtypes, then the type check itself cannot be both trivially satisfied and promoting, and I think that would avoid that confusion. |
Agreed. This is a really nice, principled justification for the idea that flow analysis should only promote to proper subtypes. I'll add it to my list and try to get to it as part of the |
Example:
The
case (_, _, _)
, which should be a no-op for a matched value type of(Object?, void, Object?)
"promotes" the middle record field's static type to
Object?
.That loses
void
protection.If it's not an implementation bug, then it's a spec bug, but it should still be fixed.
The text was updated successfully, but these errors were encountered: