@@ -4,7 +4,7 @@ Author: Bob Nystrom
44
55Status: In progress
66
7- Version 1.4 (see [ CHANGELOG] ( #CHANGELOG ) at end)
7+ Version 1.5 (see [ CHANGELOG] ( #CHANGELOG ) at end)
88
99Note: This proposal is broken into a couple of separate documents. See also
1010[ records] [ ] and [ exhaustiveness] [ ] .
@@ -1111,25 +1111,117 @@ if (case var s? = maybeString) {
11111111
11121112## Static semantics
11131113
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 :
11191119
11201120``` dart
1121- var (a, b) = (1, 2);
1121+ [1]
11221122```
11231123
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.*
11281220
11291221When calculating the context type schema or static type of a pattern, any
11301222occurrence of ` typePattern ` in a type is treated as ` Object? ` .
11311223
1132- ### Pattern context type schema
1224+ #### Pattern context type schema
11331225
11341226In a non-pattern variable declaration, the variable's type annotation is used
11351227for downwards inference of the initializer:
@@ -1151,8 +1243,6 @@ To support this, every pattern has a context type schema. This is a type
11511243var (a, int b) = ... // Schema is `(?, int)`.
11521244```
11531245
1154- #### Named fields in type schemas
1155-
11561246Named record fields add complexity to type inference:
11571247
11581248``` dart
@@ -1203,18 +1293,14 @@ The context type schema for a pattern `p` is:
12031293 the corresponding subpattern. (If there is no subpattern because it's
12041294 an implicit variable pattern like ` (field:) ` , the type schema is ` ? ` .)
12051295
1206- * ** Variable binder** :
1207- * If ` p ` has a type annotation, the context type schema is that type.
1208- * Else it is ` ? ` .
1209-
12101296* ** Variable matcher** :
12111297 * If ` p ` has a type annotation, the context type schema is ` Object? ` .
12121298 * It is not the annotated type because a variable matching pattern can
12131299 be used to downcast from any other type.*
12141300 * Else it is ` ? ` .
12151301
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? ` .
12181304
12191305 ** TODO: Should type arguments on an extractor create a type argument
12201306 constraint?**
@@ -1243,7 +1329,7 @@ var [int a, num b] = [1, 2];
12431329* Here, the GLB of ` int ` and ` num ` is ` int ` , which ensures that neither ` int a `
12441330nor ` num b ` need to downcast their respective fields.*
12451331
1246- ### Pattern static type
1332+ #### Pattern static type
12471333
12481334Once the value a pattern is matched against has a static type (which means
12491335downwards inference on it using the pattern's context type schema is complete),
@@ -1787,6 +1873,14 @@ main() {
17871873
17881874## Changelog
17891875
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+
17901884### 1.4
17911885
17921886- Link to [ exhaustiveness] [ ] proposal.
0 commit comments