@@ -1134,25 +1134,58 @@ succintly, the syntax of Dart is extended to allow the following forms:
1134
1134
any loss of functionality, provided they are not trying to construct a proof
1135
1135
of soundness._
1136
1136
1137
- In addition, the following forms are added to allow constructor invocations,
1138
- dynamic method invocations, function object invocations, instance method
1139
- invocations, and static/toplevel method invocations to be distinguished:
1137
+ In addition, forms are added to allow constructor invocations, dynamic method
1138
+ invocations, function object invocations, instance method invocations, and
1139
+ static/toplevel method invocations to be distinguished. In these forms, `n_i:
1140
+ m_i` (where ` i` is an integer) is used as a convenient meta-syntax to refer to
1141
+ an invocation argument ` m_i ` (an elaborated expression), possibly preceded by a
1142
+ name selector ` n_i: ` (where ` n_i ` is a string). In this document, we use the
1143
+ string ` ∅ ` to represent a name selector which is absent (meaning the
1144
+ corresponding ` m_i ` is a positional argument rather than a named argument).
1145
+
1146
+ The new invocation forms are as follows:
1140
1147
1141
1148
- ` @DYNAMIC_INVOKE(m_0.id<T_1, T_2, ...>(n_1: m_1, n_2: m_2, ...)) `
1142
1149
1150
+ _ This covers invocations of user-definable binary and unary operators, method
1151
+ invocations, and implicit uses of the ` call ` method, where the target has
1152
+ static type ` dynamic ` or ` Function ` . For example, if ` d ` has static type
1153
+ ` dynamic ` , the following expressions will be elaborated using
1154
+ ` @DYNAMIC_INVOKE ` : ` d.f() ` , ` -d ` , ` d + 0 ` , and ` d() ` ._
1155
+
1143
1156
- ` @FUNCTION_INVOKE(m_0.call<T_1, T_2, ...>(n_1: m_1, n_2: m_2, ...)) `
1144
1157
1158
+ _ This covers invocations of expressions whose type is a function type (but not
1159
+ ` Function ` ). For example, if ` l ` has type ` List<void Function()> ` , then
1160
+ ` l.first() ` will be elaborated using ` @FUNCTION_INVOKE ` ._
1161
+
1145
1162
- ` @INSTANCE_INVOKE(m_0.id<T_1, T_2, ...>(n_1: m_1, n_2: m_2, ...)) `
1146
1163
1164
+ _ This covers invocations of user-definable binary and unary operators, method
1165
+ invocations, and implicit uses of the ` call ` method, where the static type of
1166
+ the target is the interface type of a class, mixin, enum, or extension
1167
+ type. For example, if ` i ` has static type ` int ` , and the static type of ` x ` is
1168
+ a class containing a ` call ` method, then the following expressions will be
1169
+ elaborated using ` @INSTANCE_INVOKE ` : ` i.abs() ` , ` -i ` , ` i + 1 ` , and ` x() ` ._
1170
+
1147
1171
- ` @STATIC_INVOKE(f<T_1, T_2, ...>(n_1: m_1, n_2: m_2, ...)) `
1148
1172
1173
+ _ This covers invocations of static methods and top level methods. For example,
1174
+ the following expressions will be elaborated using ` @STATIC_INVOKE ` :
1175
+ ` print(s) ` and ` int.tryParse(s) ` ._
1176
+
1149
1177
In each of these forms, each ` m_i ` represents an elaborated expression, each
1150
1178
` T_i ` represents a type, and each ` n_i ` represents an optional argument name
1151
1179
identifier. When present, ` id ` represents an identifier or operator name, and
1152
1180
` f ` represents a static method or top level function.
1153
1181
1154
1182
The semantics of each of these forms is to evaluate the ` m_i ` in sequence, then
1155
- perform the appropriate kind of method or function call.
1183
+ perform the appropriate kind of method or function call. _ The precise runtime
1184
+ semantics are not specified here, however it should be noted that in the case of
1185
+ ` @DYNAMIC_INVOKE ` , the name ` id ` may not be found in the target's runtime type
1186
+ information at all (in which case ` noSuchMethod ` will be invoked), or ` id ` may
1187
+ resolve to a getter (in which case the getter will be invoked, and then a
1188
+ dynamic invocation of ` call ` will be attempted)._
1156
1189
1157
1190
## Additional properties satisfied by elaborated expressions
1158
1191
@@ -1263,8 +1296,8 @@ non-generic function or method, or when type arguments need to be inferred._
1263
1296
The output of argument part inference is a sequence of elaborated expressions
1264
1297
` {m_1, m_2, ...} ` (of the same length as the sequence of input expressions), a
1265
1298
sequence of zero or more elaborated type arguments ` {U_1, U_2, ...} ` , and a
1266
- result type known as ` R ` . _ (The sequence of optional names is unchanged by
1267
- argument part inference.)_
1299
+ result type ` R ` . _ (The sequence of optional names is unchanged by argument part
1300
+ inference.)_
1268
1301
1269
1302
To emphasize the relationship between argument part inference and the syntax of
1270
1303
Dart source code, the inputs and outputs of argument part inference are
@@ -1281,8 +1314,8 @@ The procedure for argument part inference is as follows:
1281
1314
- Let ` {X_1, X_2, ...} ` be the list of formal type parameters in ` F ` , or an
1282
1315
empty list if ` F ` is ` ∅ ` .
1283
1316
1284
- - Let ` {P_1, P_2, ...} ` be the list of formal parameter types corresponding to
1285
- ` {e_1, e_2, ...} ` , determined as follows:
1317
+ - Let ` {P_1, P_2, ...} ` be the list of formal parameter type schemas
1318
+ corresponding to ` {e_1, e_2, ...} ` , determined as follows:
1286
1319
1287
1320
- If ` F ` is ` ∅ ` , then let each ` P_i ` be ` _ ` .
1288
1321
@@ -1330,17 +1363,17 @@ The procedure for argument part inference is as follows:
1330
1363
- Initialize ` {U_1, U_2, ...} ` to a list of type schemas, of the same length
1331
1364
as ` {X_1, X_2, ...} ` , each of which is ` _ ` .
1332
1365
1333
- - Using subtype constraint generation, attempt to match ` R_F ` as a subtype
1334
- of ` K ` with respect to the list of type variables ` {X_1, X_2, ...} ` .
1366
+ - Check whether ` R_F ` is a subtype match for ` K ` with respect to the list of
1367
+ type variables ` {X_1, X_2, ...} ` .
1335
1368
1336
1369
- If this succeeds, then accumulate the resulting list of type constraints
1337
1370
into ` C ` . Then, let ` {V_1, V_2, ...} ` be the constraint solution for the
1338
- set of type variables ` {X_1, X_2, ...} ` with respect to the constaint
1339
- set ` C ` , with partial solution ` {U_1, U_2, ...} ` . Replace `{U_1, U_2,
1340
- ...}` with ` {V_1, V_2, ...}`. _ This step is known as "downwards
1341
- inference", since it has the effect of passing type information __ down __
1342
- the syntax tree from the context of the invocation to the context of the
1343
- arguments._
1371
+ set of type variables ` {X_1, X_2, ...} ` with respect to the constraint
1372
+ set ` C ` , with partial solution ` {U_1, U_2, ...} ` . Let the new values of
1373
+ ` {U_1, U_2, ...}` be ` {V_1, V_2, ...} ` . _ This step is known as
1374
+ "downwards inference", since it has the effect of passing type
1375
+ information __ down __ the syntax tree from the context of the invocation
1376
+ to the context of the arguments._
1344
1377
1345
1378
- Otherwise, leave ` C ` and ` {U_1, U_2, ...} ` unchanged.
1346
1379
@@ -1369,18 +1402,27 @@ The procedure for argument part inference is as follows:
1369
1402
has the effect that all arguments that are not function expressions are type
1370
1403
inferred first, in the order in which they appear in source code, followed
1371
1404
by all arguments that __ are__ function expressions, possibly in a staged
1372
- fashion._
1405
+ fashion. The reason for traversing the non-function expressions in stage
1406
+ zero before the function expressions is to allow any type promotions that
1407
+ occur in the non-function expressions to carry over into the function
1408
+ expressions, regardless of the order of the arguments. For example, `f(int?
1409
+ i) => g(() { print(i+1); }, i!);` is accepted by type inference, because the
1410
+ null check ` i! ` is guaranteed to execute before the function expression `()
1411
+ { print(i+1); }` can ever be invoked. See
1412
+ https://github.com/dart-lang/language/blob/main/accepted/2.18/horizontal-inference/feature-specification.md#why-do-we-defer-all-function-literals
1413
+ for more information._
1373
1414
1374
1415
- If ` F ` has at least one formal type parameter, and there are zero type
1375
1416
arguments ` T ` (_ in other words, generic type inference is being performed_ ),
1376
1417
then:
1377
1418
1378
- - For each ` e_i ` in stage _ k_ :
1419
+ - For each ` e_i ` in stage _ k_ , in the order in which expression inference
1420
+ was performed:
1379
1421
1380
1422
- Let ` S_i ` be the static type of ` m_i_preliminary ` .
1381
1423
1382
- - Using subtype constraint generation, attempt to match ` S_i ` as a subtype
1383
- of ` K_i ` with respect to the list of type variables ` {X_1, X_2, ...} ` .
1424
+ - Check whether ` S_i ` is a subtype match for ` P_i ` with respect to the
1425
+ list of type variables ` {X_1, X_2, ...} ` .
1384
1426
1385
1427
- If this succeeds, then accumulate the resulting list of type
1386
1428
constraints into ` C ` .
@@ -1391,21 +1433,21 @@ The procedure for argument part inference is as follows:
1391
1433
1392
1434
- If _ k_ is not the last stage in the argument partitioning, then let
1393
1435
` {V_1, V_2, ...} ` be the constraint solution for the set of type
1394
- variables ` {X_1, X_2, ...} ` with respect to the constaint set ` C ` , with
1395
- partial solution ` {U_1, U_2, ...} ` . Replace ` {U_1, U_2, ...} ` with
1396
- ` {V_1, V_2, ...} ` . _ This step is known as "horizontal inference", since
1397
- it has the effect of passing type information __ across __ the syntax tree
1398
- from the static type of some arguments to the context of other
1399
- arguments._
1436
+ variables ` {X_1, X_2, ...} ` with respect to the constraint set ` C ` , with
1437
+ partial solution ` {U_1, U_2, ...} ` . Let the new values of `{U_1, U_2,
1438
+ ...} ` be ` {V_1, V_2, ...}`. _ This step is known as "horizontal
1439
+ inference", since it has the effect of passing type information
1440
+ __ across __ the syntax tree from the static type of some arguments to the
1441
+ context of other arguments._
1400
1442
1401
1443
- Otherwise (_ k_ __ is__ the last stage in the argument partitioning), let
1402
1444
` {V_1, V_2, ...} ` be the _ grounded_ constraint solution for the set of
1403
- type variables ` {X_1, X_2, ...} ` with respect to the constaint set ` C ` ,
1404
- with partial solution ` {U_1, U_2, ...} ` . Replace ` {U_1, U_2, ...} ` with
1405
- ` {V_1, V_2, ...} ` . _ This step is known as "upwards inference", since it
1406
- has the effect of passing type information __ up__ the syntax tree from
1407
- the static type of arguments to the inferred type arguments of the
1408
- invocation._
1445
+ type variables ` {X_1, X_2, ...} ` with respect to the constraint set ` C ` ,
1446
+ with partial solution ` {U_1, U_2, ...} ` . Let the new values of `{U_1,
1447
+ U_2, ...} ` be ` {V_1, V_2, ...}`. _ This step is known as "upwards
1448
+ inference", since it has the effect of passing type information __ up__
1449
+ the syntax tree from the static type of arguments to the inferred type
1450
+ arguments of the invocation._
1409
1451
1410
1452
- _ Note that at this point, all entries in ` {U_1, U_2, ...} ` have been obtained
1411
1453
either from a _ grounded_ constraint solution or from explicit types in the
@@ -1465,7 +1507,10 @@ _Note that if `F` is `∅`, then the resulting graph has no edges._
1465
1507
_ So, for example, if the invocation in question is this:_
1466
1508
1467
1509
``` dart
1468
- f((t, u) { ... } /* A */, () { ... } /* B */, (v) { ... } /* C */, (u) { ... } /* D */)
1510
+ f((t, u) { ... }, // A
1511
+ () { ... }, // B
1512
+ (v) { ... }, // C
1513
+ (u) { ... }) // D
1469
1514
```
1470
1515
1471
1516
_ And the target of the invocation is declared like this:_
@@ -1537,6 +1582,16 @@ name identifiers `{n_1, n_2, ...}`, a sequence of zero or more type arguments
1537
1582
` {T_1, T_2, ...} ` , and a type schema ` K ` . As with [ argument part
1538
1583
inference] ( #Argument-part-inference ) , the symbol ` ∅ ` denotes a missing name.
1539
1584
1585
+ _ Method invocation inference is used for the following constructs:_
1586
+
1587
+ - _ Explicit method invocations (e.g. ` [].add(x) ` ), in which case ` id ` is the name of the method (` add ` in this example)._
1588
+
1589
+ - _ Call invocations (e.g. ` f() ` , where ` f ` is a local variable), in which case
1590
+ ` id ` is ` call ` ._
1591
+
1592
+ - _ Invocations of user-definable operators (e.g. ` 1 + 2 ` ), in which case ` id ` is
1593
+ the name of the operator._
1594
+
1540
1595
The output of method invocation inference is an elaborated expression ` m ` , with
1541
1596
static type ` T ` , where ` m ` and ` T ` are determined as follows:
1542
1597
@@ -1550,9 +1605,9 @@ static type `T`, where `m` and `T` are determined as follows:
1550
1605
then:
1551
1606
1552
1607
- Invoke [ argument part inference] ( #Argument-part-inference ) on `<T_1, T_2,
1553
- ...>(n_1: e_1, n_2: e_2, ...)` , using a target function type of ` ∅` and a
1554
- type schema ` K ` . Denote the resulting elaborated expressions by `{m_1, m_2 ,
1555
- ...}`.
1608
+ ...>(n_1: e_1, n_2: e_2, ...)` , using ` ∅` as the target function type and
1609
+ ` K ` as the context . Denote the resulting elaborated expressions by `{m_1,
1610
+ m_2, ...}`.
1556
1611
1557
1612
- Let ` m ` be `@DYNAMIC_INVOKE(m_0.id<U_1, U_2, ...>(n_1: m_1, n_2: m_2,
1558
1613
...))`.
@@ -1583,10 +1638,10 @@ static type `T`, where `m` and `T` are determined as follows:
1583
1638
then:
1584
1639
1585
1640
- Invoke [ argument part inference] ( #Argument-part-inference ) on `<T_1, T_2,
1586
- ...>(n_1: e_1, n_2: e_2, ...)` , using a target function type of ` U_0` and a
1587
- type schema ` K ` . Denote the resulting elaborated expressions by `{m_1, m_2 ,
1588
- ...}` , the resulting elaborated type arguments by ` {U_1, U_2, ...}`, and the
1589
- result type by ` R ` .
1641
+ ...>(n_1: e_1, n_2: e_2, ...)` , using ` U_0` as the target function type and
1642
+ ` K ` as the context . Denote the resulting elaborated expressions by `{m_1,
1643
+ m_2, ...}` , the resulting elaborated type arguments by ` {U_1, U_2, ...}`,
1644
+ and the result type by ` R ` .
1590
1645
1591
1646
- Let ` m ` be `@FUNCTION_INVOKE(m_0.call<U_1, U_2, ...>(n_1: m_1, n_2: m_2,
1592
1647
...))` , and let ` T` be ` R`. _ Soundness follows from the fact that the static
@@ -1598,10 +1653,10 @@ static type `T`, where `m` and `T` are determined as follows:
1598
1653
- Let ` F ` be the return type of ` U_0 ` 's accessible instance getter named ` id ` .
1599
1654
1600
1655
- Invoke [ argument part inference] ( #Argument-part-inference ) on `<T_1, T_2,
1601
- ...>(n_1: e_1, n_2: e_2, ...)` , using a target function type of ` F` and a
1602
- type schema ` K ` . Denote the resulting elaborated expressions by `{m_1, m_2 ,
1603
- ...}` , the resulting elaborated type arguments by ` {U_1, U_2, ...}`, and the
1604
- result type by ` R ` .
1656
+ ...>(n_1: e_1, n_2: e_2, ...)` , using ` F` as the target function type and
1657
+ ` K ` as the context . Denote the resulting elaborated expressions by `{m_1,
1658
+ m_2, ...}` , the resulting elaborated type arguments by ` {U_1, U_2, ...}`,
1659
+ and the result type by ` R ` .
1605
1660
1606
1661
- Let ` m ` be `@FUNCTION_INVOKE(m_0.id.call<U_1, U_2, ...>(n_1: m_1, n_2: m_2,
1607
1662
...))` , and let ` T` be ` R`. _ Soundness follows from the fact that the static
@@ -1614,10 +1669,18 @@ static type `T`, where `m` and `T` are determined as follows:
1614
1669
- Let ` F ` be the type of ` U_0 ` 's accessible instance method named ` id ` .
1615
1670
1616
1671
- Invoke [ argument part inference] ( #Argument-part-inference ) on `<T_1, T_2,
1617
- ...>(n_1: e_1, n_2: e_2, ...)` , using a target function type of ` F` and a
1618
- type schema ` K ` . Denote the resulting elaborated expressions by `{m_1, m_2,
1619
- ...}` , the resulting elaborated type arguments by ` {U_1, U_2, ...}`, and the
1620
- result type by ` R ` .
1672
+ ...>(n_1: e_1, n_2: e_2, ...)` , using ` F` as the target function type and
1673
+ ` K ` as the context. Denote the resulting elaborated expressions by `{m_1,
1674
+ m_2, ...}` , the resulting elaborated type arguments by ` {U_1, U_2, ...}`,
1675
+ and the result type by ` R ` .
1676
+
1677
+ _ TODO(paulberry): handle the possibility that ` F ` is not a function type (it
1678
+ might even be ` dynamic ` ). Note that the analyzer and CFE currently behave
1679
+ slightly differently if ` F ` is an interface type that declares a getter
1680
+ called ` call ` : the analyzer rejects this (` call ` must be a method), but the
1681
+ CFE accepts it, recursively desugaring ` .call ` invocations to arbitrary
1682
+ depth. See https://github.com/dart-lang/language/issues/3482 for more
1683
+ context._
1621
1684
1622
1685
- Let ` m ` be `@INSTANCE_INVOKE(m_0.id<U_1, U_2, ...>(n_1: m_1, n_2: m_2,
1623
1686
...))` , and let ` T` be ` R`. _ Soundness follows from the fact that the static
@@ -1702,11 +1765,15 @@ _TODO(paulberry): specify this._
1702
1765
### Implicit this invocation
1703
1766
1704
1767
If the selector chain consists of _ < ; identifier> ; < ; argumentPart> ; _ , and
1705
- _ < ; identifier> ; _ __ cannot__ be resolved to the name of a local variable ,
1768
+ _ < ; identifier> ; _ __ cannot__ be resolved using local scope resolution rules ,
1706
1769
then the result of selector chain type inference in context ` K ` is the
1707
1770
elaborated expression ` m ` , with static type ` T ` , where ` m ` and ` T ` are
1708
1771
determined as follows:
1709
1772
1773
+ _ TODO(paulberry): also handle the situation where < ; identifier> ; __ can__ be
1774
+ resolved using local scope resolution rules, but it resolves to a member of the
1775
+ current class, mixin, enum, extension, or extension type._
1776
+
1710
1777
- Let ` m_0 ` be ` this ` , with static type ` T_0 ` , where ` T_0 ` is the interface type
1711
1778
of the immediately enclosing class, enum, mixin, or extension type, or the "on"
1712
1779
type of the immediately enclosing extension. _ The runtime behavior of ` this ` is
@@ -1853,8 +1920,8 @@ _TODO(paulberry): specify this._
1853
1920
### Implicit this method tearoff with type arguments
1854
1921
1855
1922
If the selector chain consists of _ < ; identifier> ; < ; typeArguments> ; _ ,
1856
- and _ < ; identifier> ; _ __ cannot__ be resolved to the name of a local variable,
1857
- then the result of selector chain type inference in context ` K ` is the
1923
+ and _ < ; identifier> ; _ __ cannot__ be resolved using local scope resolution
1924
+ rules, then the result of selector chain type inference in context ` K ` is the
1858
1925
elaborated expression ` m ` , with static type ` T ` , where ` m ` and ` T ` are
1859
1926
determined as follows:
1860
1927
0 commit comments