@@ -4,7 +4,7 @@ Author: Bob Nystrom
4
4
5
5
Status: In progress
6
6
7
- Version 1.1 (see [ CHANGELOG] ( #CHANGELOG ) at end)
7
+ Version 1.2 (see [ CHANGELOG] ( #CHANGELOG ) at end)
8
8
9
9
## Summary
10
10
@@ -557,10 +557,24 @@ expressions evaluate to equivalent values.
557
557
A record pattern destructures fields from a record.
558
558
559
559
```
560
- recordBinder ::= '(' recordFieldBinders ')'
560
+ recordBinder ::= '(' recordFieldBinders ')'
561
561
562
- recordFieldBinders ::= recordFieldBinder ( ',' recordFieldBinder )* ','?
563
- recordFieldBinder ::= ( identifier ':' )? binder
562
+ recordFieldBinders ::= recordFieldBinder ( ',' recordFieldBinder )* ','?
563
+ recordFieldBinder ::= ( identifier ':' )? binder
564
+ | identifier ':'
565
+ ```
566
+
567
+ Each field is either a binder which destructures a positional field, or a binder
568
+ prefixed with an identifier and ` : ` which destructures a named field.
569
+
570
+ When destructuring named fields, it's common to want to bind the resulting value
571
+ to a variable with the same name. As a convenience, the binder can be omitted on
572
+ a named field. In that case, the field implicitly contains a variable binder
573
+ subpattern with the same name. These are equivalent:
574
+
575
+ ``` dart
576
+ var (first: first, second: second) = (first: 1, second: 2);
577
+ var (first:, second:) = (first: 1, second: 2);
564
578
```
565
579
566
580
** TODO: Allow a ` ... ` element in order to ignore some positional fields while
@@ -753,7 +767,23 @@ Destructures fields from records and objects.
753
767
recordMatcher ::= '(' recordFieldMatchers ')'
754
768
755
769
recordFieldMatchers ::= recordFieldMatcher ( ',' recordFieldMatcher )* ','?
756
- recordFieldMatcher ::= ( identifier ':' )? matcher
770
+ recordFieldMatcher ::= ( identifier ':' )? matcher
771
+ | identifier ':'
772
+ ```
773
+
774
+ Each field is either a positional matcher which destructures a positional field,
775
+ or a matcher prefixed with an identifier and ` : ` which destructures a named
776
+ field.
777
+
778
+ As with record binders, a named field without a matcher is implicitly treated as
779
+ containing a variable matcher with the same name as the field. The variable is
780
+ always ` final ` . These cases are equivalent:
781
+
782
+ ``` dart
783
+ switch (obj) {
784
+ case (first: final first, second: final second): ...
785
+ case (first:, second:): ...
786
+ }
757
787
```
758
788
759
789
** TODO: Add a ` ... ` syntax to allow ignoring positional fields?**
@@ -843,9 +873,9 @@ var (a, b) = (1, 2);
843
873
```
844
874
845
875
Here, the ` (a, b) ` pattern is being matched against the expression ` (1, 2) ` .
846
- When a pattern contains subpatterns, those subpatterns are matched against
847
- values destructured from the value the outer pattern is matched against. Here,
848
- ` a ` is matched against ` 1 ` and ` b ` is matched against ` 2 ` .
876
+ When a pattern contains subpatterns, each subpattern is matched against a value
877
+ destructured from the value that the outer pattern is matched against. Here, ` a `
878
+ is matched against ` 1 ` and ` b ` is matched against ` 2 ` .
849
879
850
880
When calculating the context type schema or static type of a pattern, any
851
881
occurrence of ` typePattern ` in a type is treated as ` Object? ` .
@@ -899,7 +929,7 @@ getters.
899
929
900
930
** TODO: Type inference doesn't currently look at getter return types to infer
901
931
the type arguments of a generic class's constructor, so more work is needed
902
- here.**
932
+ here if we want this to actually infer type arguments .**
903
933
904
934
The context type schema for a pattern ` p ` is:
905
935
@@ -917,11 +947,12 @@ The context type schema for a pattern `p` is:
917
947
* ** Record binder or matcher** :
918
948
* If the pattern has any positional fields, then the base type schema is
919
949
` Destructure_n_<F...> ` where ` _n_ ` is the number of fields and ` F... ` is
920
- the context type schema of all of the positional fields.
950
+ the context type schemas of all of the positional fields.
921
951
* Else the base type schema is ` Object? ` .
922
952
* The base type schema is extended with getters for each named field
923
953
subpattern in ` p ` where each getter's type schema is the type schema of
924
- the corresponding subpattern.
954
+ the corresponding subpattern. (If there is no subpattern because it's
955
+ an implicit variable pattern like ` (field:) ` , the type schema is ` ? ` .)
925
956
926
957
* ** Variable binder** :
927
958
* If ` p ` has a type annotation, the context type schema is that type.
@@ -940,7 +971,7 @@ The context type schema for a pattern `p` is:
940
971
constraint?**
941
972
942
973
* ** Literal matcher** or ** constant matcher** : The context type schema is the
943
- static type of the pattern's value expression.
974
+ static type of the pattern's constant value expression.
944
975
945
976
* ** Declaration matcher** : The context type schema is the same as the context
946
977
type schema of the inner binder.
@@ -980,8 +1011,8 @@ Putting this together, it means the process of completely inferring the types of
980
1011
a construct using patterns works like:
981
1012
982
1013
1 . Calculate the context type schema of the pattern.
983
- 2 . Use that in downwards inference to calculate the type of the value.
984
- 3 . Use that to calculate the static type of a pattern.
1014
+ 2 . Use that in downwards inference to calculate the type of the matched value.
1015
+ 3 . Use that to calculate the static type of the pattern.
985
1016
986
1017
The static type of a pattern ` p ` being matched against a value of type ` M ` is:
987
1018
@@ -1056,13 +1087,37 @@ The static type of a pattern `p` being matched against a value of type `M` is:
1056
1087
1057
1088
* **Record binder or matcher**:
1058
1089
1090
+ 1. Calculate the static types of the field subpatterns:
1091
+
1092
+ 1. It is a compile-time error if there are positional fields, `M` is
1093
+ not `dynamic`, and `M` does not implement `Destructure_n_` with as
1094
+ many type arguments as there are positional fields.
1095
+
1096
+ 1. Calculate the type of each of `f`'s positional field subpatterns
1097
+ using the corresponding type argument in `M`'s implementation of
1098
+ `Destructure_n_` as the matched value type.
1099
+
1100
+ 1. Calculate the type of `f`'s named field subpatterns using the
1101
+ return type of the getter on `M` with the same name as the field
1102
+ as the matched value type. If `M` is `dynamic`, then use `dynamic`
1103
+ as the matched value type. It is a compile-time error if `M` is
1104
+ not `dynamic` and does not have a getter whose name matches the
1105
+ subpattern's field name.
1106
+
1107
+ (If the named field has no subpattern like `(field:)`, treat it as
1108
+ if it has a variable subpattern with the same name as the field and
1109
+ calculate the static type of that subpattern like a normal variable
1110
+ pattern.)
1111
+
1059
1112
1. If `p` has any positional fields, then the static type of `p` is
1060
1113
`Destructure_n_<args...>` where `_n_` is the number of positional
1061
1114
fields and `args...` is a type argument list built from the static
1062
1115
types of the positional field subpatterns, in order.
1063
1116
1064
1117
2. Else the static type of `p` is `Object?`. *You can destructure named
1065
- fields on an object of any type by calling its getters.*
1118
+ fields on an object of any type by calling its getters. In other words,
1119
+ named fields are treated structurally and don't form part of the record
1120
+ pattern's overall static type.*
1066
1121
1067
1122
3. If `M` is not `dynamic`:
1068
1123
* It is a compile-time error if `p` has a field with name `n` and `M`
@@ -1115,7 +1170,9 @@ patterns binds depend on what kind of pattern it is:
1115
1170
1116
1171
* **List binder or matcher**, **map binder or matcher**, or **record binder or
1117
1172
matcher**: These do not introduce variables themselves but may contain type
1118
- patterns and subpatterns that do.
1173
+ patterns and subpatterns that do. A named record field with no subpattern
1174
+ implicitly defines a variable with the same name as the field. If the
1175
+ pattern is a matcher, the variable is `final`.
1119
1176
1120
1177
* **Literal matcher**, **constant matcher**, or **wildcard binder or
1121
1178
matcher**: These do not introduce any variables.
@@ -1387,7 +1444,9 @@ To match a pattern `p` against a value `v`:
1387
1444
treating that as a match failure.*
1388
1445
1389
1446
2 . Match the subpattern of ` f ` against ` r ` . If the match fails,
1390
- the record match fails.
1447
+ the record match fails. (If ` f ` has no subpattern because it's an
1448
+ implicit field pattern like ` (field:) ` , treat it like a the
1449
+ subpattern is a variable pattern with the same name.)
1391
1450
1392
1451
3 . If all field subpatterns match, the record pattern matches.
1393
1452
@@ -1459,6 +1518,11 @@ main() {
1459
1518
1460
1519
## Changelog
1461
1520
1521
+ ### 1.2
1522
+
1523
+ - Add a shorthand for destructuring a named record field to a variable with
1524
+ the same name.
1525
+
1462
1526
### 1.1
1463
1527
1464
1528
- Copy editing and clean up.
0 commit comments