-
Notifications
You must be signed in to change notification settings - Fork 213
Cascaded null-aware field accesses participate in field promotion, but non-cascaded ones don't. #4344
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
I'm considering changing flow analysis so that when (1) main() {
var a = A(0);
a._i!;
a._i.abs(); // OK: `_i` has been promoted.
a?._i.abs(); // Also OK (was previously an ERROR)
} (2) main() {
var a = A(0);
a?._i!;
a._i.abs(); // OK: `_i` has been promoted (was previously an ERROR)
a?._i.abs(); // Also OK (was previously an ERROR)
} My rationale for proposing this is that it makes main() {
var a = A(0);
a._i!;
a._i.abs(); // OK: `_i` has been promoted.
a == null ? null : a._i.abs(); // This has always been OK
} Note, however, that this would still be an error: main() {
var maybeA = A(0) as A?;
maybeA?._i!;
maybeA?._i.abs(); // ERROR: `_i` could be `null`
} The reason for this is because @dart-lang/language-team what do you think? Any objections? |
Sounds like we are only promoting Desugaring should not affect semantics. We should specify the behavior on the original syntax. I'm OK with making both And Does Maybe we should just make Avoids having to explain why this doesn't promote: A? a = A();
a._i!;
if (test) a= null;
a?._i.foo(); Logically it's safe. The value of But it's probably easier to say that what's promoted is the access to But that also means var A(_i: i) = a;
i.foo(); and if (a case A(:var _i) when _i.foo()) ... We also don't allow this, right? A? a = maybeA;
if (a != null) a._i!;
if (a != null) a._i.foo(); Not because we couldn't, but because we don't track conditional promotion. Or do we? A? a = maybeA;
var canUse = a != null && a._i != null;
if (canUse) a._i.foo(); If this does work, then why does doing |
As @lrhn noted, this is concerned with an occurrence of I think this makes the proposed updates look very good:
This can reasonably be described as an inconsistency because the promotion is equally justified (hence sound), and the update will eliminate it. Similarly, I agree that a member access (including (No need to discuss specification by syntactic sugar here: those two expressions shouldn't gratuitously have different behaviors in any case.) I haven't noticed any reason why we would not want to introduce these changes. |
If we are going to go for consistency, then I'd like every access to the variable on the same value to be promoted, independently of the syntax used to achieve that (as long as it's recognizable as reading that variable of that value). That should include object pattern getter access, like I also see no problem with supporting that. If we know that reading that value has a type, it doesn't matter how we read it. |
Yes,
Hmm, I would have expected this to work whenever
This works today (whenever
Correct, this doesn't work because flow analysis doesn't track that the two
Yes, this does work today.
Yeah, I think you've got that about right. The way I think of it is: putting a flow model "to sleep" and then "resuming" it later is hard, because we have to be able to (a) figure out that we might need it later, and store it away, (b) retrieve it when we need it, and (c) update it to reflect other state changes that might have happened while it was asleep. I figured out how to do (c) after a lot of hair pulling, but (a) and (b) are still tricky, and I've only managed to get the process to work in the specific case where a condition gets written to a variable and then later read (because the write and the read act as signals for (a) and (b)).
Agreed, this is a good principle.
Agreed!
This is a good test case for me to experiment with when I'm making the fix. Thanks! |
Ok, I've investigated this and I do believe it's a bug. I've filed a separate issue to track it: #4347. |
As discussed in dart-lang/language#4344, the current implementation has some inconsistencies in how null-aware accesses interact with field promotion. I intend to fix these inconsistencies as part of the `sound-flow-analysis` language feature. In this CL, I'm adding a regression test of the behavior that's currently implemented (as of Dart 3.8), to help me make sure that when I implement the new behavior, the changes will only take effect when `sound-flow-analysis` is enabled. Bug: dart-lang/language#4344 Change-Id: If52a0ad044399904e3389af2130ca802efdd7058 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425922 Reviewed-by: Lasse Nielsen <[email protected]> Commit-Queue: Paul Berry <[email protected]>
I've been investigating the behavior of field promotion inside null aware accesses, and I've found a little inconsistency:
All of these examples assume the following declaration:
An access to
a?._i
does not see a previous promotion ofa._i
:But if that access is in a null-aware cascade, then it does see the previous promotion:
This seems inconsistent to me. Null-aware cascades ought to behave as much like null-aware accesses as possible.
Further inconsistencies arise if the new
sound-flow-analysis
language feature is enabled:A non-null assertion applied to
_i
inside a null-aware access does not promote it (even in cases where it would be sound to do so, because the target of the null-aware access is non-nullable):But a non-null assertion applied to
_i
inside a cascaded null-aware access does promote it (provided that the target of the null-aware access is non-nullable):Again, this seems inconsistent to me. Null-aware cascades ought to behave as much like null-aware accesses as possible.
The text was updated successfully, but these errors were encountered: