OLD | NEW |
---|---|
(Empty) | |
1 # Strong Mode | |
2 | |
3 ## Overview | |
4 | |
5 The Dart Development Compiler (DDC) is a new Dart-to-JavaScript compiler that su pports a large subset of the Dart programming language. DDC is motivated by the following goals: | |
6 | |
7 First, we aim to generate clean, readable, consumable JavaScript output. This s implifies debugging Dart applications across multiple web platforms. It also en ables better, seamless interoperability between Dart and JavaScript components. | |
8 | |
9 Second, we aim to compile in a fast, modular fashion. This enables a faster, be tter development cycle across a number of platforms and devices that lack native Dart support. It also allows Dart libraries to be packaged and distributed sep arately for use in other Dart or JavaScript applications. | |
10 | |
11 To accomplish these goals, we focus on a subset of Dart applications we can stat ically type check. This subset can be viewed as a **strong mode** analogous to Dart’s checked mode and production mode. A program that runs correctly in stron g mode will run the same in checked mode and, thus, in production mode. The sub set we support entails: | |
12 | |
13 - A stricter, sounder, type system | |
14 - Type inference | |
15 - Restrictions on certain language constructs | |
16 | |
17 DDC is intended to complement our existing Dart2JS compiler. Unlike DDC, Dart2J S is focused on raw performance and support for the entire Dart language rather than readability, JavaScript interoperability, or modular compilation. | |
18 | |
19 This document provides a high-level overview of strong mode. A corresponding fo rmalism of strong mode can also be found [here](http://www.google.com/url?q=http %3A%2F%2Fdart-lang.github.io%2Fdev_compiler%2Fstrong-dart.pdf&sa=D&sntz=1&usg=AF QjCNEHQ3EZiLkwUs1_ifoVu6R0HSrenw). | |
Jennifer Messerly
2015/07/08 15:44:02
this link seems busted. Should be this?
https://da
vsm
2015/07/08 15:51:46
Done.
| |
20 | |
21 ## Motivation | |
22 | |
23 The standard Dart type system is unsound by design. This means that static type annotations may not match the actual runtime values even when a program is runn ing in checked mode. This allows considerable flexibility, but it also means th at Dart implementations cannot easily use these annotations for optimization or code generation. | |
24 | |
25 Because of this, existing Dart implementations require dynamic dispatch. Furthe rmore, because Dart’s dispatch semantics are different from JavaScript’s, it eff ectively precludes mapping Dart calls to idiomatic JavaScript. For example, the following Dart code: | |
26 | |
27 ```dart | |
28 var x = a.bar; | |
29 b.foo("hello", x); | |
30 ``` | |
31 | |
32 cannot easily be mapped to the identical JavaScript code. If `a` does not conta in a `bar` field, Dart requires a `NoSuchMethodError` while JavaScript simply re turns undefined. If `b` contains a `foo` method, but with the wrong number of a rguments, Dart again requires a `NoSuchMethodError` while JavaScript either igno res extra arguments or fills in omitted ones with undefined. | |
33 | |
34 To capture these differences, the Dart2JS compiler instead generates code that a pproximately looks like: | |
35 | |
36 ```dart | |
37 var x = getInterceptor(a).get$bar(a); | |
38 getInterceptor(b).foo$2(a, "hello", x); | |
39 ``` | |
40 The “interceptor” is Dart’s dispatch table for the objects `a` and `b`, and the mangled names (`get$bar` and `foo$2`) account for Dart’s different dispatch sema ntics. | |
41 | |
42 The above highlights why Dart-JavaScript interoperability hasn’t been seamless: Dart objects and methods do not look like normal JavaScript ones. | |
43 | |
44 DDC relies on strong mode to map Dart calling conventions to normal JavaScript o nes. If `a` and `b` have static type annotations (with a type other than `dynam ic`), strong mode statically verifies that they have a field `bar` and a 2-argum ent method `foo` respectively. In this case, DDC safely generates the identical JavaScript: | |
45 | |
46 ```javascript | |
47 var x = a.bar; | |
48 b.foo("hello", x); | |
49 ``` | |
50 | |
51 Note that DDC still supports the `dynamic` type, but relies on runtime helper fu nctions in this case. E.g., if `a` and `b` are type `dynamic`, DDC instead gene rates: | |
52 | |
53 ```javascript | |
Jennifer Messerly
2015/07/08 15:44:02
fyi, I think "js" works too
vsm
2015/07/08 15:51:46
Acknowledged.
| |
54 var x = dload(a, "bar"); | |
55 dsend(b, "foo", "hello", x); | |
56 ``` | |
57 | |
58 where `dload` and `dsend` are runtime helpers that implement Dart dispatch seman tics. Programmers are encouraged to use static annotations to avoid this. Stron g mode is able to use static checking to enforce much of what checked mode does at runtime. In the code above, strong mode statically verifies that `b`’s type (if not `dynamic`) has a `foo` method that accepts a `String` as its first argum ent and `a.bar`’s type as its second. If the code is sufficiently typed, runtim e checks are unnecessary. | |
59 | |
60 ## Strong Mode Type System | |
61 | |
62 DDC uses strong mode to ensure that static type annotations are actually correct at runtime. For this to work, strong mode requires a stricter type system than standard Dart. To understand this, consider the following, which we will use a s our running example: | |
63 | |
64 ```dart | |
65 library util; | |
66 | |
67 void info(List<int> list) { | |
68 var length = list.length; | |
69 if (length != 0) print("$length ${list[0]}"); | |
70 } | |
71 ``` | |
72 | |
73 A developer might reasonably expect the `info` function to print either nothing (empty list) or two integers (non-empty list), and that Dart’s static tooling an d checked mode would enforce this. | |
74 | |
75 However, in the following context, the info method prints “hello world” in check ed mode, without any static errors or warnings: | |
76 | |
77 ```dart | |
78 import ‘dart:collection’; | |
79 import ‘utils.dart’; | |
80 | |
81 class MyList extends ListBase<int> implements List { | |
82 Object length; | |
83 | |
84 MyList(this.length); | |
85 | |
86 operator[](index) => "world"; | |
87 operator[]=(index, value) {} | |
88 } | |
89 | |
90 void main() { | |
91 List<int> list = new MyList("hello"); | |
92 info(list); | |
93 } | |
94 ``` | |
95 | |
96 The lack of static or runtime errors is not an oversight; it is by design. It p rovides developers a mechanism to circumvent or ignore types when convenient, bu t it comes at cost. While the above example is contrived, it demonstrates that developers cannot easily reason about a program modularly: the static type annot ations in the `utils` library are of limited use, even in checked mode. | |
97 | |
98 For the same reason, a compiler cannot easily exploit type annotations if they a re unsound. A Dart compiler cannot simply assume that a `List<int>` contains `i nt` values or even that its `length` is an integer. Instead, it must either rel y on expensive (and often brittle) whole program analysis or on additional runti me checking. | |
99 | |
100 The fundamental issue above is that static annotations may not match runtime typ es, even in checked mode: this is a direct consequence of the unsoundness of the Dart type system. This can make it difficult for both programmers and compiler s to rely on static types to reason about programs. | |
101 | |
102 Strong mode enforces the correctness of static type annotations. It simply disa llows examples such as the above. It relies on a combination of static checking and runtime assertions. In our running example, standard Dart rules (checked or otherwise) allow `MyList` to masquerade as a `List<int>`. DDC disallows this b y statically rejecting the declaration of `MyList`. This allows both the develo per and the compiler to better reason about the info method. For statically che cked code, both may assume that the argument is a proper `List<int>`, with integ er-valued length and elements. | |
103 | |
104 DDC’s strong mode is strictly stronger than checked mode. A Dart program execut ion where (a) the program passes DDC’s static checking and (b) the execution doe s not trigger DDC’s runtime assertions, will also run in checked mode on any Dar t platform. | |
105 | |
106 | |
107 ### Static typing | |
108 | |
109 The primary sources of unsoundness in Dart are generics and functions. Both int roduce circularity in the Dart subtyping relationship. | |
110 | |
111 #### Generics | |
112 | |
113 Generics in Dart are co-variant, with the added rule that the `dynamic` type may serve as both ⊤ (top) and ⊥ (bottom) of the type hierarchy in certain situation s. For example, let *<:<sub>D</sub>* represent the standard Dart subtyping rul e. Then, for all types `S` and `T`: | |
114 | |
115 `List<S>` <:<sub>D</sub> `List<dynamic>` <:<sub>D</sub> `List<T>` | |
116 | |
117 where `List` is equivalent to `List<dynamic>`. This introduces circularity - e. g.,: | |
118 | |
119 `List<int>` <:<sub>D</sub> `List` <:<sub>D</sub> `List<String>`<:<sub>D</sub> `L ist` <:<sub>D</sub> `List<int>` | |
120 | |
121 | |
122 From a programmer’s perspective, this means that, at compile-time, values that a re statically typed `List<int>` may later be typed `List<String>` and vice versa . At runtime, a plain `List` can interchangeably act as a `List<int>` or a `Lis t<String>` regardless of its actual values. | |
123 | |
124 Our running example exploits this. A `MyList` may be passed to the `info` funct ion as it’s a subtype of the expected type: | |
125 | |
126 `MyList` <:<sub>D</sub> `List` <:<sub>D</sub>`List<int>` | |
127 | |
128 In strong mode, we introduce a stricter subtyping rule <:<sub>S</sub> to disallo w this. In this case, in the context of a generic type parameter, dynamic may o nly serve as ⊤. This means that this is still true: | |
129 | |
130 `List<int>` <:<sub>S</sub> `List` | |
131 | |
132 but that this is not: | |
133 | |
134 `List<int>` ~~<:<sub>S</sub> `List`~~ | |
135 | |
136 | |
137 Our running example fails in strong mode: | |
138 | |
139 `MyList` <:<sub>S</sub> `List` ~~<:<sub>S</sub> `List<int>`~~ | |
140 | |
141 | |
142 #### Functions | |
143 | |
144 The other primary source of unsoundness in Dart is function subtyping. An unusu al feature of the Dart type system is that function types are bivariant in both the parameter types and the return type (see Section 19.5 of the [Dart specifica tion](http://www.google.com/url?q=http%3A%2F%2Fwww.ecma-international.org%2Fpubl ications%2Ffiles%2FECMA-ST%2FECMA-408.pdf&sa=D&sntz=1&usg=AFQjCNGoFPzBNx2fgejKQg SgiS2dUBstBw)). As with generics, this leads to circularity: | |
145 | |
146 `(int) -> int` <:<sub>D</sub> `(Object) -> Object` <:<sub>D</sub> `(int) -> int` | |
147 | |
148 And, as before, this can lead to surprising behavior. In Dart, an overridden me thod’s type should be a subtype of the base class method’s type (otherwise, a st atic warning is given). In our running example, the (implicit) `MyList.length` getter has type: | |
149 | |
150 `() -> Object` | |
151 | |
152 while the `List.length` getter it overrides has type: | |
153 | |
154 `() -> int` | |
155 | |
156 This is valid in standard Dart as: | |
157 | |
158 `() -> Object` <:<sub>D</sub> `() -> int` | |
159 | |
160 Because of this, a `length` that returns "hello" (a valid `Object`) triggers no static or runtime warnings or errors. | |
161 | |
162 Strong mode enforces the stricter, [traditional function subtyping](https://en.w ikipedia.org/wiki/Subtyping#Function_types) rule: subtyping is contravariant in parameter types and covariant in return types. This permits: | |
163 | |
164 `() -> int` <:<sub>S</sub> `() -> Object` | |
165 | |
166 but disallows: | |
167 | |
168 `() -> Object` <:<sub>S</sub> `() -> int` | |
169 | |
170 With respect to our example, strong mode requires that any subtype of a List hav e an int-typed length. It statically rejects the length declaration in MyList. | |
171 | |
172 Formal details of the strong mode type system may be found [here](http://www.go ogle.com/url?q=http%3A%2F%2Fdart-lang.github.io%2Fdev_compiler%2Fstrong-dart.pdf &sa=D&sntz=1&usg=AFQjCNEHQ3EZiLkwUs1_ifoVu6R0HSrenw). | |
173 | |
174 ### Implicit runtime assertions | |
175 | |
176 Although strong mode relies heavily on static checking, it also requires some ru ntime checking for soundness. For example, the following code is allowed: | |
177 | |
178 ```dart | |
179 dynamic x = …; | |
180 List y = x; | |
181 int z = y.length; | |
182 ``` | |
183 | |
184 but a runtime check is required (and inserted by DDC) to ensure that `y` is assi gned a `List`. This is similar to checked mode, but much less pervasive. Check ed mode would also require a runtime check on the assignment of `z`. Strong mod e would not as this is enforced statically instead. | |
185 | |
186 ## Type Inference | |
187 | |
188 A secondary goal of DDC is to preserve the terseness of Dart. While strong mode requires and/or encourages more static type annotations, our aim is make this a s lightweight as possible. | |
189 | |
190 In Dart, per the specification, the static type of a variable `x` declared as: | |
191 | |
192 ``` | |
Jennifer Messerly
2015/07/08 15:44:02
```dart missing from this one? (it's there in othe
vsm
2015/07/08 15:51:46
Done.
| |
193 var x = <String, String>{ "hello": "world"}; | |
194 ``` | |
195 | |
196 is `dynamic` as there is no explicit type annotation on the left-hand side. To d iscourage code bloat, the Dart style guide generally recommends omitting these t ype annotations in many situations. In these cases, the benefits of strong mode would be lost. | |
197 | |
198 To avoid this, strong mode uses limited inference. In the case above, the stron g mode infers and enforces the type of `x` as `Map<String, String>`. An importa nt aspect to inference is ordering: when an inferred type may be used to infer o ther type. To maximize the impact, we perform the following inference in the fo llowing order: | |
199 | |
200 - Top-level and static fields | |
201 - Instance fields and methods | |
202 - Local variables | |
203 - Allocation expressions | |
204 | |
205 In all cases, inference tightens the static type or runtime type as compared to the Dart specification. The `dynamic` type, either alone or in the context of a function or generic parameter type, is inferred to a more specific type. The e ffect of this inference (other than stricter type errors) should not be observab le at runtime outside the use of the mirrors API. (Note, in the next section, w e discuss corresponding restrictions on `is` and `as` type checks.) | |
206 | |
207 ### Top-level and Static Fields | |
208 | |
209 Strong mode will infer the static type of any top-level or static field with: | |
210 | |
211 - No static type annotation | |
212 - An initializer expression | |
213 | |
214 The static type of the declared variable is inferred as the static type of the i nitializer. For example, consider: | |
215 | |
216 ```dart | |
217 var PI = 3.14159; | |
218 var TAU = PI * 2; | |
219 ``` | |
220 | |
221 Strong mode would infer the static type of `PI` as `double` directly from its in itializer. It would infer the static type of `TAU` as `double`, transitively us ing `PI`’s inferred type. Standard Dart rules would treat the static type of bot h `PI` and `TAU` as `dynamic`. Note that the following later assignment would b e allowed in standard Dart, but disallowed (as a static type error) in strong mo de: | |
222 ```dart | |
223 PI = "\u{03C0}"; // Unicode string for PI symbol | |
224 ``` | |
225 Strong mode inference avoids circular dependences. If a variable’s initializer expression refers to another variable whose type would be dependent (directly or transitively) on the first, the static type of that other variable is treated a s `dynamic` for the purpose of inference. In this modified example, | |
226 | |
227 ```dart | |
228 var _PI_FIRST = true; | |
229 var PI = _PI_FIRST ? 3.14159 : TAU / 2; | |
230 var TAU = _PI_FIRST ? PI * 2 : 6.28318; | |
231 ``` | |
232 | |
233 the variables `PI` and `TAU` are circularly dependent on each other. Strong mod e would leave the static type of both as `dynamic`. | |
234 | |
235 <em> | |
236 Note - we’re experimenting with a few arguably simpler variants here: | |
237 - Limiting inference to final or const fields (i.e., not var). | |
238 - Limiting transitive inference to explicit program order. | |
239 </em> | |
240 | |
241 ### Instance Fields and Methods | |
242 | |
243 Strong mode performs two types of inference on instances fields and methods. | |
244 | |
245 The first uses base types to constrain overrides in subtypes. Consider the foll owing example: | |
246 | |
247 ```dart | |
248 abstract class A { | |
249 Map get m; | |
250 int value(int i); | |
251 } | |
252 | |
253 class B extends A { | |
254 var m; | |
255 value(i) => m[i]; | |
256 … | |
257 } | |
258 ``` | |
259 | |
260 In Dart, overridden method, getter, or setter types should be subtypes of the co rresponding base class ones (otherwise, static warnings are given). In standard Dart, the above declaration of `B` is not an error: both `m`’s getter type and `value`’s return type are `dynamic`. | |
261 | |
262 Strong mode - without inference - would disallow this: if `m` in `B` could be as signed an arbitrarily typed value, it would violate the type contract in the dec laration of `A`. | |
263 | |
264 However, rather than rejecting the above code, strong mode employs inference to tighten the static types to obtain a valid override. The corresponding types in B are inferred as if it was: | |
265 | |
266 ```dart | |
267 class B extends A { | |
268 Map m; | |
269 int value(i) => m[i]; | |
270 … | |
271 } | |
272 ``` | |
273 | |
274 Note that the argument type of `value` is left as `dynamic`. Tightening this ty pe is not required for soundness. | |
275 | |
276 The second form inference is limited to instance fields (not methods) and is sim ilar to that on static fields. For instance fields where the static type is omi tted and an initializer is present, the field’s type is inferred as the initiali zer’s type. In this continuation of our example: | |
277 | |
278 ```dart | |
279 class C extends A { | |
280 var y = 42; | |
281 var m = <int, int>{ 0: 38}; | |
282 ... | |
283 } | |
284 ``` | |
285 the instance field `y` has inferred type `int` based upon its initializer. Note that override-based inference takes precedence over initializer-based inference . The instance field `m` has inferred type `Map`, not `Map<int, int>` due to th e corresponding declaration in `A`. | |
286 | |
287 <em> | |
288 Note - we’re considering with a few variants here as well: | |
289 - Limiting inference to final or const fields (i.e., not var). | |
290 - Inference on parameter types when omitted (e.g., the argument to `B.value` abo ve). | |
291 - When to allow or prefer override-based inference. | |
292 </em> | |
293 | |
294 ### Local Variables | |
295 | |
296 As with fields, local variable types are inferred if the static type is omitted and an initializer expression is present. In the following example: | |
297 | |
298 ```dart | |
299 Object foo(int x) { | |
300 final y = x + 1; | |
301 var z = y * 2; | |
302 return z; | |
303 } | |
304 ``` | |
305 | |
306 the static types of `y` and `z` are both inferred as `int` in strong mode. Note that local inference is done in program order: the inferred type of `z` is comp uted using the inferred type of `y`. Local inference may result in strong mode t ype errors in otherwise legal Dart code. In the above, a second assignment to ` z` with a string value: | |
307 ```dart | |
308 z = “$z”; | |
309 ``` | |
310 would trigger a static error in strong mode, but is allowed in standard Dart. I n strong mode, the programmer must use an explicit type annotation to avoid infe rence. Explicitly declaring `z` with the type `Object` or `dynamic` would suffi ce in this case. | |
311 | |
312 ### Allocation Expressions | |
313 | |
314 The final form of strong mode inference is on allocation expressions. This infe rence is rather different from the above: it tightens the runtime type of the co rresponding expression using the static type of its context. Contextual inferen ce is used on expressions that allocated a new object: closure literals, map and list literals, and explicit constructor invocations (i.e., via `new` or `const` ). | |
315 | |
316 #### Closure literals | |
317 | |
318 Consider the following example: | |
319 | |
320 ```dart | |
321 int apply(int f(int arg), int value) { | |
322 return f(value); | |
323 } | |
324 | |
325 void main() { | |
326 int result = | |
327 apply((x) { x = x * 9 ~/ 5; return x + 32; }, 41); | |
328 print(result); | |
329 } | |
330 ``` | |
331 | |
332 The function `apply` takes another function `f`, typed `(int) -> int`, as its fi rst argument. It is invoked in `main` with a closure literal. In standard Dart , the static type of this closure literal would be `(dynamic) -> dynamic`. In s trong mode, this type cannot be safely converted to `(int) -> int` : it may retu rn a `String` for example. | |
333 | |
334 Dart has a syntactic limitation in this case: it is not possible to statically a nnotate the return type of a closure literal. | |
335 | |
336 Strong mode sidesteps this difficulty via contextual inference. It infers the c losure type as `(dynamic) -> int`. This is the most general type allowed by the context: the parameter type of apply. | |
337 | |
338 #### List and map literals | |
339 | |
340 Similarly, strong mode infers tighter runtime types for list and map literals. E.g., in | |
341 | |
342 ```dart | |
343 List<String> l = [ "hello", "world" ]; | |
344 ``` | |
345 | |
346 the runtime type is inferred as `List` in order to match the context of the left hand side. In other words, the code above executes as if it was: | |
347 | |
348 ```dart | |
349 List<String> l = <String>[ "hello", "world" ]; | |
350 ``` | |
351 | |
352 Contextual inference may be recursive: | |
353 | |
354 ```dart | |
355 Map<List<String>, Map<int, int>> map = | |
356 { ["hello"]: { 0: 42 }}; | |
357 ``` | |
358 | |
359 In this case, the inner map literal is inferred and allocated as a `Map<int, int >`. Note, strong mode will statically reject code where the contextually requir ed type is not compatible. This will trigger a static error: | |
360 | |
361 ```dart | |
362 Map<List<String>, Map<int, int>> map = | |
363 { ["hello"]: { 0: "world" }}; // STATIC ERROR | |
364 ``` | |
365 | |
366 as "world" is not of type `int`. | |
367 | |
368 #### Constructor invocations | |
369 | |
370 Finally, strong mode performs similar contextual inference on explicit construct or invocations via new or const. For example: | |
371 | |
372 ```dart | |
373 Set<String> string = new Set.from(["hello", "world"]); | |
374 ``` | |
375 | |
376 is treated as if it was written as: | |
377 | |
378 ```dart | |
379 Set<String> string = | |
380 new Set<String>.from(<String>["hello", "world"]); | |
381 ``` | |
382 | |
383 Note, as above, context is propagated downward into the expression. | |
384 | |
385 ## General Language Restrictions | |
386 | |
387 In addition to stricter typing rules, DDC enforces other restrictions on Dart pr ograms. | |
388 | |
389 ### Warnings are Errors | |
390 | |
391 DDC effectively treats all standard Dart static warnings as static errors. Most of these warnings are required for soundness (e.g., if a concrete class is miss ing methods required by a declared interface). A full list of Dart static warni ngs may found in the [Dart specification](http://www.google.com/url?q=http%3A%2F %2Fwww.ecma-international.org%2Fpublications%2Ffiles%2FECMA-ST%2FECMA-408.pdf&sa =D&sntz=1&usg=AFQjCNGoFPzBNx2fgejKQgSgiS2dUBstBw), or enumerated here: | |
392 | |
393 [https://github.com/dart-lang/sdk/blob/master/pkg/analyzer/lib/src/generated/err or.dart#L3772](https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Fdart-lang %2Fsdk%2Fblob%2Fmaster%2Fpkg%2Fanalyzer%2Flib%2Fsrc%2Fgenerated%2Ferror.dart%23L 3772&sa=D&sntz=1&usg=AFQjCNFc4E37M1PshVcw4zk7C9jXgqfGbw) | |
394 | |
395 ### Is / As Restrictions | |
396 | |
397 Dart is and as runtime checks expose the unsoundness of the type system in certa in cases. For example, consider: | |
398 | |
399 ```dart | |
400 var list = ["hello", "world"]; | |
401 if (list is List<int>) { | |
402 ... | |
403 } else if (list is List<String>) { | |
404 ... | |
405 } | |
406 ``` | |
407 | |
408 Perhaps surprisingly, the first test - `list is List<int>` - evaluates to true h ere. Such code is highly likely to be erroneous. | |
409 | |
410 DDC strong mode statically disallows problematic `is` or `as` checks.. In gener al, an expression: | |
411 | |
412 ```dart | |
413 x is T | |
414 ``` | |
415 | |
416 or | |
417 | |
418 ```dart | |
419 x as T | |
420 ``` | |
421 | |
422 is only allowed where `T` is a *ground type*: | |
423 | |
424 - A non-generic class type (e.g., `Object`, `String`, `int`, ...). | |
425 - A generic class type where all type parameters are implicitly or explicitly `d ynamic` (e.g., `List<dynamic>`, `Map`, …). | |
426 - A function type where the return type and all parameter types are `dynamic` (e .g., (`dynamic`, `dynamic`) -> `dynamic`, ([`dynamic`]) -> `dynamic`). | |
427 | |
428 In all other cases, strong mode reports a static error. | |
429 | |
430 ### Super Invocations | |
431 | |
432 In the context of constructor initializer lists, DDC restricts `super` invocatio ns to the end. This restriction simplifies generated code with minimal effect o n the program. | |
433 | |
434 *Note: Both the VM and Dart2JS ignore the Dart specification on ordering: i.e., they appear to invoke the super constructor after other items on the initializer list regardless of where it appears.* | |
435 | |
436 ### For-in Loops | |
437 | |
438 In for-in statements of the form: | |
439 | |
440 ```dart | |
441 for (var i in e) { … } | |
442 ``` | |
443 | |
444 Strong mode requires the expression `e` to be an `Iterable`. When the loop var iable `i` is also statically typed: | |
445 | |
446 ```dart | |
447 for (T i in e) { … } | |
448 ``` | |
449 | |
450 the expression `e` is required to be an `Iterable<T>`. | |
451 | |
452 *Note: we may weaken these.* | |
453 | |
454 ### Await Expressions | |
455 | |
456 In an await expression of the form: | |
457 ```dart | |
458 await expr | |
459 ``` | |
460 strong mode requires `expr` to be a subtype of `Future`. In standard Dart, this is not required although tools may provide a hint. | |
461 | |
462 ### Open Items | |
463 | |
464 We do not yet implement but are considering the following restrictions as well. | |
465 | |
466 - Disallow overriding fields: this results in complicated generated code where a field definition in a subclass shadows the field definition in a base class but both are generally required to be allocated. Users should prefer explicit gett ers and setters in such cases. See: https://github.com/dart-lang/dev_compiler/i ssues/52 | |
Jennifer Messerly
2015/07/08 15:44:02
I think "See issue #52" would auto link, because "
vsm
2015/07/08 15:51:46
Done - had to do the latter.
| |
467 | |
468 - `Future<Future<T>>`: the Dart specification automatically flattens this type t o `Future<T>` (where `T` is not a `Future`). This can be issue as far as soundn ess. We are considering forbidding this type altogether (with a combination of static and runtime checks). See: https://github.com/dart-lang/dev_compiler/issu es/228 | |
469 | |
OLD | NEW |