@@ -68,22 +68,27 @@ constructors in the static extension must return an object whose type is
68
68
For example:
69
69
70
70
``` dart
71
- // Omit extension type parameters when the static extension only has static
72
- // members. Type parameters are just noise for static members, anyway.
71
+ // Omit extension type parameters when the static extension only
72
+ // has static members. Type parameters are just noise for static
73
+ // members, anyway.
73
74
static extension E2 on Map {
74
75
static Map<K2, V> castFromKey<K, V, K2>(Map<K, V> source) =>
75
76
Map.castFrom<K, V, K2, V>(source);
76
77
}
77
78
78
- // Declare extension type parameters, to be used by constructors. The
79
- // type parameters can have stronger bounds than the on-declaration.
79
+ // Declare extension type parameters, to be used by constructors.
80
+ // The type parameters can have stronger bounds than the
81
+ // on-declaration.
80
82
static extension E3<K extends String, V> on Map<K, V> {
81
- factory Map.fromJson(Map<String, Object?> source) => Map.from(source);
83
+ factory Map.fromJson(Map<String, Object?> source) =>
84
+ Map.from(source);
82
85
}
83
86
84
87
var jsonMap = <String, Object?>{"key": 42};
85
88
var typedMap = Map<String, int>.fromJson(jsonMap);
86
- // `Map<int, int>.fromJson(...)` is an error: Violates the bound of `K`.
89
+
90
+ // But `Map<int, int>.fromJson(...)` is an error: It violates the
91
+ // bound of `K`.
87
92
```
88
93
89
94
Another motivation for this mechanism is that it supports constructors of
@@ -120,14 +125,14 @@ static extension E4<X> on Map<X, List<X>> {
120
125
factory Map.listValue(X x) => {x: [x]};
121
126
}
122
127
123
- var int2intList = Map.listValue(1); // Inferred as `Map<int, List<int>>`.
128
+ var int2intList = Map.listValue(1); // `Map<int, List<int>>`.
124
129
// `Map<int, double>.listValue(...)` is an error.
125
130
126
131
static extension E6<Y> on Map<String, Y> {
127
132
factory Map.fromString(Y y) => {y.toString(): y};
128
133
}
129
134
130
- var string2bool = Map.fromString(true); // Inferred as `Map<String, bool>`.
135
+ var string2bool = Map.fromString(true); // `Map<String, bool>`.
131
136
Map<String, List<bool>> string2listOfBool = Map.fromString([]);
132
137
```
133
138
@@ -147,7 +152,8 @@ The grammar is modified as follows:
147
152
...;
148
153
149
154
<staticExtensionDeclaration> ::= // New rule.
150
- 'static' 'extension' <identifier>? <typeParameters>? 'on' <type>
155
+ 'static' 'extension' <identifier>? <typeParameters>?
156
+ 'on' <type>
151
157
'{' (<metadata> <staticExtensionMemberDeclaration>)* '}';
152
158
153
159
<staticExtensionMemberDeclaration> ::= // New rule.
@@ -168,9 +174,6 @@ The grammar is modified as follows:
168
174
('final' | 'const') <type>? <staticFinalDeclarationList> |
169
175
'late' 'final' <type>? <initializedIdentifierList> |
170
176
'late'? <varOrType> <initializedIdentifierList>;
171
-
172
- <constructorNameList> ::=
173
- <constructorName> (',' <constructorName>)*;
174
177
```
175
178
176
179
In a static extension of the form ` static extension E on C {...} ` where ` C `
@@ -257,7 +260,9 @@ constructor or a static member with the same basename as a constructor or a
257
260
static member in the on-declaration of _ D_ .
258
261
259
262
* In other words, a static extension should not have name clashes with its
260
- on-declaration.*
263
+ on-declaration. The warning above is aimed at static members and
264
+ constructors, but a similar warning would probably be useful for name
265
+ clashes with instance members as well.*
261
266
262
267
#### Static extension scopes
263
268
@@ -278,10 +283,10 @@ type parameter scope, if any, and otherwise the library scope.
278
283
Static members in a static extension are subject to the same static
279
284
analysis as static members in other declarations.
280
285
281
- A factory constructor in a static extension introduces scopes in the same
282
- way as other factory constructor declarations. The return type of the
283
- factory constructor is the constructor return type of the static
284
- extension * (that is, the type in the ` on ` clause)* .
286
+ A constructor in a static extension introduces scopes in the same way as
287
+ other constructor declarations. The return type of the constructor is the
288
+ constructor return type of the static extension * (that is, the type in the
289
+ ` on ` clause)* .
285
290
286
291
Type variables of a static extension ` E ` are in scope in static member
287
292
declarations in ` E ` , but any reference to such type variables in a static
@@ -295,46 +300,95 @@ the current library, or if _D_ is imported and not hidden.
295
300
296
301
* In particular, it is accessible even in the case where there is a name
297
302
clash with another locally declared or imported declaration with the same
298
- name.*
299
-
300
- #### Invocation of a static member of a static extension
301
-
302
- An _ explicitly resolved invocation_ of a static member of a static
303
- extension named ` E ` is an expression of the form ` E.m() ` (or any other
304
- member access, * e.g., ` E.m ` , ` E.m = e ` , etc* ), where ` m ` is a static member
305
- declared by ` E ` .
303
+ name. This is also true if _ D_ is imported with a prefix. Similarly, it is
304
+ accessible even in the case where _ D_ does not have a name, if it is
305
+ declared in the current library.*
306
+
307
+ #### Invocation of a static member
308
+
309
+ * The language specification defines the notion of a _ member invocation_ in
310
+ the section [ Member Invocations] [ ] , which is used below. This concept
311
+ includes method invocations like ` e.aMethod<int>(24) ` , property extractions
312
+ like ` e.aGetter ` or ` e.aMethod ` (tear-offs), operator invocations like
313
+ ` e1 + e2 ` or ` aListOrNull?[1] = e ` , function invocations like ` f() ` . Each
314
+ of these expressions has a _ syntactic receiver_ and an _ associated member
315
+ name_ . With ` e.aMethod<int>(24) ` , the receiver is ` e ` and the associated
316
+ member name is ` aMethod ` , with ` e1 + e2 ` the receiver is ` e1 ` and the
317
+ member name is ` + ` , and with ` f() ` the receiver is ` f ` and the member name
318
+ is ` call ` . Note that the syntactic receiver is a type literal in the case
319
+ where the member invocation invokes a static member. In the following we
320
+ will specify invocations of static members using this concept.*
321
+
322
+ [ Member Invocations ] : https://github.com/dart-lang/language/blob/94194cee07d7deadf098b1f1e0475cb424f3d4be/specification/dartLangSpec.tex#L13903
323
+
324
+ Consider an expression ` e ` which is a member invocation with syntactic
325
+ receiver ` E ` and associated member name ` m ` , where ` E ` denotes a static
326
+ extension and ` m ` is a static member declared by ` E ` . We say that ` e ` is an
327
+ _ explicitly resolved invocation_ of said static member of ` E ` .
306
328
307
329
* This can be used to invoke a static member of a specific static extension
308
- in order to manually resolve a name clash.*
309
-
310
- A static member invocation on a class ` C ` , of the form ` C.m() ` (or any
311
- other member access), is resolved by looking up static members in ` C ` named
312
- ` m ` and looking up static members of every accessible static extension with
313
- on-declaration ` C ` and a member named ` m ` .
314
-
315
- If ` C ` contains such a declaration then the expression is an invocation of
316
- that static member of ` C ` , with the same static analysis and dynamic
317
- semantics as before the introduction of this feature.
318
-
319
- Otherwise, an error occurs if no declarations named ` m ` or more than one
320
- declaration named ` m ` were found. * They would necessarily be declared in
321
- static extensions.*
322
-
323
- Otherwise, the invocation is resolved to the given static member
324
- declaration in a static extension named ` Ej ` , and the invocation is treated
325
- as ` Ej.m() ` * (this is an explicitly resolved invocation, which is specified
326
- above)* .
330
+ in order to manually resolve a name clash.
331
+
332
+ Consider an expression ` e ` which is a member invocation with syntactic
333
+ receiver ` C ` and an associated member name ` m ` , where ` C ` denotes a class
334
+ and ` m ` is a static member declared by ` C ` . The static analysis and dynamic
335
+ semantics of this expression is the same as in Dart before the introduction
336
+ of this feature.
337
+
338
+ When ` C ` declares a static member whose basename is the basename of ` m ` ,
339
+ but ` C ` does not declare a static member named ` m ` or a constructor named
340
+ ` C.m ` , a compile-time error occurs. * This is the same behavior as in
341
+ pre-feature Dart. It's about "near name clashes" involving a setter.*
342
+
343
+ In the case where ` C ` does not declare any static members whose basename is
344
+ the basename of ` m ` , and ` C ` does not declare any constructors named ` C.m2 `
345
+ where ` m2 ` is the basename of ` m ` , let _ M_ be the set containing each
346
+ accessible extension whose on-declaration is ` C ` , and whose static members
347
+ include one with the name ` m ` , or which declares a constructor named ` C.m ` .
348
+
349
+ * If ` C ` does declare a constructor with such a name ` C.m2 ` then the given
350
+ expression is not a static member invocation. This case is described in a
351
+ section below.*
352
+
353
+ Otherwise * (when ` C ` does not declare such a constructor)* , an error occurs
354
+ if _ M_ is empty or _ M_ contains more than one member.
355
+
356
+ Otherwise * (when no error occurred)* , assume that _ M_ contains exactly one
357
+ element which is an extension ` E ` that declares a static member named
358
+ ` m ` . The invocation is then treated as ` E.m() ` * (this is an explicitly
359
+ resolved invocation, which is specified above)* .
360
+
361
+ Otherwise * (when ` E ` does not declare such a static member)* , _ M_ will
362
+ contain exactly one element which is a constructor named ` C.m ` . This is not
363
+ a static member invocation, and it is specified in a section below.
364
+
365
+ In addition to these rules for invocations of static members of a static
366
+ extension or a class, a corresponding set of rules exist for a static
367
+ extension and the following: An enumerated declaration * (` enum ... ` )* , a
368
+ mixin class, a mixin, and an extension type. They only differ by being
369
+ concerned with a different kind of on-declaration.
370
+
371
+ In addition to the member invocations specified above, it is also possible
372
+ to invoke a static member of the enclosing declaration based on lexical
373
+ lookup. This case is applicable when an expression in a class, enum, mixin
374
+ or extension type resolves to an invocation of a static member of the
375
+ enclosing declaration.
376
+
377
+ * This invocation will never invoke a static member of a static extension
378
+ which is not the enclosing declaration. In other words, there is nothing
379
+ new in this case.*
327
380
328
381
#### The instantiated constructor return type of a static extension
329
382
330
- We associate a static extension declaration _ D_ named ` E ` with formal type
331
- parameters ` X1 extends B1 .. Xs extends Bs ` and an actual type argument
332
- list ` T1 .. Ts ` with a type known as the _ instantiated constructor return
333
- type of_ _ D_ _ with type arguments_ ` T1 .. Ts ` .
383
+ Assume that _ D_ is a generic static extension declaration named ` E ` with
384
+ formal type parameters ` X1 extends B1, ..., Xs extends Bs ` and constructor
385
+ return type ` C<S1 .. Sk> ` . Let ` T1, ..., Ts ` be a list of types. The
386
+ _ instantiated constructor return type_ of _ D_ _ with actual type arguments_
387
+ ` T1 .. Ts ` is then the type ` [T1/X1 .. Ts/Xs]C<S1 .. Sk> ` .
334
388
335
- When a static extension declaration _ D_ named ` E ` has an on-clause which
336
- denotes a non-generic class ` C ` , the instantiated constructor return type
337
- is ` C ` , for any list of actual type arguments.
389
+ * As a special case, assume that _ D_ has an on-type which denotes a
390
+ non-generic class ` C ` . In this case , the instantiated constructor return
391
+ type is ` C ` , for any list of actual type arguments.*
338
392
339
393
* Note that such type arguments can be useful, in spite of the fact that
340
394
they do not occur in the type of the newly created object. For example:*
@@ -352,25 +406,16 @@ static extension E<X> on A {
352
406
void main() {
353
407
// We can create an `A` "directly".
354
408
A a = A(42);
355
-
409
+
356
410
// We can also use a function to compute the `int`.
357
411
a = A.computed('Hello!', (s) => s.length);
358
412
}
359
413
```
360
414
361
- When a static extension declaration _ D_ has no formal type parameters, and
362
- it has an on-type ` C<S1 .. Sk> ` , the instantiated constructor return type
363
- of _ D_ is ` C<S1 .. Sk> ` .
364
-
365
- * In this case the on-type is a fixed type (also known as a ground type),
366
- e.g., ` List<int> ` . This implies that the constructor return type of D is
367
- the same for every call site.*
368
-
369
- Finally we have the general case: Consider a static extension declaration
370
- _ D_ named ` E ` with formal type parameters ` X1 extends B1 .. Xs extends Bs `
371
- and a constructor return type ` C<S1 .. Sk> ` . With actual type arguments
372
- ` T1 .. Ts ` , the instantiated constructor return type of _ D_ with type
373
- arguments ` T1 .. Ts ` is ` [T1/X1 .. Ts/Xs]C<S1 .. Sk> ` .
415
+ * As another special case, assume that _ D_ has no formal type parameters,
416
+ and it has a constructor return type of the form ` C<S1 .. Sk> ` . In this
417
+ case the instantiated constructor return type of _ D_ is ` C<S1 .. Sk> ` ,
418
+ which is a ground type, and it is the same for all call sites.*
374
419
375
420
#### Invocation of a constructor in a static extension
376
421
@@ -391,7 +436,7 @@ information. In particular, the actual type arguments passed to the
391
436
extension determines the actual type arguments passed to the class, which
392
437
means that the explicitly resolved invocation typically has quite some
393
438
redundancy (but it is very easy to check whether it is consistent, and it
394
- is an error if it is inconsistent). Every other form is reduced to the
439
+ is an error if it is inconsistent). Every other form is reduced to this
395
440
explicitly resolved form.*
396
441
397
442
A compile-time error occurs if the type arguments passed to ` E ` violate the
@@ -415,10 +460,10 @@ normalization occurs. *In other words, the types must be equal, not
415
460
just mutual subtypes.*
416
461
417
462
* Note that explicitly resolved invocations of constructors declared in
418
- static extensions are an exception in real code, usable in the case where a
419
- name clash prevents an implicitly resolved invocation. However, implicitly
420
- resolved invocations are specified in the rest of this section by reducing
421
- them to explicitly resolved ones.*
463
+ static extensions are a rare exception in real code, usable in the case
464
+ where a name clash prevents an implicitly resolved invocation. However,
465
+ implicitly resolved invocations are specified in the rest of this section
466
+ by reducing them to explicitly resolved ones.*
422
467
423
468
A constructor invocation of the form ` C<T1 .. Tm>.name(args) ` is partially
424
469
resolved by looking up a constructor named ` C.name ` in the class ` C ` and in
@@ -437,46 +482,65 @@ Otherwise, the invocation is partially resolved to a set of candidate
437
482
constructors found in static extensions. Each of the candidates _ kj_ is
438
483
vetted as follows:
439
484
440
- Assume that _ kj_ is a constructor declared by a static extension _ D_ named
441
- ` E ` with type parameters ` X1 extends B1 .. Xs extends Bs ` and on-type
442
- ` C<S1 .. Sm> ` . Find actual values ` U1 .. Us ` for ` X1 .. Xs ` satisfying the
443
- bounds ` B1 .. Bs ` , such that ` ([U1/X1 .. Us/Xs]C<S1 .. Sm>) == C<T1 .. Tm> ` .
444
- If this fails then remove _ kj_ from the set of candidate constructors.
445
- Otherwise note that _ kj_ uses actual type arguments ` U1 .. Us ` .
485
+ If ` m ` is zero and ` E ` is an accessible extension with on-declaration ` C `
486
+ that declares a static member whose basename is ` name ` then the invocation
487
+ is a static member invocation * (which is specified in an earlier section)* .
488
+
489
+ Otherwise, assume that _ kj_ is a constructor declared by a static extension
490
+ _ D_ named ` E ` with type parameters ` X1 extends B1 .. Xs extends Bs ` ,
491
+ on-declaration ` C ` , and on-type ` C<S1 .. Sm> ` . Find actual values
492
+ ` U1 .. Us ` for ` X1 .. Xs ` satisfying the bounds ` B1 .. Bs ` , such that
493
+ ` ([U1/X1 .. Us/Xs]C<S1 .. Sm>) == C<T1 .. Tm> ` . This may determine the
494
+ value of some of the actual type arguments ` U1 .. Us ` , and others may be
495
+ unconstrained (because they do not occur in ` C<T1 .. Tm> ` ). Actual type
496
+ arguments corresponding to unconstrained type parameters are given as ` _ `
497
+ (and they are subject to inference later on, where the types of the actual
498
+ arguments ` args ` may influence their value). If this inference fails
499
+ then remove _ kj_ from the set of candidate constructors. Otherwise note
500
+ that _ kj_ uses actual type arguments ` U1 .. Us ` .
446
501
447
502
If all candidate constructors have been removed, or more than one candidate
448
503
remains, a compile-time error occurs. Otherwise, the invocation is
449
504
henceforth treated as ` E<U1 .. Us>.C<T1 .. Tm>.name(args) ` (respectively
450
- ` E<U1 .. Us>.C<T1 .. Tm>(args) ` ).
505
+ ` E<U1 .. Us>.C<T1 .. Tm>(args) ` ). * This is an explicitly resolved static
506
+ extension constructor invocation, which is specified above.*
451
507
452
508
A constructor invocation of the form ` C.name(args) ` (respectively
453
509
` C(args) ` ) where ` C ` denotes a non-generic class is resolved in the
454
- same manner, with ` m == 0 ` .
455
-
456
- * In this case, type parameters declared by ` E ` may be inferred based on the
457
- constructor signature (similarly to the example with ` A.computed ` above),
458
- or they will be bound to values selected by instantiation to bound.*
510
+ same manner, with ` m == 0 ` .
459
511
460
512
Consider a constructor invocation of the form ` C.name(args) ` (and similarly
461
513
for ` C(args) ` ) where ` C ` denotes a generic class. As usual, the
462
514
invocation is treated as in the pre-feature language when it denotes a
463
515
constructor declared by the class ` C ` .
464
516
465
- In the case where the context type schema for this invocation fully
466
- determines the actual type arguments of ` C ` , the expression is changed to
467
- receive said actual type arguments, ` C<T1 .. Tm>.name(args) ` , and treated
468
- as described above.
517
+ In the case where the context type schema for this invocation
518
+ determines some actual type arguments of ` C ` , the expression is changed to
519
+ receive said actual type arguments, ` C<T1 .. Tm>.name(args) ` (where the
520
+ unconstrained actual type arguments are given as ` _ ` and inferred later).
521
+ The expression is then treated as described above.
522
+
523
+ Next, we construct a set _ M_ containing all accessible static extensions
524
+ with on-declaration ` C ` that declare a constructor named ` C.name `
525
+ (respectively ` C ` ).
469
526
470
- In the case where the invocation resolves to exactly one constructor
471
- ` C.name ` (or ` C ` ) declared by a static extension named ` E ` , the invocation
472
- is treated as ` E.C.name(args) ` (respectively ` E.C(args) ` ).
527
+ In the case where _ M _ contains exactly one extension ` E ` that declares a
528
+ constructor named ` C.name ` (respectively ` C ` ), the invocation is treated as
529
+ ` E.C.name(args) ` (respectively ` E.C(args) ` ).
473
530
474
- Otherwise, when there are two or more candidates from static extensions,
475
- an error occurs. * We do not wish to specify an approach whereby ` args ` is
531
+ Otherwise, when there are two or more candidates from static extensions, an
532
+ error occurs. * We do not wish to specify an approach whereby ` args ` is
476
533
subject to type inference multiple times, and hence we do not support type
477
534
inference for ` C.name(args) ` in the case where there are multiple distinct
478
535
declarations whose signature could be used during the static analysis of
479
- that expression.*
536
+ that expression. The workaround is to specify the actual type arguments
537
+ explicitly.*
538
+
539
+ In addition to these rules for invocations of constructors of a static
540
+ extension or a class, a corresponding set of rules exist for a static
541
+ extension and the following: An enumerated declaration * (` enum ... ` )* , a
542
+ mixin class, a mixin, and an extension type. They only differ by being
543
+ concerned with a different kind of declaration.
480
544
481
545
### Dynamic Semantics
482
546
@@ -495,7 +559,7 @@ This fully determines the dynamic semantics of this feature.
495
559
496
560
### Changelog
497
561
498
- 1.1 - August 28 , 2024
562
+ 1.1 - August 30 , 2024
499
563
500
564
* Clarify many parts.
501
565
0 commit comments