@@ -7,11 +7,11 @@ are fairly simple and easy to explain.
7
7
8
8
### Elevator pitch
9
9
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
11
11
* apparent context type* .
12
12
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.
15
15
16
16
This makes immediate sense for accessing enum and enum-like constants or
17
17
invoking 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.
22
22
There must be a context type that allows static member access, similar to when
23
23
we allow static access through a type alias.
24
24
25
- We also special-case the ` == ` and ` != ` operators, but nothing else.
25
+ We also special-case the ` == ` and ` != ` operators, but nothing else.
26
26
27
27
## Specification
28
28
@@ -44,7 +44,8 @@ We introduce grammar productions of the form:
44
44
45
45
We also add ` . ` to the tokens that an expression statement cannot start with.
46
46
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):
48
49
49
50
``` dart
50
51
Endian littleEndian = .little; // -> Endian.little (enum value)
@@ -79,6 +80,8 @@ This is a simple grammatical change. It allows new constructs in any place where
79
80
we currently allow primary expressions, which can be followed by selector chains
80
81
through the ` <postfixExpression> ` production ` <primary> <selector>* ` .
81
82
83
+ #### Non-ambiguity
84
+
82
85
A ` <primary> ` cannot immediately follow any other complete expression. We trust
83
86
that because a primary expression already contains the production
84
87
` '(' <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’
100
103
want ` @foo . bar(4) ; ` to be ambiguous. If we ever allow metadata on
101
104
expressions, we have bigger issues.)_
102
105
103
- A primary expression * can* follow a ` ? ` in a conditional expression,
106
+ A primary expression * can* follow a ` ? ` in a conditional expression, as in
104
107
` {e1 ? . id : e2} ` . This is not ambiguous with ` e1?.id ` since we parse ` ?. ` as a
105
108
single token, and will keep doing so. It does mean that ` {e1?.id:e2} ` and
106
109
` {e1? .id:e2} ` will now both be valid and have different meanings, where the
107
110
existing grammar didn’t allow the ` ? ` token to be followed by ` . ` anywhere.
108
111
109
112
### Semantics
110
113
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
112
115
example, 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
114
117
a combination of doing a ` C.id ` tear-off, then a ` <T1> ` instantiation and then
115
118
an ` (e2) ` invocation. The context type of that entire expression is used
116
119
throughout 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,
119
122
and it won’t be the context type of the entire expression)._
120
123
121
124
Because 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 >,
123
126
<code >.* id* \< * typeArgs* \> </code >, <code >.* id* (* args* )</code >,
124
127
<code >.* id* \< * typeArgs* \> (* args* )</code >, ` .new ` or <code >.new(* args* )</code >.
125
128
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.)_
130
134
131
135
The * general rule* is that any of the expression forms above, starting with
132
136
<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
144
148
shorthand, and does not change that when recursing on shorter prefixes._
145
149
146
150
_ 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._
148
152
149
153
** Definition:** If a shorthand context type schema has the form ` C ` or ` C<...> ` ,
150
154
and ` C ` is a type introduced by the type declaration * D* , then the shorthand
151
155
context * 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.
154
158
155
159
_ This effectively derives a * declaration* from the context type scheme of the
156
160
surrounding ` <postfixExpression> ` . It allows a nullable context type to denote
@@ -160,12 +164,10 @@ type to nullable just to allow omitting things ._
160
164
161
165
** Constant shorthand** : When inferring types for a ` const .id(arguments) ` or
162
166
` 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.
169
171
170
172
** Non-constant shorthand** : When inferring types for constructs containing the
171
173
non-` const ` production, in every place where the current specification specifies
@@ -193,12 +195,13 @@ Doing `List<int> l = .filled(10, 10);` works like doing
193
195
` List<int> l = List.filled(10, 10); ` , and it is the following downwards
194
196
inference with context type ` List<int> ` that makes it into
195
197
` List<int>.filled(10, 10); ` . This distinction matters for something like:
198
+
196
199
``` dart
197
200
List<String> l = .generate(10, (int i) => i + 1).map((x) => x.toRadixString(16)).toList();
198
201
```
199
202
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
202
205
the context type will fill in the missing type variables, but if the
203
206
construction is followed by more selectors, it loses that context type. _ It also
204
207
means 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.
218
221
219
222
#### Special case for ` == `
220
223
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.
222
225
223
226
If 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
228
232
<code >* T* </code > is a supertype of ` Object ` ,
233
+
229
234
* Then assign * T* as the shorthand context of ` e2 ` .
230
235
231
236
_ 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._
236
241
237
242
This special-casing is only against an immediate static member shorthand.
238
243
It does not change the * context type* of the second operand, so it would not
@@ -246,7 +251,7 @@ Examples of allowed comparisons:
246
251
247
252
``` dart
248
253
if (Endian.host == .big) ok!;
249
- if (Endian.host case == .big) ok!
254
+ if (Endian.host case == .big) ok!;
250
255
```
251
256
252
257
Not allowed:
@@ -380,7 +385,7 @@ shorthands for any interface type.
380
385
It is a conspicuous special-casing to allow ` int? ` to denote a static namespace,
381
386
but it’s special casing of a type that we otherwise special-case all the time.
382
387
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* .
384
389
It also allows ` int x = .tryParse(input) ?? 0; ` to work, which it
385
390
wouldn’t otherwise because the context type of ` .tryParse(input) ` is ` int? ` .
386
391
0 commit comments