Skip to content

Commit ef7102a

Browse files
authored
[patterns] Disambiguate identifiers in the pattern grammar. (#2785)
* [patterns] Disambiguate identifiers in the pattern grammar. There are no user-visible syntax or semantic changes here. It only changes how the grammar is organized. Fix #2714. * Apply review feedback.
1 parent 3eb6daa commit ef7102a

File tree

1 file changed

+131
-72
lines changed

1 file changed

+131
-72
lines changed

accepted/future-releases/0546-patterns/feature-specification.md

Lines changed: 131 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ Before introducing each pattern in detail, here is a summary with some examples:
188188
| [Null-check][nullCheckPattern] | `subpattern?` |
189189
| [Null-assert][nullAssertPattern] | `subpattern!` |
190190
| [Constant][constantPattern] | `123`, `null`, `'string'`<br>`math.pi`, `SomeClass.constant`<br>`const Thing(1, 2)`, `const (1 + 2)` |
191-
| [Variable][variablePattern] | `foo`, `var bar`, `String str`, `_`, `int _` |
191+
| [Variable][variablePattern] | `var bar`, `String str`, `final int _` |
192+
| [Identifier][identifierPattern] | `foo`, `_` |
192193
| [Parenthesized][parenthesizedPattern] | `(subpattern)` |
193194
| [List][listPattern] | `[subpattern1, subpattern2]` |
194195
| [Map][mapPattern] | `{"key": subpattern1, someConst: subpattern2}` |
@@ -203,6 +204,7 @@ Before introducing each pattern in detail, here is a summary with some examples:
203204
[nullAssertPattern]: #null-assert-pattern
204205
[constantPattern]: #constant-pattern
205206
[variablePattern]: #variable-pattern
207+
[identifierPattern]: #identifier-pattern
206208
[parenthesizedPattern]: #parenthesized-pattern
207209
[listPattern]: #list-pattern
208210
[mapPattern]: #map-pattern
@@ -226,6 +228,7 @@ unaryPattern ::= castPattern
226228
227229
primaryPattern ::= constantPattern
228230
| variablePattern
231+
| identifierPattern
229232
| parenthesizedPattern
230233
| listPattern
231234
| mapPattern
@@ -436,7 +439,6 @@ constantPattern ::= booleanLiteral
436439
| '-'? numericLiteral
437440
| stringLiteral
438441
| symbolLiteral
439-
| identifier
440442
| qualifiedName
441443
| constObjectExpression
442444
| 'const' typeArguments? '[' elements? ']'
@@ -455,14 +457,10 @@ supporting terse forms of the most common constant expressions like so:
455457
literal `2` with a unary `-` applied to it (which is how the language
456458
views it).
457459

458-
* Named constants are also allowed because they aren't ambiguous. That
459-
includes simple identifiers like `someConstant`, prefixed constants like
460-
`some_library.aConstant`, static constants on classes like
461-
`SomeClass.aConstant`, and prefixed static constants like
462-
`some_library.SomeClass.aConstant`. *Simple identifiers would be ambiguous
463-
with variable patterns that aren't marked with `var`, `final`, or a type,
464-
but unmarked variable patterns are only allowed in irrefutable contexts
465-
where constant patterns are prohibited.*
460+
* Qualified named constants are also allowed because they aren't ambiguous.
461+
That includes prefixed constants like `some_library.aConstant`, static
462+
constants on classes like `SomeClass.aConstant`, and prefixed static
463+
constants like `some_library.SomeClass.aConstant`.
466464

467465
* List literals are ambiguous with list patterns, so we only allow list
468466
literals explicitly marked `const`. Likewise with set and map literals
@@ -487,7 +485,7 @@ expression.
487485
### Variable pattern
488486

489487
```
490-
variablePattern ::= ( 'var' | 'final' | 'final'? type )? identifier
488+
variablePattern ::= ( 'var' | 'final' | 'final'? type ) identifier
491489
```
492490

493491
A variable pattern binds the matched value to a new variable. These usually
@@ -502,8 +500,8 @@ Here, `a` and `b` are variable patterns and end up bound to `1` and `2`,
502500
respectively.
503501

504502
The pattern may have a type annotation in order to only match values of the
505-
specified type. If the type annotation is omitted, the variable's type is
506-
inferred and the pattern matches all values.
503+
specified type. Otherwise, it is declared using `var` or `final` and the
504+
variable's type is inferred such that it matches all values.
507505

508506
```dart
509507
switch (record) {
@@ -517,17 +515,9 @@ They are specified later in the "Pattern context" section.*
517515

518516
#### Wildcards
519517

520-
If the variable's name is `_`, it doesn't bind any variable. This "wildcard"
521-
name is useful as a placeholder in places where you need a subpattern in order
522-
to destructure later positional values:
523-
524-
```dart
525-
var list = [1, 2, 3];
526-
var [_, two, _] = list;
527-
```
528-
529-
The `_` identifier can also be used with a type annotation when you want to test
530-
a value's type but not bind the value to a name:
518+
If the variable's name is `_`, it doesn't bind any variable. A "wildcard" name
519+
with a type annotation is useful when you want to test a value's type but not
520+
bind the value to a name:
531521

532522
```dart
533523
switch (record) {
@@ -536,6 +526,32 @@ switch (record) {
536526
}
537527
```
538528

529+
### Identifier pattern
530+
531+
```
532+
identifierPattern ::= identifier
533+
```
534+
535+
A bare identifier in a pattern is semantically ambiguous. A user might expect it
536+
to match if the value is equal to a constant with that name (as it currently
537+
does in switches). Or the user could expect it to bind or assign to a variable
538+
with that name.
539+
540+
The answer is it's both. Depending on the context where it appears, a bare
541+
identifier pattern may behave like a constant pattern or like a variable
542+
pattern. The section on pattern context below lays out the precise rules.
543+
544+
#### Wildcards
545+
546+
As with variable patterns, an identifier pattern named `_` is a wildcard that
547+
doesn't bind or assign to any variable. It's useful as a placeholder in places
548+
where you need a subpattern in order to destructure later positional values:
549+
550+
```dart
551+
var list = [1, 2, 3];
552+
var [_, two, _] = list;
553+
```
554+
539555
### Parenthesized pattern
540556

541557
```
@@ -782,8 +798,8 @@ In both record patterns and object patterns, a field subpattern's name may be
782798
elided when it can be inferred from the field's value subpattern. The inferred
783799
field name for a pattern `p`, if one exists, is defined as:
784800
785-
* If `p` is a variable pattern which binds a variable `v`, and `v` is not `_`,
786-
then the inferred name is `v`.
801+
* If `p` is a variable or identifier pattern with identifier `v`, and `v` is
802+
not `_`, then the inferred name is `v`.
787803
788804
* If `p` is `q?` then the inferred name of `p` (if any) is the inferred name
789805
of `q`.
@@ -912,15 +928,15 @@ patternAssignment ::= outerPattern '=' expression
912928
assignments, but does not allow patterns to the left of a compound assignment
913929
operator.*
914930

915-
In a pattern assignment, all variable patterns are interpreted as referring to
931+
In a pattern assignment, all identifier patterns are interpreted as referring to
916932
existing variables. You can't declare any new variables. *Disallowing new
917933
variables allows pattern assignment expressions to appear anywhere expressions
918934
are allowed while avoiding confusion about the scope of new variables.*
919935

920936
It is a compile-time error if:
921937

922-
* An identifier in a variable pattern does not resolve to an assignable local
923-
variable or formal parameter. A variable is assignable if it is any of:
938+
* An identifier pattern does not resolve to an assignable local variable or
939+
formal parameter. A variable is assignable if it is any of:
924940

925941
* Non-final
926942
* Final and definitely unassigned
@@ -952,12 +968,12 @@ It is a compile-time error if:
952968
to local variables, which are also the only kind of variables that can be
953969
declared by patterns.*
954970
955-
* The matched value type for a variable pattern is not assignable to the
971+
* The matched value type for an identifier pattern is not assignable to the
956972
corresponding variable's type.
957973
958974
* The same variable is assigned more than once. *In other words, a pattern
959-
assignment can't have multiple variable subpatterns with the same name. This
960-
prohibits code like:*
975+
assignment can't have multiple identifier subpatterns with the same name.
976+
This prohibits code like:*
961977
962978
```dart
963979
var a = 1;
@@ -1452,8 +1468,8 @@ categorize into three contexts:
14521468
We refer to declaration and assignment contexts as *irrefutable contexts*.
14531469

14541470
While most patterns look and act the same regardless of where they appear in the
1455-
language, context places some restrictions on which kinds of patterns are
1456-
allowed and what their syntax is. The rules are:
1471+
language, context determines what identifier patterns mean, and places some
1472+
restrictions on which other kinds of patterns are allowed. The rules are:
14571473

14581474
* It is a compile-time error if any of the following *refutable patterns*
14591475
appear in an irrefutable context:
@@ -1481,6 +1497,14 @@ allowed and what their syntax is. The rules are:
14811497
the matched value isn't assignable to their required type. This error is
14821498
specified under type checking.*
14831499

1500+
* In a declaration context, an identifier pattern declares a new variable with
1501+
that name. *A pattern declaration statement begins with `var` or `final`, so
1502+
within that, new variables can be introduced just using simple identifiers:*
1503+
1504+
```dart
1505+
var (a, b) = (1, 2);
1506+
```
1507+
14841508
* It is a compile-time error if a variable pattern in a declaration context is
14851509
marked with `var` or `final`. *A pattern declaration statement is already
14861510
preceded by `var` or `final`, so allowing those on the variable patterns
@@ -1492,18 +1516,12 @@ allowed and what their syntax is. The rules are:
14921516
final [var y] = [2];
14931517
```
14941518
1495-
*To declare variables in a declaration context, use a simple identifer:*
1496-
1497-
```dart
1498-
// OK:
1499-
var [x] = [1];
1500-
final [y] = [2];
1501-
```
1519+
*Variable patterns are allowed in declaration contexts but must have type
1520+
annotations. This can be useful to upcast the declared variable.*
15021521
1503-
* It is a compile-time error if a variable pattern in an assignment context is
1504-
marked with `var`, `final`, or a type annotation (or both `final` and a type
1505-
annotation). *Patterns in assignments can only assign to existing variables,
1506-
not declare new ones.*
1522+
* It is a compile-time error if a variable pattern appears in an assignment
1523+
context. *Patterns in assignments can only assign to existing variables
1524+
using identifier patterns, not declare new ones.*
15071525
15081526
```dart
15091527
var a = 1;
@@ -1516,16 +1534,13 @@ allowed and what their syntax is. The rules are:
15161534
(a, b) = (3, 4);
15171535
```
15181536
1519-
* A simple identifier in a matching context is treated as a named constant
1520-
pattern unless its name is `_`. *A bare identifier is ambiguous and could
1521-
be either a named constant or a variable pattern without any `var`, `final`,
1522-
or type annotation marker. We prefer the constant interpretation for
1523-
backwards compatibility and to make variable declarations more explicit in
1524-
cases. To declare variables in a matching context, use `var`, `final`, or a
1525-
type before the name.*
1526-
1527-
*There is no ambiguity with bare identifiers in irrefutable contexts since
1528-
constant patterns are disallowed there.*
1537+
* An identifier pattern in a matching context is treated as a named constant
1538+
pattern unless its name is `_`. *A bare identifier is ambiguous and could be
1539+
either a named constant or a variable pattern without any `var`, `final`, or
1540+
type annotation marker. We prefer the constant interpretation for backwards
1541+
compatibility and to make variable declarations more explicit in cases. To
1542+
declare variables in a matching context, use a variable pattern with `var`,
1543+
`final`, or a type before the name.*
15291544
15301545
```dart
15311546
const c = 1;
@@ -1537,9 +1552,13 @@ allowed and what their syntax is. The rules are:
15371552
15381553
*This program prints "no match" and not "match 2".*
15391554
1540-
* A simple identifier in any context named `_` is treated as a wildcard
1541-
variable pattern. *A bare `_` is always treated as a wildcard regardless of
1542-
context, even though other variables in matching contexts require a marker.*
1555+
*There is no ambiguity with bare identifiers in irrefutable contexts since
1556+
constant patterns are disallowed there.*
1557+
1558+
* An identifier pattern named `_` in any context is treated as a wildcard that
1559+
matches any value and discards it. *A bare `_` is always treated as a
1560+
wildcard regardless of context, even though other variables in matching
1561+
contexts require a marker.*
15431562
15441563
```dart
15451564
// OK:
@@ -1553,10 +1572,10 @@ allowed and what their syntax is. The rules are:
15531572
forbid it, but doing so is discouraged.*
15541573
15551574
*In short, you can't use refutable patterns in places that don't do control
1556-
flow. Use simple identifiers (optionally with type annotations) to declare
1557-
variables in pattern declarations. Use simple identifiers to assign to variables
1558-
in pattern assignments. Use explicitly marked identifiers to declare variables
1559-
in `case` patterns. Use `_` anywhere for a wildcard.*
1575+
flow. Use identifier patterns or type annotated variable patterns to declare
1576+
variables in pattern declarations. Use identifier patterns to assign to
1577+
variables in pattern assignments. Use variable patterns to declare variables in
1578+
`case` patterns. Use `_` anywhere for a wildcard.*
15601579
15611580
## Static semantics
15621581
@@ -1766,6 +1785,10 @@ The context type schema for a pattern `p` is:
17661785
// ^- Infers List<int>.
17671786
```
17681787
1788+
* **Identifier**: Context type schemas are only used in irrefutable contexts,
1789+
so an identifier pattern is always a variable and is handled like a
1790+
variable pattern, as above.
1791+
17691792
* **Cast**: The context type schema is `_`.
17701793
17711794
* **Parenthesized**: The context type schema of the inner subpattern.
@@ -1926,13 +1949,10 @@ To type check a pattern `p` being matched against a value of type `M`:
19261949
19271950
* **Variable**:
19281951
1929-
1. In an assignment context, the required type of `p` is the (unpromoted)
1930-
static type of the variable that `p` resolves to.
1931-
1932-
2. Else if the variable has a type annotation, the required type of `p` is
1933-
that type, as is the static type of the variable introduced by `p`.
1952+
1. If the variable has a type annotation, the required type of `p` is that
1953+
type, as is the static type of the variable introduced by `p`.
19341954
1935-
3. Else the required type of `p` is `M`, as is the static type of the
1955+
2. Else the required type of `p` is `M`, as is the static type of the
19361956
variable introduced by `p`. *This means that an untyped variable pattern
19371957
can have its type indirectly inferred from the type of a superpattern:*
19381958
@@ -1945,6 +1965,17 @@ To type check a pattern `p` being matched against a value of type `M`:
19451965
That inferred type is then destructured and used to infer `num` for `a`
19461966
and `Object` for `b`.*
19471967
1968+
* **Identifier**:
1969+
1970+
1. In an assignment context, the required type of `p` is the (unpromoted)
1971+
static type of the variable that `p` resolves to.
1972+
1973+
2. In a matching context, the name refers to a constant. Type check
1974+
the constant identifier expression in context type `M`.
1975+
1976+
3. In a declaration context, the required type of `p` is `M`, as is the
1977+
static type of the variable introduced by `p`.
1978+
19481979
* **Parenthesized**: Type-check the inner subpattern using `M` as the matched
19491980
value type.
19501981
@@ -2051,10 +2082,11 @@ To type check a pattern `p` being matched against a value of type `M`:
20512082
20522083
If `p` with required type `T` is in an irrefutable context:
20532084
2054-
* It is a compile-time error if `M` is not assignable to `T`. *Destructuring
2055-
and variable patterns can only be used in declarations and assignments if we
2056-
can statically tell that the destructuring and variable binding won't fail
2057-
to match.*
2085+
* It is a compile-time error if `M` is not assignable to `T`. *Destructuring,
2086+
variable, and identifier patterns can only be used in declarations and
2087+
assignments if we can statically tell that the destructuring and variable
2088+
binding won't fail to match (though it may still throw at runtime if the
2089+
matched value type is `dynamic`).*
20582090
20592091
* Else if `M` is not a subtype of `T` then an implicit coercion or cast is
20602092
inserted before the pattern binds the value, tests the value's type,
@@ -2161,6 +2193,16 @@ pattern is:
21612193
matching context, the variable is final if the variable pattern is
21622194
marked `final` and is not otherwise.
21632195
2196+
* **Identifier**:
2197+
2198+
1. In a matching context, the empty set. *The identifier is a constant
2199+
reference.*
2200+
2201+
2. Else a set containing a single variable whose name is the identifier and
2202+
whose type is the pattern's required type (which may have been
2203+
inferred). The variable is final if and only if the surrounding
2204+
`patternVariableDeclaration` has a `final` modifier.
2205+
21642206
#### Scope
21652207
21662208
The variables defined by a pattern and its subpatterns (its pattern variable
@@ -2745,6 +2787,13 @@ To match a pattern `p` against a value `v`:
27452787
27462788
3. Otherwise, store `v` in `p`'s variable and the match succeeds.
27472789
2790+
* **Identifier**:
2791+
2792+
1. In a matching context, the same as a constant pattern whose constant
2793+
expression is the identifier.
2794+
2795+
2. Else, the same as a variable pattern with the same identifier.
2796+
27482797
* **Parenthesized**: Match the subpattern against `v` and succeed if it
27492798
matches.
27502799
@@ -3168,6 +3217,13 @@ To bind invocation keys in a pattern `p` using parent invocation `i`:
31683217

31693218
1. Nothing to do.
31703219

3220+
* **Identifier**:
3221+
3222+
1. In a matching context, the same as a constant pattern whose constant
3223+
expression is the identifier.
3224+
3225+
2. Else, nothing to do.
3226+
31713227
* **List**:
31723228

31733229
1. Bind `i : ("length", [])` to the `length` getter invocation.
@@ -3356,6 +3412,9 @@ Here is one way it could be broken down into separate pieces:
33563412
33573413
- Handle negative length lists and maps (#2701).
33583414
3415+
- Disambiguate the grammar around bare identifiers (#2714). The overall syntax
3416+
and semantics are unchanged, but the pattern grammar is now unambiguous.
3417+
33593418
- Allow promoted types and type variables with bounds to be always-exhaustive
33603419
(#2765).
33613420

0 commit comments

Comments
 (0)