@@ -4,7 +4,7 @@ Author: Bob Nystrom
44
55Status: In progress
66
7- Version 1.1 (see [ CHANGELOG] ( #CHANGELOG ) at end)
7+ Version 1.2 (see [ CHANGELOG] ( #CHANGELOG ) at end)
88
99## Summary
1010
@@ -557,10 +557,24 @@ expressions evaluate to equivalent values.
557557A record pattern destructures fields from a record.
558558
559559```
560- recordBinder ::= '(' recordFieldBinders ')'
560+ recordBinder ::= '(' recordFieldBinders ')'
561561
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);
564578```
565579
566580** TODO: Allow a ` ... ` element in order to ignore some positional fields while
@@ -753,7 +767,23 @@ Destructures fields from records and objects.
753767recordMatcher ::= '(' recordFieldMatchers ')'
754768
755769recordFieldMatchers ::= 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+ }
757787```
758788
759789** TODO: Add a ` ... ` syntax to allow ignoring positional fields?**
@@ -843,9 +873,9 @@ var (a, b) = (1, 2);
843873```
844874
845875Here, 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 ` .
849879
850880When calculating the context type schema or static type of a pattern, any
851881occurrence of ` typePattern ` in a type is treated as ` Object? ` .
@@ -899,7 +929,7 @@ getters.
899929
900930** TODO: Type inference doesn't currently look at getter return types to infer
901931the 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 .**
903933
904934The context type schema for a pattern ` p ` is:
905935
@@ -917,11 +947,12 @@ The context type schema for a pattern `p` is:
917947* ** Record binder or matcher** :
918948 * If the pattern has any positional fields, then the base type schema is
919949 ` 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.
921951 * Else the base type schema is ` Object? ` .
922952 * The base type schema is extended with getters for each named field
923953 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 ` ? ` .)
925956
926957* ** Variable binder** :
927958 * 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:
940971 constraint?**
941972
942973* ** 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.
944975
945976* ** Declaration matcher** : The context type schema is the same as the context
946977 type schema of the inner binder.
@@ -980,8 +1011,8 @@ Putting this together, it means the process of completely inferring the types of
9801011a construct using patterns works like:
9811012
98210131 . 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.
9851016
9861017The static type of a pattern ` p ` being matched against a value of type ` M ` is:
9871018
@@ -1056,13 +1087,37 @@ The static type of a pattern `p` being matched against a value of type `M` is:
10561087
10571088* **Record binder or matcher**:
10581089
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+
10591112 1. If `p` has any positional fields, then the static type of `p` is
10601113 `Destructure_n_<args...>` where `_n_` is the number of positional
10611114 fields and `args...` is a type argument list built from the static
10621115 types of the positional field subpatterns, in order.
10631116
10641117 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.*
10661121
10671122 3. If `M` is not `dynamic`:
10681123 * 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:
11151170
11161171* **List binder or matcher**, **map binder or matcher**, or **record binder or
11171172 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`.
11191176
11201177* **Literal matcher**, **constant matcher**, or **wildcard binder or
11211178 matcher**: These do not introduce any variables.
@@ -1387,7 +1444,9 @@ To match a pattern `p` against a value `v`:
13871444 treating that as a match failure.*
13881445
13891446 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.)
13911450
13921451 3 . If all field subpatterns match, the record pattern matches.
13931452
@@ -1459,6 +1518,11 @@ main() {
14591518
14601519## Changelog
14611520
1521+ ### 1.2
1522+
1523+ - Add a shorthand for destructuring a named record field to a variable with
1524+ the same name.
1525+
14621526### 1.1
14631527
14641528- Copy editing and clean up.
0 commit comments