@@ -7,11 +7,11 @@ are fairly simple and easy to explain.
77
88### Elevator pitch
99
10- An expression starting with ` . ` is an implicit static namespaces access on the
10+ An expression starting with ` . ` is an implicit static namespace access on the
1111* apparent context type* .
1212
13- The type that the context expects is known, and the expression avoids repeating
14- the type, and starts by doing a static access on that type.
13+ Since the type that the context expects is known, the shorthand expression
14+ avoids repeating the type, and starts by doing a static access on that type.
1515
1616This makes immediate sense for accessing enum and enum-like constants or
1717invoking constructors, which will have the desired type. There is no requirement
@@ -22,7 +22,7 @@ the end. The context type used is the one for the entire selector chain.
2222There must be a context type that allows static member access, similar to when
2323we allow static access through a type alias.
2424
25- We also special-case the ` == ` and ` != ` operators, but nothing else.
25+ We also special-case the ` == ` and ` != ` operators, but nothing else.
2626
2727## Specification
2828
@@ -44,7 +44,8 @@ We introduce grammar productions of the form:
4444
4545We also add ` . ` to the tokens that an expression statement cannot start with.
4646
47- That means you can write things like the following (with the intended meaning as comments, specification to achieve that below):
47+ That means you can write things like the following (with the intended meaning as
48+ comments, specification to achieve that below):
4849
4950``` dart
5051Endian littleEndian = .little; // -> Endian.little (enum value)
@@ -79,6 +80,8 @@ This is a simple grammatical change. It allows new constructs in any place where
7980we currently allow primary expressions, which can be followed by selector chains
8081through the ` <postfixExpression> ` production ` <primary> <selector>* ` .
8182
83+ #### Non-ambiguity
84+
8285A ` <primary> ` cannot immediately follow any other complete expression. We trust
8386that because a primary expression already contains the production
8487` '(' <expression> ')' ` which would cause an ambiguity for ` e1(e2) ` since ` (e2) `
@@ -100,17 +103,17 @@ shorthand can compile at all. If we ever allow metadata on statements, we don’
100103want ` @foo . bar(4) ; ` to be ambiguous. If we ever allow metadata on
101104expressions, we have bigger issues.)_
102105
103- A primary expression * can* follow a ` ? ` in a conditional expression,
106+ A primary expression * can* follow a ` ? ` in a conditional expression, as in
104107` {e1 ? . id : e2} ` . This is not ambiguous with ` e1?.id ` since we parse ` ?. ` as a
105108single token, and will keep doing so. It does mean that ` {e1?.id:e2} ` and
106109` {e1? .id:e2} ` will now both be valid and have different meanings, where the
107110existing grammar didn’t allow the ` ? ` token to be followed by ` . ` anywhere.
108111
109112### Semantics
110113
111- Dart semantics, static and dynamic, does not follow the grammar precisely. For
114+ Dart semantics, static and dynamic, do not follow the grammar precisely. For
112115example, a static member invocation expression of the form ` C.id<T1>(e2) ` is
113- treated as an atomic entity for type inference (and runtime semantics), it ’s not
116+ treated as an atomic entity for type inference (and runtime semantics). It ’s not
114117a combination of doing a ` C.id ` tear-off, then a ` <T1> ` instantiation and then
115118an ` (e2) ` invocation. The context type of that entire expression is used
116119throughout the inference, where ` (e1.id<T1>)(e2) ` has ` (e1.id<T1>) ` in a
@@ -119,14 +122,15 @@ inference, it may have something, but a selector context is not a type context,
119122and it won’t be the context type of the entire expression)._
120123
121124Because of that, the specification of the static and runtime semantics of the
122- new constructs need to address all the forms <Code >.* id* </code >,
125+ new constructs needs to address all the forms <code >.* id* </code >,
123126<code >.* id* \< * typeArgs* \> </code >, <code >.* id* (* args* )</code >,
124127<code >.* id* \< * typeArgs* \> (* args* )</code >, ` .new ` or <code >.new(* args* )</code >.
125128
126- _ (It also addresses ` .new<typeArgs> ` and ` .new<typeArgs>(args) ` , but those will
127- always be compile-time errors because ` .new ` denotes a constructor which is not
128- generic. We do not want this to be treated as ` (.new)<typeArgs>(args) ` which
129- creates and calls a generic tear-off of the constructor.)_
129+ _ (The proposal also addresses ` .new<typeArgs> ` and ` .new<typeArgs>(args) ` , but
130+ those will always be compile-time errors because ` .new ` denotes a constructor
131+ which is not generic. We do not want this to be treated as
132+ ` (.new)<typeArgs>(args) ` which creates and calls a generic tear-off of the
133+ constructor.)_
130134
131135The * general rule* is that any of the expression forms above, starting with
132136<code >.id</code >, are treated exactly * as if* they were prefixed by a fresh
@@ -144,13 +148,13 @@ context type scheme of the entire, maximal selector chain to the static member
144148shorthand, and does not change that when recursing on shorter prefixes._
145149
146150_ The effect will be that ` .id… ` will behave exactly like ` T.id… ` where ` T `
147- denotes the declaration of the context type.
151+ denotes the declaration of the context type._
148152
149153** Definition:** If a shorthand context type schema has the form ` C ` or ` C<...> ` ,
150154and ` C ` is a type introduced by the type declaration * D* , then the shorthand
151155context * denotes the type declaration* * D* . If a shorthand context ` S ` denotes a
152- type declaration * D* , then so does a shorthand context ` S? ` . Otherwise a
153- shorthand context it does not denote any declaration.
156+ type declaration * D* , then so does a shorthand context ` S? ` . Otherwise, a
157+ shorthand context does not denote any declaration.
154158
155159_ This effectively derives a * declaration* from the context type scheme of the
156160surrounding ` <postfixExpression> ` . It allows a nullable context type to denote
@@ -160,12 +164,10 @@ type to nullable just to allow omitting things ._
160164
161165** Constant shorthand** : When inferring types for a ` const .id(arguments) ` or
162166` const .new(arguments) ` with context type schema * C* , let * D* be the declaration
163- denoted by the shorthand context assigned to the ` <staticMemberShorthand> ` . It’s
164- a compile-time error if the shorthand context does not denote a class, mixin,
165- enum or extension type declaration. Then proceed with type inference as if
166- ` .id ` /` .new ` was preceded by an identifier denoting the declaration * D* . It’s a
167- compile-time error if the shorthand context does not denote a class, mixin, enum
168- or extension type declaration.
167+ denoted by the shorthand context assigned to the ` <staticMemberShorthand> ` . Then
168+ proceed with type inference as if ` .id ` /` .new ` was preceded by an identifier
169+ denoting the declaration * D* . It’s a compile-time error if the shorthand context
170+ does not denote a class, mixin, enum or extension type declaration.
169171
170172** Non-constant shorthand** : When inferring types for constructs containing the
171173non-` const ` production, in every place where the current specification specifies
@@ -193,12 +195,13 @@ Doing `List<int> l = .filled(10, 10);` works like doing
193195` List<int> l = List.filled(10, 10); ` , and it is the following downwards
194196inference with context type ` List<int> ` that makes it into
195197` List<int>.filled(10, 10); ` . This distinction matters for something like:
198+
196199``` dart
197200List<String> l = .generate(10, (int i) => i + 1).map((x) => x.toRadixString(16)).toList();
198201```
199202
200- which is equivalent to inserting ` List ` in front of ` .filled ` , which will then
201- be inferred as ` List<int> ` . In most normal use- cases it doesn’t matter, because
203+ which is equivalent to inserting ` List ` in front of ` .generate ` , which will then
204+ be inferred as ` List<int> ` . In most normal use cases it doesn’t matter, because
202205the context type will fill in the missing type variables, but if the
203206construction is followed by more selectors, it loses that context type. _ It also
204207means that the meaning of ` .id ` /` .new ` is * always* the same, it doesn’t matter
@@ -218,21 +221,23 @@ FutureOr<int> = .parse("42"); // Context `FutureOr<int>` is structural type.
218221
219222#### Special case for ` == `
220223
221- For ` == ` , we special-case a second operand that is an static member shorthand.
224+ For ` == ` , we special-case when the right operand is a static member shorthand.
222225
223226If an expression has the form ` e1 == e2 ` or ` e1 != e2 ` , or a pattern has the
224- form ` == e2 ` , where static type of ` e1 ` is * S1* and the function signature of
225- ` operator == ` of ` S1 ` is <code >* R* Function(* T* )</code >, * then*
226- before doing type inference of ` e2 ` as part of that expression or pattern:
227- * If ` e2 ` has the form ` <staticMemberShorthand> <selector>* ` and
227+ form ` == e2 ` , where the static type of ` e1 ` is * S1* and the function signature
228+ of ` operator == ` of ` S1 ` is <code >* R* Function(* T* )</code >, * then* before doing
229+ type inference of ` e2 ` as part of that expression or pattern:
230+
231+ * If ` e2 ` has the form ` <staticMemberShorthand> <selector>* ` and
228232 <code >* T* </code > is a supertype of ` Object ` ,
233+
229234* Then assign * T* as the shorthand context of ` e2 ` .
230235
231236_ If the parameter type of the ` == ` operator of the type of ` e1 ` is,
232- unexpectedly, a proper subtype of ` Object ` (so it's declared ` covariant ` ),
233- it's assumed that that is the kind of object it should be compared to.
234- Otherwise it's assumed that it's something of the same type,
235- most likely an enum value._
237+ unexpectedly, a proper subtype of ` Object ` (so it's declared ` covariant ` ), it's
238+ assumed that that is the kind of object it should be compared to. Otherwise we
239+ assume the right-hand side should have the same type as the left-hand side, most
240+ likely an enum value._
236241
237242This special-casing is only against an immediate static member shorthand.
238243It does not change the * context type* of the second operand, so it would not
@@ -246,7 +251,7 @@ Examples of allowed comparisons:
246251
247252``` dart
248253if (Endian.host == .big) ok!;
249- if (Endian.host case == .big) ok!
254+ if (Endian.host case == .big) ok!;
250255```
251256
252257Not allowed:
@@ -380,7 +385,7 @@ shorthands for any interface type.
380385It is a conspicuous special-casing to allow ` int? ` to denote a static namespace,
381386but it’s special casing of a type that we otherwise special-case all the time.
382387
383- It allows ` int? v = .tryParse(42); ` will work. That’s a * pretty good reason* .< br >
388+ It allows ` int? v = .tryParse(42); ` to work. That’s a * pretty good reason* .
384389It also allows ` int x = .tryParse(input) ?? 0; ` to work, which it
385390wouldn’t otherwise because the context type of ` .tryParse(input) ` is ` int? ` .
386391
0 commit comments