diff --git a/examples/analysis/analysis_options.yaml b/examples/analysis/analysis_options.yaml index 33ee748b39..9a58b29fbe 100644 --- a/examples/analysis/analysis_options.yaml +++ b/examples/analysis/analysis_options.yaml @@ -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 diff --git a/examples/analysis/analyzer-results-beta.txt b/examples/analysis/analyzer-results-beta.txt index 6405ab4a76..ee71ad254e 100644 --- a/examples/analysis/analyzer-results-beta.txt +++ b/examples/analysis/analyzer-results-beta.txt @@ -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:13:7 - The argument type 'dynamic' can't be assigned to the parameter type 'List'. - argument_type_not_assignable 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:22:27 - The type argument(s) of 'Map' can't be inferred. Use explicit type argument(s) for 'Map'. - inference_failure_on_collection_literal + info - lib/strict_modes.dart:33:3 - The generic type 'List' should have explicit type arguments but doesn't. Use explicit type arguments for 'List'. - strict_raw_type -3 issues found. +5 issues found. diff --git a/examples/analysis/analyzer-results-dev.txt b/examples/analysis/analyzer-results-dev.txt index 6405ab4a76..ee566eeba6 100644 --- a/examples/analysis/analyzer-results-dev.txt +++ b/examples/analysis/analyzer-results-dev.txt @@ -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:13:7 - The argument type 'dynamic' can't be assigned to the parameter type 'List'. - argument_type_not_assignable 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:22:17 - The type argument(s) of 'Map' can't be inferred. Use explicit type argument(s) for 'Map'. - inference_failure_on_collection_literal + info - lib/strict_modes.dart:33:3 - The generic type 'List' should have explicit type arguments but doesn't. Use explicit type arguments for 'List'. - strict_raw_type -3 issues found. +5 issues found. diff --git a/examples/analysis/analyzer-results-stable.txt b/examples/analysis/analyzer-results-stable.txt index 6405ab4a76..ee566eeba6 100644 --- a/examples/analysis/analyzer-results-stable.txt +++ b/examples/analysis/analyzer-results-stable.txt @@ -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:13:7 - The argument type 'dynamic' can't be assigned to the parameter type 'List'. - argument_type_not_assignable 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:22:17 - The type argument(s) of 'Map' can't be inferred. Use explicit type argument(s) for 'Map'. - inference_failure_on_collection_literal + info - lib/strict_modes.dart:33:3 - The generic type 'List' should have explicit type arguments but doesn't. Use explicit type arguments for 'List'. - strict_raw_type -3 issues found. +5 issues found. diff --git a/examples/analysis/lib/assignment.dart b/examples/analysis/lib/assignment.dart index 356762755f..58c076cb45 100644 --- a/examples/analysis/lib/assignment.dart +++ b/examples/analysis/lib/assignment.dart @@ -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(); - // 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 diff --git a/examples/analysis/lib/strict_modes.dart b/examples/analysis/lib/strict_modes.dart new file mode 100644 index 0000000000..aa1dcf7802 --- /dev/null +++ b/examples/analysis/lib/strict_modes.dart @@ -0,0 +1,38 @@ +// ignore_for_file: dead_code, prefer_typing_uninitialized_variables, +// ignore_for_file: unused_local_variable + +import 'dart:convert'; + +import 'package:examples_util/ellipsis.dart'; + +// #docregion strict-casts +void foo(List lines) { + ellipsis(); +} + +void bar(String jsonText) { + // ignore: stable, beta, dev, argument_type_not_assignable + foo(jsonDecode(jsonText)); // Implicit cast +} +// #enddocregion strict-casts + +void strictInference() { + // #docregion strict-inference + // ignore: stable, beta, dev, inference_failure_on_collection_literal + final lines = {}; // Inference failure + lines['Dart'] = 10000; + lines['C++'] = 'one thousand'; + lines['Go'] = 2000; + print('Lines: ${lines.values.reduce((a, b) => a + b)}'); // Runtime error + // #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 +} diff --git a/examples/analysis/pubspec.yaml b/examples/analysis/pubspec.yaml index cc839dd43c..966dc6cd51 100644 --- a/examples/analysis/pubspec.yaml +++ b/examples/analysis/pubspec.yaml @@ -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} diff --git a/src/_guides/language/analysis-options.md b/src/_guides/language/analysis-options.md index c9b5a059fc..5c15f34008 100644 --- a/src/_guides/language/analysis-options.md +++ b/src/_guides/language/analysis-options.md @@ -162,54 +162,113 @@ 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: - + ```yaml analyzer: - strong-mode: - implicit-casts: false - implicit-dynamic: false + language: + strict-casts: true + strict-inference: true + strict-raw-types: 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: ` -: A value of `false` ensures that the type inference engine never +`strict-casts: ` +: 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: + The following valid Dart code includes an implicit downcast from the + `dynamic` value returned by `jsonDecode` to `List` + that could fail at runtime. + This mode reports the potential error, + requiring you to add an explicit cast or otherwise adjust your code. {:.fails-sa} - + {% prettify dart class="analyzer" %} -dynamic o = ... -String s = [!o!]; // Implicit downcast -String s2 = s.substring(1); +void foo(List lines) { + ... +} + +void bar(String jsonText) { + foo([!jsonDecode(jsonText)!]); // Implicit cast +} {% endprettify %} {:.console-output} - + ```nocode -error - A value of type 'dynamic' can't be assigned to a variable of type 'String' - invalid_assignment +error - The argument type 'dynamic' can't be assigned to the parameter type 'List'. - argument_type_not_assignable ``` {{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: ` -: A value of `false` ensures that the type inference engine never chooses +`strict-inference: ` +: 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 creates a `Map` + whose type argument cannot be inferred, + resulting in an inference failure hint by this mode: -{% comment %} -TODO: Clarify that description, and insert an example here. -{% endcomment %} +{:.fails-sa} + +{% prettify dart class="analyzer" %} +final lines = [!{}!]; // Inference failure +lines['Dart'] = 10000; +lines['C++'] = 'one thousand'; +lines['Go'] = 2000; +print('Lines: ${lines.values.reduce((a, b) => a + b)}'); // Runtime error +{% endprettify %} + +{:.console-output} + +```nocode +info - The type argument(s) of 'Map' can't be inferred - inference_failure_on_collection_literal +``` +{{site.alert.info}} + The `strict-inference` mode can identify many situations + which result in an inference failure. + + See [Conditions for strict inference failure][] + for an exhaustive list of inference failure conditions. +{{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: ` +: 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} + +{% 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} +'. / /g; /-(.*?):(.*?):(.*?)-/-/g"?> +```nocode +info - The generic type 'List' should have explicit type arguments but doesn't - strict_raw_type +``` ## Enabling and disabling linter rules {#enabling-linter-rules}