The setReachable method took a bool indicating whether the new state
should be considered reachable or not, however outside of tests the
value that was passed in was always `false`. Change to a
`setUnreachable` method taking no arguments.
This should make it easier to transition to a stack representation for
reachability.
Bug: https://github.com/dart-lang/sdk/issues/40009
Change-Id: I16a35ec3d5f44763a60e42f200a3caa619fac118
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/165142
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
The CFE defers the final build of the body of a for-element until
after building the rest of the body. This caused a bug: if the body
was an assignment expression, flow analysis was not picking up on the
fact that the assignment was inside the loop.
Fixed by introducing a mechanism that allows the CFE to temporarily
pop the innermost structure on the AssignedVariables stack and then
push it again.
Change-Id: I11d526302934e9283807124ebd4a23e9d3e5ec66
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/164980
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
A late variable with an initializer is very similar to a function
expression, in that it may be evaluated at any time in the future
(possibly more than once, if it throws an exception), so flow analysis
models it that way.
Fixes#42990.
Change-Id: I90ed00c8fd7388145f89011628e31ff7e85a5c43
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/164420
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
When flow analysis encounters a variable declaration of the form `var
x = expr;`, if the type of `expr` is `X&T`, then the variable is given
the inferred type `X`, but it is immediately promoted to `X&T`.
Change-Id: I2a5ffca3860ab009f0942e6efc641c1604ab6323
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/163840
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
When performing flow analysis for a "for each" loop such as `for (var
x in ...) { ... }`, we don't need to consider the iterated value to be
"written to" the variable `x`, since the actual runtime semantics are
to create a fresh instance of the variable `x` each time through the
loop, initialized to the iterated value.
Fixes#43136.
Bug: https://github.com/dart-lang/sdk/issues/43136
Change-Id: I497c408c3efc26e93502de8ba0530bb5278e74c6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/162581
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Previously the flow analysis equations for a for-each loop `N` of the
form `for (var V in E) S` were approximately as follows:
- Let `before(E) = before(N)`
- Let `before(S) = conservativeJoin(after(E), assignedIn(N), capturedIn(N))`
- Let `after(N) = join(after(E), break(S))`
This CL changes the behavior to:
- Let `before(E) = before(N)`
- Let `before(S) = conservativeJoin(after(E), assignedIn(N), capturedIn(N))`
- Let `after(N) = join(before(S), break(S))`
(In other words, the result of the conservative join is carried
through to the state after the loop). This isn't strictly necessary
for soundness, but it makes the behavior of a for-each loop more
consistent with its desugared equivalent. In particular, it means
that if a variable is potentially assigned to or captured in the body
of the loop, then the effect of that potential assignment or capture
will be felt in the code that follows the loop, even if the potential
assignment or capture is not connected to the flow control path.
Change-Id: I7a70a8ae9f87bd40b6592992d8ee985a9aa87e80
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/162480
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
The new logic classifies the LHS and RHS of the equality check as
either null, non-nullable, or potentially nullable, and then either
promotes, treats the expression as equivalent to a boolean, or does
nothing, as appropriate.
This means, for example, that a comparison between a non-nullable
value and `null` is now known to evaluate to `true` for reachability
analysis.
Note: as part of this change, it was tempting to trigger promotion
whenever a varialbe is equality compared to an expression of type
`Null`, but this would be unsound (consider `(int? x) => x == (x =
null) ? true : x.isEven`). So we still only promote when the variable
is compared to a literal `null`.
Fixes#41985.
There's a corresponding spec change out for review:
https://github.com/dart-lang/language/pull/1134
Change-Id: Id7f1d4eaa3b0fa57124445bb8352eef32c304feb
Bug: https://github.com/dart-lang/sdk/issues/41985
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/155926
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
The handling of null shorting in the variable initializer interfered with
the declaration of the variable, making subsequent flow potentially
losing track of promotions.
Closes#42504
Change-Id: Idb17920ffe8746983825714f76160abcca54751b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/152760
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
At the top of a loop, loop-assigned variables need to be marked as not
definitely unassigned, otherwise we will give incorrect results for
code like this:
```dart
f() {
late int x;
bool firstIteration = true;
while (true) {
if(firstIteration) {
x = 0;
firstIteration = false;
} else {
print(x); // BOGUS ERROR: x definitely unassigned
}
}
}
```
Previously, we were handling this by calling `joinUnassigned` at the
bottom of `removePromotedAll`, but it's simpler to just mark these
variables as not-unassigned while discarding promotions. This change
will make the implementation more closely match spec changes I'll be
making shortly.
Change-Id: If50e28d20a75730aa5187a62ae5cac8690b0dfaf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/152861
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Fixes https://github.com/dart-lang/sdk/issues/42375
EdgeBuilder wishes to do its own GLB type-joining, as does FlowAnalysis.
When FlowAnalysis pushes a promotion in ifNullExpression_rightBegin,
and then in write, and then pops those two promotions to join them in
ifNullExpression_end, EdgeBuilder is not given a chance to make its
own GLB node. Instead promotion never happens: the DecoratedType which
is the variable's type is promoted to non-nullable, for the left side.
The DecoratedType for the right side expression is not considered
non-nullable, so the FlowAnalysis.join will always fail to promote.
TypeOperations.adjustPromotedTypes solves this. It is a no-op in all
implementations except in EdgeBuilder.
Additionally FlowAnalysis.write's promotion fails for the same reason:
the only type of interest is the declared type made non-nullable, and
no matter what, the writtenType is not a subtype of this.
TypeOperations.forcePromotion solves this. It is a no-op in all
implementations except EdgeBuilder.
Change-Id: Iba6b9a69583af8fe1aa23124c7d66047acfff495
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/152104
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
This is the second part of the referenced issue.
Practically, we don't do anything special during demotion, we merely
demote when write T to such type S, that T <: S. This S must be a
type of interest (tested or declared). If it happens to be nullable,
and T < NonNull(S), we will promote to NonNull(S).
Bug: https://github.com/dart-lang/sdk/issues/40011
Change-Id: I254b4bfbbfad47fa2c2811def864c8ce0419b7c9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/145740
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Adds support for pretty printing verbose annotations.
Adds support for force updating annotation texts useful for applying
the pretty printing to valid annotations.
Change-Id: I8fe9b6d2f8198bd5e160854053c8d964ef832a8d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/129710
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>