Skip to content

Rework flow analysis of == and !=. #1134

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

Merged
merged 2 commits into from
Aug 12, 2020

Conversation

stereotype441
Copy link
Member

Previously, we specified flow states null() and nonNull() (similar
to true() and false()), and the special behaviors of == null and
!= null checks fell out of a general analysis of E1 == E2. But it
didn't work in practice, because it required doing joins like
join(null(E1), null(E2)), which isn't sound in general (because it
carries the flow control implication that either E1 or E2 is evaluated
but not both). Because of these problems, the implementation never
matched this specification, and instead used ad-hoc pattern matching
to recognize == null and != null.

In the new formulation, we remove the flow states null() and
nonNull() and retain the ad-hoc pattern matching for == null and
!= null, consistent with the current implementation. However, we
also add cases to recognize when an equality test is guaranteed to
evaluate to true or false; this addresses
dart-lang/sdk#41985 and ensures that we
recognize dead code associated with unnecessary null checks.

Previously, we specified flow states `null()` and `nonNull()` (similar
to `true()` and `false()`), and the special behaviors of `== null` and
`!= null` checks fell out of a general analysis of `E1 == E2`.  But it
didn't work in practice, because it required doing joins like
`join(null(E1), null(E2))`, which isn't sound in general (because it
carries the flow control implication that either E1 or E2 is evaluated
but not both).  Because of these problems, the implementation never
matched this specification, and instead used ad-hoc pattern matching
to recognize `== null` and `!= null`.

In the new formulation, we remove the flow states `null()` and
`nonNull()` and retain the ad-hoc pattern matching for `== null` and
`!= null`, consistent with the current implementation.  However, we
also add cases to recognize when an equality test is guaranteed to
evaluate to `true` or `false`; this addresses
dart-lang/sdk#41985 and ensures that we
recognize dead code associated with unnecessary null checks.
@stereotype441
Copy link
Member Author

I will follow up with an implementation change that brings the implementation in line with these spec changes. A few small changes to the Flutter SDK will be necessary, to ignore dead code warnings that result from the fact that dead code analysis now detects unnecessary null checks.

@stereotype441
Copy link
Member Author

Implementation change: https://dart-review.googlesource.com/c/sdk/+/155926

@stereotype441
Copy link
Member Author

Necessary Flutter changes are here: flutter/flutter#63007

Copy link
Member

@munificent munificent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, for what it's worth. :)

Copy link
Member

@eernstg eernstg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, with a few comments. In particular, I think we have to use the notion of 'strictly non-nullable' for the analysis of ??.

@stereotype441 stereotype441 merged commit b901765 into dart-lang:master Aug 12, 2020
@stereotype441 stereotype441 deleted the b-41985-5 branch August 12, 2020 16:24
dart-bot pushed a commit to dart-lang/sdk that referenced this pull request Aug 14, 2020
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:
dart-lang/language#1134

Change-Id: Id7f1d4eaa3b0fa57124445bb8352eef32c304feb
Bug: #41985
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/155926
Reviewed-by: Konstantin Shcheglov <[email protected]>
Reviewed-by: Johnni Winther <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants