Skip to content

Commit

Permalink
Introduce documentation for new strict modes
Browse files Browse the repository at this point in the history
  • Loading branch information
parlough committed Feb 9, 2022
1 parent b307a77 commit 3297e9d
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 42 deletions.
7 changes: 4 additions & 3 deletions examples/analysis/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ include: ../analysis_options.yaml

analyzer:
exclude: [build/**]
strong-mode:
implicit-casts: false
implicit-dynamic: false
language:
strict-casts: true
strict-inference: true
strict-raw-types: true
6 changes: 4 additions & 2 deletions examples/analysis/analyzer-results-beta.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
Analyzing analysis...

error - lib/assignment.dart:11:14 - A value of type 'dynamic' can't be assigned to a variable of type 'String'. Try changing the type of the variable, or casting the right-hand type to 'String'. - invalid_assignment
error - lib/strict_modes.dart:9:14 - A value of type 'dynamic' can't be assigned to a variable of type 'String'. Try changing the type of the variable, or casting the right-hand type to 'String'. - invalid_assignment
info - lib/lint.dart:9:19 - Avoid empty statements. - empty_statements
info - lib/lint.dart:17:7 - Close instances of `dart.core.Sink`. - close_sinks
info - lib/strict_modes.dart:18:7 - The type of dynamicValue can't be inferred without either a type or initializer. Try specifying the type of the variable. - inference_failure_on_uninitialized_variable
info - lib/strict_modes.dart:27:3 - The generic type 'List<dynamic>' should have explicit type arguments but doesn't. Use explicit type arguments for 'List<dynamic>'. - strict_raw_type

3 issues found.
5 issues found.
6 changes: 4 additions & 2 deletions examples/analysis/analyzer-results-dev.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
Analyzing analysis...

error - lib/assignment.dart:11:14 - A value of type 'dynamic' can't be assigned to a variable of type 'String'. Try changing the type of the variable, or casting the right-hand type to 'String'. - invalid_assignment
error - lib/strict_modes.dart:9:14 - A value of type 'dynamic' can't be assigned to a variable of type 'String'. Try changing the type of the variable, or casting the right-hand type to 'String'. - invalid_assignment
info - lib/lint.dart:9:19 - Avoid empty statements. - empty_statements
info - lib/lint.dart:17:7 - Close instances of `dart.core.Sink`. - close_sinks
info - lib/strict_modes.dart:18:7 - The type of dynamicValue can't be inferred without either a type or initializer. Try specifying the type of the variable. - inference_failure_on_uninitialized_variable
info - lib/strict_modes.dart:27:3 - The generic type 'List<dynamic>' should have explicit type arguments but doesn't. Use explicit type arguments for 'List<dynamic>'. - strict_raw_type

3 issues found.
5 issues found.
6 changes: 4 additions & 2 deletions examples/analysis/analyzer-results-stable.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
Analyzing analysis...

error - lib/assignment.dart:11:14 - A value of type 'dynamic' can't be assigned to a variable of type 'String'. Try changing the type of the variable, or casting the right-hand type to 'String'. - invalid_assignment
error - lib/strict_modes.dart:9:14 - A value of type 'dynamic' can't be assigned to a variable of type 'String'. Try changing the type of the variable, or casting the right-hand type to 'String'. - invalid_assignment
info - lib/lint.dart:9:19 - Avoid empty statements. - empty_statements
info - lib/lint.dart:17:7 - Close instances of `dart.core.Sink`. - close_sinks
info - lib/strict_modes.dart:18:7 - The type of dynamicValue can't be inferred without either a type or initializer. Try specifying the type of the variable. - inference_failure_on_uninitialized_variable
info - lib/strict_modes.dart:27:3 - The generic type 'List<dynamic>' should have explicit type arguments but doesn't. Use explicit type arguments for 'List<dynamic>'. - strict_raw_type

3 issues found.
5 issues found.
12 changes: 0 additions & 12 deletions examples/analysis/lib/assignment.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,6 @@
// ignore_for_file: unused_local_variable, duplicate_ignore, dead_code
// #enddocregion ignore_for_file

import 'package:examples_util/ellipsis.dart';

String downcastExample() {
// #docregion implicit-downcast
dynamic o = ellipsis<String>();
// ignore: stable, beta, dev, invalid_assignment
String s = o; // Implicit downcast
String s2 = s.substring(1);
// #enddocregion implicit-downcast
return s2;
}

void assignment0() {
// #docregion single-line
int x = ''; // ignore: invalid_assignment
Expand Down
32 changes: 32 additions & 0 deletions examples/analysis/lib/strict_modes.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// ignore_for_file: dead_code, prefer_typing_uninitialized_variables

import 'package:examples_util/ellipsis.dart';

String strictCasts() {
// #docregion strict-casts
dynamic o = ellipsis<String>();
// ignore: stable, beta, dev, invalid_assignment
String s = o; // Implicit downcast
String s2 = s.substring(1);
// #enddocregion strict-casts
return s2;
}

void strictInference() {
// #docregion strict-inference
// ignore: stable, beta, dev, inference_failure_on_uninitialized_variable
var dynamicValue;
dynamicValue.add(1);
dynamicValue.add(2);
// #enddocregion strict-inference
}

void strictRawTypes() {
// #docregion strict-raw-types
// ignore: stable, beta, dev, strict_raw_type
List numbers = [1, 2, 3]; // List with raw type
for (final n in numbers) {
print(n.length); // Runtime error
}
// #enddocregion strict-raw-types
}
2 changes: 1 addition & 1 deletion examples/analysis/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: examples
description: dart.dev example code.

environment:
sdk: '>=2.15.0 <3.0.0'
sdk: '>=2.16.0 <3.0.0'

dev_dependencies:
examples_util: {path: ../util}
Expand Down
88 changes: 68 additions & 20 deletions src/_guides/language/analysis-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,26 +162,26 @@ and `my_other_other_package`, and file #2 to analyze the code in

If you want stricter static checks than
the [Dart type system][type-system] requires,
consider using the `implicit-casts` and `implicit-dynamic` flags:
consider enabling the
`strict-casts`, `strict-inference`, and `strict-raw-types` language modes:

<?code-excerpt "analysis/analysis_options.yaml" from="analyzer" to="implicit-dynamic" remove="exclude"?>
<?code-excerpt "analysis/analysis_options.yaml" from="analyzer" to="strict-casts" remove="exclude"?>
```yaml
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
language:
strict-casts: true
```

You can use the flags together or separately; both default to `true`.
You can use the modes together or separately; all default to `false`.

`implicit-casts: <bool>`
: A value of `false` ensures that the type inference engine never
`strict-casts: <bool>`
: A value of `true` ensures that the type inference engine never
implicitly casts from `dynamic` to a more specific type.
The following valid Dart code
includes an implicit downcast that would be caught by this flag:
includes an implicit downcast that would be caught by this mode:

{:.fails-sa}
<?code-excerpt "analysis/lib/assignment.dart (implicit-downcast)" replace="/(s = )(o)/$1[!$2!]/g"?>
<?code-excerpt "analysis/lib/strict_modes.dart (strict-casts)" replace="/(s = )(o)/$1[!$2!]/g"?>
{% prettify dart class="analyzer" %}
dynamic o = ...
String s = [!o!]; // Implicit downcast
Expand All @@ -195,21 +195,69 @@ error - A value of type 'dynamic' can't be assigned to a variable of type 'Strin
```

{{site.alert.version-note}}
In packages that use a [language version][] before 2.12
(when support for [null safety](/null-safety) was introduced),
code can implicitly downcast from non-`dynamic` types such as `Object`.
The `implicit-casts` flag can catch those non-`dynamic` downcasts,
even if you're using a more recent Dart SDK.
The `strict-casts` mode was introduced in Dart 2.16.
To enable similar checks with earlier SDK releases,
consider using the now deprecated `implicit-casts` option:

```yaml
analyzer:
strong-mode:
implicit-casts: false
```
{{site.alert.end}}

`implicit-dynamic: <bool>`
: A value of `false` ensures that the type inference engine never chooses
`strict-inference: <bool>`
: A value of `true` ensures that the type inference engine never chooses
the `dynamic` type when it can't determine a static type.
The following valid Dart code has an expression
that fails to evaluate to a static type,
resulting in an inference failure hint by this mode:

{:.fails-sa}
<?code-excerpt "analysis/lib/strict_modes.dart (strict-inference)" replace="/var dynamicValue/var [!dynamicValue!]/g"?>
{% prettify dart class="analyzer" %}
var [!dynamicValue!];
dynamicValue.add(1);
dynamicValue.add(2);
{% endprettify %}

{:.console-output}
<?code-excerpt "analysis/analyzer-results-stable.txt" retain="dynamicValue can't be inferred" replace="/. Try.*variable. / /g; /-(.*?):(.*?):(.*?)-/-/g"?>
```nocode
info - The type of dynamicValue can't be inferred without either a type or initializer - inference_failure_on_uninitialized_variable
```

{% comment %}
TODO: Clarify that description, and insert an example here.
{% endcomment %}
{{site.alert.info}}
The `strict-inference` mode identifies many conditions
which result in an inference failure.

See [Conditions for strict inference failure][]
for an extensive set of examples highlighting inference failures.
{{site.alert.end}}

[Conditions for strict inference failure]: https://github.com/dart-lang/language/blob/master/resources/type-system/strict-inference.md#conditions-for-strict-inference-failure

`strict-raw-types: <bool>`
: A value of `true` ensures that the type inference engine never chooses
the `dynamic` type when it can't determine a static type
due to omitted type arguments.
The following valid Dart code has a `List` variable with a raw type,
resulting in a raw type hint by this mode:

{:.fails-sa}
<?code-excerpt "analysis/lib/strict_modes.dart (strict-raw-types)" replace="/List n/[!List!] n/g"?>
{% prettify dart class="analyzer" %}
[!List!] numbers = [1, 2, 3]; // List with raw type
for (final n in numbers) {
print(n.length); // Runtime error
}
{% endprettify %}

{:.console-output}
<?code-excerpt "analysis/analyzer-results-stable.txt" retain="The generic type" replace="/. Use explicit.*'List<dynamic>'. / /g; /-(.*?):(.*?):(.*?)-/-/g"?>
```nocode
info - The generic type 'List<dynamic>' should have explicit type arguments but doesn't - strict_raw_type
```

## Enabling and disabling linter rules {#enabling-linter-rules}

Expand Down

0 comments on commit 3297e9d

Please sign in to comment.