This fixes a minor bug in flow analysis which was preventing it from
recognizing when a switch statement was trivially exhaustive, meaning
one of its reachable cases was guaranteed to always match.
This mostly addresses
https://github.com/dart-lang/language/issues/2980, but flow analysis
still fails to recognize that:
- A list pattern containing a just a single rest pattern always
matches (unless the rest pattern has a subpattern that may fail to
match).
- A null check pattern always matches if its subpattern always matches
and the matched value type is non-nullable.
- The relational pattern `!= null` always matches if its subpattern
always matches and the matched value type is non-nullable.
Fortunately, these drawbacks are small and don't lead to unsoundness.
I'll try to address them in follow up CLs.
Bug: https://github.com/dart-lang/language/issues/2980
Change-Id: Ie9f8564cde66a5a2c41114033ca3ff0e1a0f139a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/293860
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This updates the message report for non-exhaustive switch statements
and expressions to include the witness in the problem message and
a reduced witness, which doesn't include properties that fully cover the
static type. The message is also split into two messages; one for
switch statements and one for switch expressions, allowing for a
better wording regarding the default/wildcard pattern case.
Change-Id: I17db657ef12ade5d47fa96bf69b8807e33ed5b8c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/293040
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
The implementations are doing the right thing, but the tests are
slightly off:
- The CFE doesn't report unreachable case warnings because they are
non-fatal warnings, so remove those expectations. (But analyzer does,
so continue to check that analyzer reports them.)
- The CFE reports shared case variable errors at a different location.
Change-Id: I7143a7705d3c8879fb91e5fdb8df8599bfb96165
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292520
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Auto-Submit: Bob Nystrom <rnystrom@google.com>
Commit-Queue: Bob Nystrom <rnystrom@google.com>
Just corner cases that occurred to me while specifying the
implementation. There's probably already front end tests for it too, but
I like the idea of having some language coverage as well.
Change-Id: I158f274483799c3ccb29c32f0e7c5c42d31f327f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/291962
Auto-Submit: Bob Nystrom <rnystrom@google.com>
Commit-Queue: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Eventually, these hints should probably be moved over to warnings. But
for now, this makes it possible to write static error language tests
that validate that analyzer produces unreachable case warnings/hints
where expected.
Also updated the patterns/ and switch/ tests now that those errors must
be expected by the test.
Change-Id: If1fb92602c4bde2819b9eec73598033009054947
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/291967
Auto-Submit: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Bob Nystrom <rnystrom@google.com>
The precedence-based pattern parser can understand a unary pattern
inside another unary pattern (e.g. `_ as int as num`) or a relational
pattern inside a unary pattern (e.g. `> 1?`), but the specification
prohibits these constructions because they're difficult to read and
not very useful.
This change updates the implementation to match the spec, by producing
the appropriate error. The offset and length of the error cover the
inner pattern, so it should be easy to construct an analysis server
quick fix that inserts the necessary parentheses.
Bug: https://github.com/dart-lang/sdk/issues/50035
Change-Id: I33e74d6d1f863e7162851d26fefbacd4fd17277c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292120
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
The logic for parsing types has special disambiguation rules for
deciding whether a trailing `?` should be included in the type, based
on what token(s) follow the `?`. In the case where the token that
follows the `?` is `when`, we need to look further ahead to
disambiguate, to distinguish `PATTERN as T? when guard` from something
like `EXPRESSION is T ? when : otherwise`.
(Note: an alternative implementation would be to disambiguate based on
whether we're parsing a pattern or an expression. But in the future I
want to move toward an architecture where expression parsing and
pattern parsing are combined, so that if the parser makes the wrong
decision about whether it's looking at a pattern or an expression,
error recovery will do a better job. So I'm disambiguating based
solely on what follows the `?`.)
Bug: https://github.com/dart-lang/sdk/issues/50035
Change-Id: Idbc780b7b54fecc7fd01cae868c34771564dd804
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292282
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
The listener API for variable patterns is split into three separate
functions, to handle the three separate behaviors:
- `handleAssignedVariablePattern` for variable names appearing in an
assignment context (these assign to an existing variable upon a
successful match).
- `handleDeclaredVariablePattern` for variable declarations appearing
in a declaration or matching context (these cause a new variable
name to come into scope).
- `handleWildcardPattern` for wildcards in any context (these don't
capture the matched value).
Also, responsibility is shifted to the parser for reporting the
following error conditions:
- VariablePatternKeywordInDeclarationContext (e.g.
`var (var x) = ...;`)
- PatternAssignmentDeclaresVariable (e.g. `[x, var y] = ...;`)
Previously these errors were detected by the implementations, and
weren't fully covering all possible error scenarios.
In the case of VariablePatternKeywordInDeclarationContext, the
listener method `handleDeclaredVariablePattern` is called instead of
`handleAssignedVariablePattern`. This ensures that no tokens are
dropped from the analyzer AST. The CFE uses the `inAssignmentPattern`
argument of `handleDeclaredVariablePattern` to distinguish this error
recovery case from a legitimate declared variable pattern.
Fixes#51868.
Bug: https://github.com/dart-lang/sdk/issues/51868
Change-Id: I28ec679b73d64033166721c6460be35f15e23171
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/291583
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
I've also added some runtime checks to
`tests/language/patterns/object_pattern_inference_test.dart` to verify
that the object patterns match when they should match and don't match
when they shouldn't; this helps verify that not only has the front end
inferred the correct type for the object patterns, but it has also
stored the correct type in the kernel representation.
Fixes#51795.
Bug: https://github.com/dart-lang/sdk/issues/51795
Change-Id: I73ce43e440db50d9942deb4a1eb4ee68a5c23142
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/290900
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This changes the analyzer and CFE to use the real exhaustiveness
checking algorithm. The fallback algorithm is kept and will be
removed once we know that the real exhaustiveness algorithm sticks.
Change-Id: Ic9df92c1ca9f7dec4cbdfa138dc6ed39ef2d4df5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/288703
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This removes the use of [SwitchInfo], [SwitchCaseInfo] and
[ExhaustivessInfo] to pass on information for exhaustiveness checking
and instead uses the AST nodes directly in the constant evaluator.
Change-Id: Ie8d72b03e38334d1be9857794c38ed142dba5783
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/288402
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
This moves the lowering of patterns in switch statement/expression,
pattern assignment, pattern variable declaration and if-case statement
to the constant evaluator.
Change-Id: Ic5810e96b26a74987c50fd71b306e41b59504e1f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/288401
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
This change improves the fallback exhaustiveness algorithm so that it
also takes advantage of the old, pre-patterns exhaustiveness logic for
enums. This ensures that the fallback exhaustiveness algorithm won't
seem like a regression to users who are used to the old pre-patterns
behaviour. This required extending the old algorithm to handle
new-style switch statements (which have a different representation
from classic switch statements in the CFE) as well as switch
expressions.
We also turn on the fallback exhaustiveness algorithm by default.
Unit tests can still disable it by temporarily setting the global
variable `useFallbackExhaustivenessAlgorithm` to `false`.
The hope is that this algorithm will be short-lived; we are just using
it so that if we decide to enable pattern support in the near future,
users will experience something that is sound. That is, it may
require `default` or `_` cases more often than is strictly necessary,
but it shouldn't ever allow a non-exhaustive switch in a place where
an exhaustive switch is required.
Change-Id: I4a8b7f996b109c4ee8832f286c3b3bf3b216fe8b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/284840
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This adds support for record types in the exhaustiveness algorithm.
The original algorithm was based on that record pattern would
match fields on all types, but that is no longer the case. Instead
record patterns only match corresponding to their own type. For this
reason the testing code is updated to create record spaces in relation
to a type. For instance, when the test create a record space {x: B}, it
is know create in relation to a type, say (x: A, y: A), and the create
space will therefore have (x: *, y: *) structure where the y: component
is implicitly Top, similar to how object patterns are used.
Unlike the Dart record types used for type checking and inference, the
record types used for exhaustiveness do not take the field types into
account for its subtype relation. This is avoid conclusions like
(int i, Object o) and (Object o, int i) having no values in common because
their corresponding types (int, Object) and (Object, int) are not subtypes
of each other. Instead, the subtype relation for record types used for
exhaustiveness only use the structure of the record to determine whether
two types are related.
Note though, that fields of a record type still know the type of the field.
This is used when expanded a record type into a space; the field spaces
will be derived from the field types in this case.
Change-Id: I84735d827494bcf384fd5f419d71933830ff5d15
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/283182
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This allows the parser to parse constant patterns at lower precedence
level in order to recognize more expressions in this context. To
support this, _parsePrecedenceExpressionLoop special cases a few cases
that should _not_ be parsed as expression in a constant pattern context.
Closes#50996
Change-Id: I43bb0ce52d366bd2dfcf47e12eec5883402f668a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/282100
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
This adds the initial implementation of exhaustiveness checking in
the analyzer and CFE. The checking is currently only performed in
switch statements and only handle a subset of the patterns.
Change-Id: Ia0050c2c80fbefe3e22615599136f9d919ebe4ef
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279173
Reviewed-by: Jonas Termansen <sortie@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
This doesn't comprehensively cover everything we should test around
pattern variable scopes, but I wanted to cover most of the tricky
behavior around variables in cases that share a body, along with some
other edge cases that I thought of while speccing that out.
Change-Id: I64fff7b4a9a30b00801fbf37b52f07799ef0fd35
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/268370
Commit-Queue: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Kallen Tu <kallentu@google.com>