@@ -4,7 +4,7 @@ Author: Bob Nystrom
4
4
5
5
Status: In progress
6
6
7
- Version 1.4 (see [ CHANGELOG] ( #CHANGELOG ) at end)
7
+ Version 1.5 (see [ CHANGELOG] ( #CHANGELOG ) at end)
8
8
9
9
Note: This proposal is broken into a couple of separate documents. See also
10
10
[ records] [ ] and [ exhaustiveness] [ ] .
@@ -1111,25 +1111,117 @@ if (case var s? = maybeString) {
1111
1111
1112
1112
## Static semantics
1113
1113
1114
- A pattern always appears in the context of some value expression that it is
1115
- being matched against. In a switch statement or expression, the value expression
1116
- is the value being switched on. In an if-case statement, the value is the result
1117
- of the expression to the right of the ` = ` . In a variable declaration, the value
1118
- is the initializer :
1114
+ ### Type inference
1115
+
1116
+ Type inference in Dart allows type information in one part of the program to
1117
+ flow over and fill in missing pieces in another part. Inference can flow
1118
+ "upwards" from a subexpression to the surrounding expression :
1119
1119
1120
1120
``` dart
1121
- var (a, b) = (1, 2);
1121
+ [1]
1122
1122
```
1123
1123
1124
- Here, the ` (a, b) ` pattern is being matched against the expression ` (1, 2) ` .
1125
- When a pattern contains subpatterns, each subpattern is matched against a value
1126
- destructured from the value that the outer pattern is matched against. Here, ` a `
1127
- is matched against ` 1 ` and ` b ` is matched against ` 2 ` .
1124
+ Here, we infer ` List<int> ` for the type of the list literal based on type of its
1125
+ element. Inference can flow "downwards" from an expression into its
1126
+ subexpressions too:
1127
+
1128
+ ``` dart
1129
+ <List<int>>[[]]
1130
+ ```
1131
+
1132
+ Here, the inner empty list literal ` [] ` gets type ` List<int> ` because the type
1133
+ argument on the outer list literal is pushed into it.
1134
+
1135
+ Type information can flow through patterns in the same way. From subpatterns
1136
+ upwards to the surrounding pattern:
1137
+
1138
+ ``` dart
1139
+ var [int x] = ...
1140
+ ```
1141
+
1142
+ Here, we infer ` List<int> ` for the list pattern based on the type of the element
1143
+ subpattern. Or downwards:
1144
+
1145
+ ``` dart
1146
+ var <int>[x] = ...
1147
+ ```
1148
+
1149
+ Here, we infer ` int ` for the inner ` x ` subpattern based on the type of the
1150
+ surrounding list pattern.
1151
+
1152
+ In variable declarations, type information can also flow between the variable
1153
+ and its initializer. "Upwards" from initializer to variable:
1154
+
1155
+ ``` dart
1156
+ var x = 1;
1157
+ ```
1158
+
1159
+ Here we infer ` int ` for ` x ` based on the initializer expression's type. That
1160
+ upwards flow extends to patterns:
1161
+
1162
+ ``` dart
1163
+ var [x] = <int>[1];
1164
+ ```
1165
+
1166
+ Here, we infer ` List<int> ` for the list pattern (and thus ` int ` for the ` x `
1167
+ subpattern) based on type of the initializer expression ` <int>[1] ` .
1168
+
1169
+ Types can also flow "downwards" from variable to initializer:
1170
+
1171
+ ``` dart
1172
+ List<int> x = [];
1173
+ ```
1174
+
1175
+ Here, the empty list is instantiated as ` List<int> ` because the type annotation
1176
+ on ` x ` gets pushed over to the initializer. That extends to patterns:
1177
+
1178
+ ``` dart
1179
+ var <num>[x] = [1];
1180
+ ```
1181
+
1182
+ Here, we infer the list literal in the initializer to have type ` List<num> ` (and
1183
+ not ` List<int> ` ) based on the type of list pattern. All of this type flow can be
1184
+ combined:
1185
+
1186
+ ``` dart
1187
+ var (a, b, <double>[c], [int d]) = ([1], <List<int>>[[]], [2], [3]);
1188
+ ```
1189
+
1190
+ To orchestrate this, type inference on patterns proceeds in three phases:
1191
+
1192
+ 1 . ** Calculate the pattern type schema.** Start at the top of the pattern and
1193
+ recurse downwards into subpatterns using the surrounding pattern as context.
1194
+ When we reach the leaves, work back upwards filling in missing pieces where
1195
+ possible. When this completes, we have a type schema for the pattern. It's
1196
+ a type * schema* and not a * type* because there may be holes where types
1197
+ aren't known yet.
1198
+
1199
+ 2 . ** Calculate the static type of the matched value.** A pattern always occurs
1200
+ in the context of some matched value. For pattern variable declarations,
1201
+ this is the initializer. For switches and if-case statements, it's the value
1202
+ being matched.
1203
+
1204
+ Using the pattern's type schema as a context type, infer missing types on
1205
+ the value expression. This is the existing type inference rules on
1206
+ expressions. It yields a complete static type for the matched value.
1207
+
1208
+ 3 . ** Calculate the static type of the pattern.** Using that value type, recurse
1209
+ through the pattern again downwards to the leaf subpatterns filling in any
1210
+ holes in the type schema. When that completes, we now have a full static
1211
+ type for the pattern and all of its subpatterns.
1212
+
1213
+ The full process only comes into play for pattern variable declarations. For
1214
+ switch case, and if-case statements, there is no downwards inference from
1215
+ pattern to value and the first step is skipped. Instead, the type of the matched
1216
+ value is inferred and we jump straight to inferring the types of the case
1217
+ patterns from that context type. * The intent of a matcher pattern is to query
1218
+ the type of the matched value, so it would be strange if that query affected the
1219
+ value expression.*
1128
1220
1129
1221
When calculating the context type schema or static type of a pattern, any
1130
1222
occurrence of ` typePattern ` in a type is treated as ` Object? ` .
1131
1223
1132
- ### Pattern context type schema
1224
+ #### Pattern context type schema
1133
1225
1134
1226
In a non-pattern variable declaration, the variable's type annotation is used
1135
1227
for downwards inference of the initializer:
@@ -1151,8 +1243,6 @@ To support this, every pattern has a context type schema. This is a type
1151
1243
var (a, int b) = ... // Schema is `(?, int)`.
1152
1244
```
1153
1245
1154
- #### Named fields in type schemas
1155
-
1156
1246
Named record fields add complexity to type inference:
1157
1247
1158
1248
``` dart
@@ -1203,18 +1293,14 @@ The context type schema for a pattern `p` is:
1203
1293
the corresponding subpattern. (If there is no subpattern because it's
1204
1294
an implicit variable pattern like ` (field:) ` , the type schema is ` ? ` .)
1205
1295
1206
- * ** Variable binder** :
1207
- * If ` p ` has a type annotation, the context type schema is that type.
1208
- * Else it is ` ? ` .
1209
-
1210
1296
* ** Variable matcher** :
1211
1297
* If ` p ` has a type annotation, the context type schema is ` Object? ` .
1212
1298
* It is not the annotated type because a variable matching pattern can
1213
1299
be used to downcast from any other type.*
1214
1300
* Else it is ` ? ` .
1215
1301
1216
- * ** Cast binder** , ** wildcard matcher ** , or ** extractor matcher** : The context
1217
- type schema is ` Object? ` .
1302
+ * ** Cast binder** , ** variable binder ** , ** wildcard matcher** , or ** extractor
1303
+ matcher ** : The context type schema is ` Object? ` .
1218
1304
1219
1305
** TODO: Should type arguments on an extractor create a type argument
1220
1306
constraint?**
@@ -1243,7 +1329,7 @@ var [int a, num b] = [1, 2];
1243
1329
* Here, the GLB of ` int ` and ` num ` is ` int ` , which ensures that neither ` int a `
1244
1330
nor ` num b ` need to downcast their respective fields.*
1245
1331
1246
- ### Pattern static type
1332
+ #### Pattern static type
1247
1333
1248
1334
Once the value a pattern is matched against has a static type (which means
1249
1335
downwards inference on it using the pattern's context type schema is complete),
@@ -1787,6 +1873,14 @@ main() {
1787
1873
1788
1874
## Changelog
1789
1875
1876
+ ### 1.5
1877
+
1878
+ - Introduce and clarify type inference.
1879
+
1880
+ - The context type schema for a variable matcher is always ` Object? ` , since
1881
+ it's intent is to * match* a type and * cause* the expression to have some
1882
+ type.
1883
+
1790
1884
### 1.4
1791
1885
1792
1886
- Link to [ exhaustiveness] [ ] proposal.
0 commit comments