Skip to content

Commit 0badadd

Browse files
authored
[patterns] More small fixes. (#2675)
* [patterns] More small fixes. - Specify exhaustiveness checking of switch elements. - Resolve ambiguity with `=>` in switch expression guards. - Compile error if map pattern has identical keys. Fix #2672. Fix #2657. * Clarify when restriction on "=>" in guards comes into play.
1 parent 056a397 commit 0badadd

File tree

1 file changed

+82
-3
lines changed

1 file changed

+82
-3
lines changed

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

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Author: Bob Nystrom
44

55
Status: Accepted
66

7-
Version 2.18 (see [CHANGELOG](#CHANGELOG) at end)
7+
Version 2.19 (see [CHANGELOG](#CHANGELOG) at end)
88

99
Note: This proposal is broken into a couple of separate documents. See also
1010
[records][] and [exhaustiveness][].
@@ -595,6 +595,15 @@ It is a compile-time error if:
595595

596596
* Any of the entry key expressions are not constant expressions.
597597

598+
* If any two keys in the map are identical. *Map patterns that don't have a
599+
rest element only match if the `length` of the map is equal to the number of
600+
map entries. If a map pattern has multiple identical key entries, they will
601+
increase the required length for the pattern to match but in all but the
602+
most perverse `Map` implementations will represent the same key. Thus, it's
603+
very unlikely that any map pattern containing identical keys (and no rest
604+
element) will ever match. Duplicate keys are most likely a typo in the
605+
code.*
606+
598607
* If any two keys in the map both have primitive `==` methods, then it is a
599608
compile-time error if they are equal according to their `==` operator. *In
600609
cases where keys have types whose equality can be checked at compile time,
@@ -1231,6 +1240,67 @@ of an expression statement. This is similar to existing restrictions on map
12311240
literals appearing in expression statements. In the rare case where a user
12321241
really wants one there, they can parenthesize it.
12331242

1243+
#### Function expression in guard ambiguity
1244+
1245+
Function expressions also use `=>`, which leads to a potential ambiguity:
1246+
1247+
```dart
1248+
var x = switch (obj) {
1249+
_ when a + (b) => (c) => body
1250+
};
1251+
```
1252+
1253+
This could be interpreted as either:
1254+
1255+
```dart
1256+
var x = switch (obj) {
1257+
_ when (a + (b)) => ((c) => body)
1258+
// --------- -------------
1259+
};
1260+
1261+
var x = switch (obj) {
1262+
_ when (a + (b) => (c)) => (body)
1263+
// ---------------- ------
1264+
};
1265+
```
1266+
1267+
A similar ambiguity exists with function expressions in initializer lists, if
1268+
the constructor happens to be a factory constructor with `=>` for its body. We
1269+
resolve the ambiguity similarly here: When `=>` is encountered after `when` in
1270+
a guard, if the code between forms a valid expression, then it is interpreted as
1271+
such and the `=>` is treated as the separator between the guard and case body.
1272+
*In the above example, we take the first interpretation.*
1273+
1274+
This rules applies in all contexts where a guard can appear: switch statements,
1275+
switch elements, switch expressions, and if-case statements. *We could restrict
1276+
this rule to guards only in switch expressions where the ambiguity arises, but
1277+
that leads to a syntactic restriction that is context-sensitive and harder to
1278+
learn. Since the rule is unusual enough as it is, we apply it as consistently as
1279+
possible. Note that the related restriction on `=>` in constructor initializers
1280+
applies even though generative constructors can't use `=>` for their body.*
1281+
1282+
The rule is applied unconditionally even if the code after `=>` is not a valid
1283+
body expression, as in:
1284+
1285+
```dart
1286+
var x = switch (obj) {
1287+
_ when (a) => b => c
1288+
};
1289+
```
1290+
1291+
Here, we treat the guard expression as `(a)`, which leads the body to be `b =>
1292+
c` which isn't a valid expression and produces a compile-time error.
1293+
1294+
If you want a guard expression that ends in a function expression (which is
1295+
quite unlikely), you can avoid the `=>` being captured as the case separator by
1296+
parenthesizing the function:
1297+
1298+
```dart
1299+
var x = switch (obj) {
1300+
_ when ((a) => b) => c
1301+
};
1302+
```
1303+
12341304
### If-case statement and element
12351305

12361306
Often you want to conditionally match and destructure some data, but you only
@@ -2265,8 +2335,9 @@ All other types are not exhaustive. Then:
22652335
is to throw an error and most Dart users prefer to catch those kinds of
22662336
mistakes at compile time.*
22672337

2268-
* It is a compile-time error if the cases in a switch statement are not
2269-
exhaustive and the static type of the matched value is an exhaustive type.
2338+
* It is a compile-time error if the cases in a switch statement or switch
2339+
collection element are not exhaustive and the static type of the matched
2340+
value is an exhaustive type.
22702341

22712342
[exhaustiveness]: https://github.com/dart-lang/language/blob/master/accepted/future-releases/0546-patterns/exhaustiveness.md
22722343

@@ -3122,6 +3193,14 @@ Here is one way it could be broken down into separate pieces:
31223193
31233194
## Changelog
31243195
3196+
### 2.19
3197+
3198+
- Specify exhaustiveness checking of switch elements.
3199+
3200+
- Resolve ambiguity with `=>` in switch expression guards (#2672).
3201+
3202+
- Compile error if map pattern has identical keys (#2657).
3203+
31253204
### 2.18
31263205
31273206
- Support negative number literals in patterns (#2663).

0 commit comments

Comments
 (0)