Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(615)

Side by Side Diff: doc/RUNTIME_SAFETY.md

Issue 1541833002: Update strong mode doc (Closed) Base URL: https://github.com/dart-lang/dev_compiler.git@master
Patch Set: Fixed links Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Strong Mode in the Dart Dev Compiler
2
3 ## Overview
4
5 In the Dart Dev Compiler (DDC), [static strong mode](STATIC_SAFETY.md) checks ar e augmented with stricter runtime behavior. Together, they enforce the soundnes s of Dart type annotations.
6
7 In general, and in contrast to Dart's checked mode, most safety is enforced stat ically, at analysis time. DDC exploits this to generate relatively few runtime checks while still providing stronger guarantees than checked mode.
8
9 In particular, DDC adds the following:
10
11 - Stricter (but fewer) runtime type checks
12 - Reified type narrowing
13 - Restricted `is`/`as` checks
14
15 In all these cases, DDC (with static checks) is stricter than standard checked m ode (or production mode). It may reject (either statically or at runtime) progr ams that run correctly in checked mode (similar to how checked mode may reject p rograms that run in production mode).
16
17 On the other hand, programs that statically check and run correctly in DDC shoul d also run the same in checked mode. A caveat to note is that mirrors (or `runt imeType`) may show a more narrow type in DDC (though, in practice, programmers a re discouraged from using these features for performance / code size reasons).
18
19 ## Runtime checks
20
21 In practice, strong mode enforces most type annotations at compile time, and, th us, requires less work at runtime to enforce safety. Consider the following Dar t code:
22
23 ```dart
24 String foo(Map<int, String> map, int x) {
25 return map[x.abs()];
26 }
27 ```
28
29 Strong mode will enforce that the function `foo` is only invoked in a manner con sistent with its signature. DDC - which assumes strong mode static checking - i nserts no further runtime checks. In contrast, standard Dart checked mode would check the type of the parameters - `map` and `x` - along with the type of the r eturn value at runtime on every invocation of `foo`. Even Dart production mode, depending on the implementation and its ability to optimize, may require simila r checking to dynamically dispatch the map lookup and the method call in the bod y of `foo`.
Bob Nystrom 2016/02/02 23:02:16 " - " -> "—".
vsm 2016/02/03 00:50:04 Done.
30
31 Nevertheless, there are cases where DDC still requires runtime checks. (Note: D DC may eventually provide a mode to elide these checks, but this would violate s oundness and is beyond the scope of this document.)
32
33 ### Implicit casts
34
35 Dart has flexible assignability rules. Programmers are not required to explicit ly cast from supertypes to subtypes. For example, the following is valid Dart:
36
37 ```dart
38 Object o = ...;
39 String s = o; // Implicit downcast
40 String s2 = s.substring(1);
41 ```
42
43 The assignment to `s` is an implicit downcast from `Object` to `String` and trig gers a runtime check in DDC to ensure it is correct.
44
45 Note that checked mode would also perform this runtime test. Unlike checked mod e, DDC would not require a check on the assignment to `s2` - this type is establ ished statically.
46
47 ### Inferred variables
48
49 Dart's inference may narrow the static type of certain variables. If the variab le is mutable, DDC will enforce the narrower type at runtime when necessary.
Bob Nystrom 2016/02/02 23:02:16 "will enforce" -> "enforces".
vsm 2016/02/03 00:50:04 Done.
50
51 In the following example, strong mode will infer of the type of the local variab le `y` as an `int`:
52
53 ```dart
54 int bar(Object x) {
55 var y = 0;
56 if (x != null) {
57 y = x;
58 }
59 return y.abs();
60 }
61 ```
62
63 This allows it to, for example, static verify the call to `y.abs()` and determin e that it returns an `int`. However, the parameter `x` is typed as `Object` and the assignment from `x` to `y` now requires a type check to ensure that `y` is only assigned an `int`.
64
65 Note, strong mode and DDC are conservative by enforcing a tighter type than requ ired by standard Dart checked mode. For example, checked mode would accept a no n-`int` `x` with an `abs` method that happened to return an `int`. In strong mo de, a programmer would have to explicitly opt into this behavior by annotating ` y` as an `Object` or `dynamic`.
66
67 ### Covariant generics
68
69 Strong mode preserves the covariance of Dart's generic classes. To support this soundly, DDC injects runtime checks on parameters in method invocations whose t ype is a class type parameter. Consider the call to `baz` in the parameterized class `A`:
70
71 ```dart
72 class A<T> {
73 T baz(T x, int y) => x;
74 }
75
76 void foo(A<Object> a) {
77 a.baz(42, 38);
78 }
79
80 void main() {
81 var aString = new A<String>();
82 foo(aString);
83 }
84 ```
85
86 Statically, sound mode will not generate an error or warning on this code. The call to `baz` in `foo` is statically valid as `42` is an `Object` (as required b y the static type of `a`). However, the runtime type of `a` in this example is the narrower `A<String>`. At runtime, when baz is executed, DDC will check that the type of `x` matches the reified type parameter and, in this example, fail.
87
88 Note, only `x` requires a runtime check. Unlike checked mode, no runtime check is required for `y` or the return value. Both are statically verified.
89
90 ### Dynamic operations
91
92 Strong mode allows programmers to explicitly use `dynamic` as a type. It also a llows programmers to omit types, and in some of these cases inference may fall b ack on `dynamic` if it cannot determine a static type. In these cases, DDC inse rts runtime checks (typically in the form of runtime helper calls).
93
94 For example, in the following:
95
96 ```dart
97 int foo(int x) => x + 1;
98
99 void main() {
100 dynamic bar = foo;
101 bar("hello"); // DDC runtime error
102 }
103 ```
104
105 `foo` (via `bar`) is incorrectly invoked on a `String`. There is no static erro r as `bar` is typed `dynamic`. Instead DDC, performs extra runtime checking on the invocation of `bar`. In this case, it would generate a runtime type error. Note, if the type of `bar` had been omitted, it would have been inferred, and t he error would have been reported statically.
106
107 Nevertheless, there are situations where programmers may prefer a dynamic type f or flexibility.
108
109 ## Runtime type Narrowing
110
111 Strong mode statically infers tighter types for functions and generics. In DDC, this is reflected in the reified type at runtime. This allows DDC to enforce t he stricter type soundly at runtime when necessary.
112
113 In particular, this means that DDC may have a stricter concrete runtime type tha n other Dart implementations for generic classes and functions. The DDC type wi ll always be a subtype.
114
115 This will impact execution in the following ways:
116 - DDC may trigger runtime errors where checked mode is forgiving.
117 - Code that uses reflection may observe a narrower type in DDC.
118
119 ### Allocation inference
120
121 When strong infers a narrower type for a closure literal or other allocation exp ression, DDC reifies this narrower type at runtime. As a result, it can soundly enforce typing errors at runtime.
122
123 The following is an example of where static checking fails to catch a typing err or:
124
125 ```dart
126 apply(int g(x), y) {
127 print(g(y));
128 }
129
130 typedef int Int2Int(int x);
131
132 void main() {
133 Int2Int f = (x) => x + x;
134 apply(f, "hello");
135 }
136 ```
137
138 A programmer examining `apply` would reasonably expect it to print an `int` valu e. The analyzer (with or without strong mode) fails to report a problem. Stand ard Dart checked simply prints `"hellohello"`. In DDC, however, a runtime error is thrown on the application of `g` in `apply`. The closure literal assigned t o `f` in `main` is reified as an `int -> int`, and DDC enforces this at runtime.
139
140 In this example, if `apply` and its parameters were fully typed, strong mode wou ld report a static error, and DDC would impose no runtime check.
141
142 ### Generic methods
143
144 [Note: This is not yet implemented correctly.](https://github.com/dart-lang/dev_ compiler/issues/301)
145
146 Similarly, DDC requires that [generic methods](GENERIC_METHODS.md) return the co rrect reified type. In strong mode, `Iterable.map` is a generic method. In DDC , `lengths` in `main` will have a reified type of `List<int>`. In `foo`, this w ill trigger a runtime error when a string is added to the list.
147
148 ```dart
149 void foo(List l) {
150 l.add("a string");
151 }
152
153 void main() {
154 Iterable<String> list = <String>["hello", "world"];
155 List<int> lengths = list.map((x) => x.length).toList();
156 foo(lengths);
157 print(lengths[2]);
158 }
159 ```
160
161 Standard checked mode would print `"a string"` without error.
162
163 ## Is / As restrictions
164
165 In standard Dart, `is` and `as` runtime checks expose the unsoundness of the typ e system in certain cases. For example, consider:
166
167 ```dart
168 var list = ["hello", "world"];
169 if (list is List<int>) {
170 ...
171 } else if (list is List<String>) {
172 ...
173 }
174 ```
175
176 Perhaps surprisingly, the first test - `list is List<int>` - evaluates to true h ere. Such code is highly likely to be erroneous.
177
178 Strong mode provides a stricter subtyping check and DDC enforces this at runtime . For compatibility with standard Dart semantics, however, DDC throws a runtime error when an `is` or `as` check would return a different answer with strong mo de typing semantics.
179
180 In the example above, the first `is` check would generate a runtime error.
181
182 Note, we are exploring making this a static error or warning in strong mode. In general, an expression:
183
184 ```dart
185 x is T
186 ```
187
188 or
189
190 ```dart
191 x as T
192 ```
193
194 is only guaranteed safe when `T` is a *ground type*:
195
196 - A non-generic class type (e.g., `Object`, `String`, `int`, ...).
197 - A generic class type where all type parameters are implicitly or explicitly `d ynamic` (e.g., `List<dynamic>`, `Map`, …).
198 - A function type where the return type and all parameter types are `dynamic` (e .g., (`dynamic`, `dynamic`) -> `dynamic`, ([`dynamic`]) -> `dynamic`).
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698