|
| 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