Skip to content

Commit 2100ca1

Browse files
authored
Document new strict-casts mode (#2019)
1 parent 85e4ec0 commit 2100ca1

File tree

1 file changed

+95
-0
lines changed

1 file changed

+95
-0
lines changed

resources/type-system/strict-casts.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Strict casts static analysis option
2+
3+
This document specifies the "Strict casts" mode enabled with a static
4+
analysis option, new in Dart 2.16. As a static analysis option, we only intend
5+
to implement this feature in the Dart Analyzer. Under this feature, any
6+
implicit cast is reported as an analyzer "Hint" (a warning).
7+
8+
Note that under the null safe type system, the only expressions which may be
9+
implicitly cast are those with a static type of `dynamic`. These are exactly
10+
the implicit casts reported in the strict casts mode.
11+
12+
## Enabling strict casts
13+
14+
To enable strict casts, set the `strict-casts` option to `true`, under
15+
the Analyzer's `language` section:
16+
17+
```yaml
18+
analyzer:
19+
language:
20+
strict-casts: true
21+
```
22+
23+
## Motivation
24+
25+
Static analysis can provide many benefits which require meaningful static
26+
types. For example, when a value of one type is _not assignable_ to a variable
27+
of another type, the error is reported by static analysis. However, when a
28+
value has a static type of `dynamic`, no error is reported. Such a value is
29+
always assignable, because a cast is implicitly inserted at runtime, which may
30+
fail. For example:
31+
32+
```dart
33+
import 'dart:convert';
34+
void main() {
35+
var decoded = jsonDecode(/* some JSON */);
36+
if (decoded['foo']) {
37+
print('Got foo.');
38+
}
39+
}
40+
```
41+
42+
The expression used in an if-statement's condition must have a static type of
43+
`bool`. Without the strict casts mode, an expression with a static type of
44+
`dynamic` (such as the example's `decoded['foo']`) is allowed, due to the
45+
implicit cast to `bool` which will occur at runtime. The strict casts mode aims
46+
to warn about such code during static analysis.
47+
48+
Note that another way to root out implicit casts from the `dynamic` type is to
49+
ban all use of the `dynamic` type. However, there are many common APIs which
50+
return `dynamic`-typed values, such as the `dart:convert` library's
51+
JSON-decoding functions (referenced in the example above). The strict casts
52+
mode allows the use of such APIs, requiring only that such `dynamic`-typed
53+
values are _explicitly_ cast before using them in a position where a value of
54+
non-`dynamic` type is expected.
55+
56+
## Differences from "no implicit casts" mode
57+
58+
The strict casts mode is very similar to another static analysis mode supported
59+
by the Dart analyzer: "no implicit casts," now deprecated in favor of the
60+
strict casts mode. The new mode reports all of the same implicit casts which
61+
the "no implicit casts" mode does, and it also reports three more cases,
62+
detailed below.
63+
64+
### for-in loop iteration
65+
66+
A value with a static type of `dynamic` which is used as the iterator
67+
expression in a for-in loop is reported. For example:
68+
69+
```dart
70+
void foo(dynamic arg) {
71+
for (var value in arg) { /* ... */ }
72+
}
73+
```
74+
75+
### spread expression
76+
77+
A value with a static type of `dynamic` which is used as the expression in a
78+
spread is reported. For example:
79+
80+
```dart
81+
void foo(dynamic arg) {
82+
[...arg];
83+
}
84+
```
85+
86+
### yield-each expression
87+
88+
A value with a static type of `dynamic` which is used as the expression in a
89+
yield-each expression is reported. For example:
90+
91+
```dart
92+
Stream<int> foo(dynamic arg) async* {
93+
yield* arg;
94+
}
95+
```

0 commit comments

Comments
 (0)