-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Flag additional code as unreachable due to types Null
and Never
#49635
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 don't understand how this is breaking. It seems like an obvious win with no downside. |
@Hixie The breakage scenarios are very minor:
foo(int Function() f) {
if (f() is Never) {
print('unreachable');
}
} I suppose you could argue that this is only a breakage in a very pedantic technical sense.
foo(int Function() f) {
int? i;
if (f() is Never) {
print('hello'); // (1)
} else {
i = 0;
}
var j = i; // (2)
j = null; // (3)
} Before the change, (1) is not recognized as unreachable, therefore at (2), After the change, (1) is recognized to be unreachable, therefore at (2), Technically this is breaking since code that used to comple and execute without a problem now contains a compile-time error. But I would be very surprised if a situation like this arose in practice. |
Fair enough. Seems fine to me either way. :-) |
lgtm |
LGTM |
Marking this breaking change request approved based on the comments. |
Several unusual constructs that lead to unreachable code are now recognized by flow analysis: - Control flow after an expression of the form `e ?? other` or `e ??= other`, where `e` has static type `Null` and `other` has static type `Never`, is considered unreachable. - Control flow predicated on an expression of the form `e is Never` evaluating to `true` is considered unreachable. - Control flow predicated on an expression of the form `e is! Never` evaluating to `false` is considered unreachable. - Control flow on the RHS of a null-aware access such as `e?.property...`, `e?.property = ...` or `e?.method(...)`, where `e` has static type `Null`, is considered unreachable (Note: this can arise in the presence of extension methods). Previously, these behaviors only took effect if `e` was a reference to a local variable. Note: the change to `regress/issue_31180` is because I’ve corrected the behavior of implicit temporary variables to not undergo a type change from `Null` to `dynamic`, so the dead code part of `null?[1]` is now erroneous. (I had to make this change in order for the last bullet above to work properly; without it, the type change to `dynamic` prevents flow analysis from recognizing that the code to the right of `?.` is unreachable.) There's no behavioral change to correct code, but I've captured the behavioral change to incorrect code in `tests/language_2/null_aware/null_aware_index_on_null_error_test.dart`. Bug: #49635 Change-Id: I8b24b3b040a34f897c0b61dcb9bd105be6d0af6d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/251280 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Bob Nystrom <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]>
As of b7567b1 this change has landed. |
Note: this change wound up having a slightly larger effect than anticipated: as of b7567b1, a type test of the form This a small enough change that I don't think it's necessary to re-open the breaking change process, but I wanted it documented here. I've sent https://dart-review.googlesource.com/c/sdk/+/256880 for review, to update the CHANGELOG and add a test that exercises the new behavior. |
Breaking change #49635 had a slightly larger effect than I previously understood. This change documents the additional effect and adds a test that would have caught it. Bug: #49635 Change-Id: I40e9434a7fb87ff00d71b454239e4cadf197a285 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/256880 Reviewed-by: Leaf Petersen <[email protected]> Commit-Queue: Paul Berry <[email protected]>
Change
In present-day Dart, the following flow analysis behaviours only take effect if the expression
e
is a reference to a local variable:e ?? other
ore ??= other
, wheree
has static typeNull
andother
has static typeNever
, is considered unreachable.e is Never
evaluating totrue
is considered unreachable.e is! Never
evaluating tofalse
is considered unreachable.e?.property...
,e?.property = ...
ore?.method(...)
, wheree
has static typeNull
, is considered unreachable (Note: this can arise in the presence of extension methods).I propose to change this so that these behaviours take effect regardless of the form of the expression
e
.Rationale
There are two motivations for this change:
Impact
The primary expected user impact would be the appearance of "unreachable code" hints that did not appear previously. A secondary possible impact would be that type inference would assign a more accurate type to an implicitly typed variable, as a result of an unreachable code branch being excluded from analysis; this could in turn cause static errors, or (in highly contrived scenarios) runtime failures. I've prototyped this change in Google's internal codebase, and it caused zero visible change, so both of these impacts are expected to be rare.
Mitigation
If a user gets a new "unreachable code" hint, they may either delete the unreachable code or ignore the error (e.g. using an
// ignore
comment). In the unlikely event that unreachable code detection leads to a change in type inference, and that in turn leads to a static error or runtime failure, the user can mitigate the problem through the use of an explicit type.(Note: previous discussion here: dart-lang/language#2394)
The text was updated successfully, but these errors were encountered: