diff --git a/examples/type_system/analyzer-results-beta.txt b/examples/type_system/analyzer-results-beta.txt index 72e831a4a0..9cbee8d14b 100644 --- a/examples/type_system/analyzer-results-beta.txt +++ b/examples/type_system/analyzer-results-beta.txt @@ -17,6 +17,5 @@ Analyzing type_system... error - lib/strong_analysis.dart:109:23 - A value of type 'String' can't be assigned to a variable of type 'double'. Try changing the type of the variable, or casting the right-hand type to 'double'. - invalid_assignment error - lib/strong_analysis.dart:121:19 - A value of type 'Cat' can't be assigned to a variable of type 'MaineCoon'. Try changing the type of the variable, or casting the right-hand type to 'MaineCoon'. - invalid_assignment error - lib/strong_analysis.dart:148:24 - A value of type 'List' can't be assigned to a variable of type 'List'. Try changing the type of the variable, or casting the right-hand type to 'List'. - invalid_assignment - error - test/strong_test.dart:120:26 - A value of type 'dynamic' can't be assigned to a variable of type 'List'. Try changing the type of the variable, or casting the right-hand type to 'List'. - invalid_assignment -16 issues found. \ No newline at end of file +15 issues found. diff --git a/examples/type_system/analyzer-results-dev.txt b/examples/type_system/analyzer-results-dev.txt index 72e831a4a0..9cbee8d14b 100644 --- a/examples/type_system/analyzer-results-dev.txt +++ b/examples/type_system/analyzer-results-dev.txt @@ -17,6 +17,5 @@ Analyzing type_system... error - lib/strong_analysis.dart:109:23 - A value of type 'String' can't be assigned to a variable of type 'double'. Try changing the type of the variable, or casting the right-hand type to 'double'. - invalid_assignment error - lib/strong_analysis.dart:121:19 - A value of type 'Cat' can't be assigned to a variable of type 'MaineCoon'. Try changing the type of the variable, or casting the right-hand type to 'MaineCoon'. - invalid_assignment error - lib/strong_analysis.dart:148:24 - A value of type 'List' can't be assigned to a variable of type 'List'. Try changing the type of the variable, or casting the right-hand type to 'List'. - invalid_assignment - error - test/strong_test.dart:120:26 - A value of type 'dynamic' can't be assigned to a variable of type 'List'. Try changing the type of the variable, or casting the right-hand type to 'List'. - invalid_assignment -16 issues found. \ No newline at end of file +15 issues found. diff --git a/examples/type_system/analyzer-results-stable.txt b/examples/type_system/analyzer-results-stable.txt index 4b7c4f348c..c4536e02d6 100644 --- a/examples/type_system/analyzer-results-stable.txt +++ b/examples/type_system/analyzer-results-stable.txt @@ -17,6 +17,5 @@ Analyzing type_system... error - lib/strong_analysis.dart:109:23 - A value of type 'String' can't be assigned to a variable of type 'double'. Try changing the type of the variable, or casting the right-hand type to 'double'. - invalid_assignment error - lib/strong_analysis.dart:121:19 - A value of type 'Cat' can't be assigned to a variable of type 'MaineCoon'. Try changing the type of the variable, or casting the right-hand type to 'MaineCoon'. - invalid_assignment error - lib/strong_analysis.dart:148:24 - A value of type 'List' can't be assigned to a variable of type 'List'. Try changing the type of the variable, or casting the right-hand type to 'List'. - invalid_assignment - error - test/strong_test.dart:120:26 - A value of type 'dynamic' can't be assigned to a variable of type 'List'. Try changing the type of the variable, or casting the right-hand type to 'List'. - invalid_assignment -16 issues found. +15 issues found. diff --git a/examples/type_system/test/strong_test.dart b/examples/type_system/test/strong_test.dart index ea5a1650af..ce155d7cc9 100644 --- a/examples/type_system/test/strong_test.dart +++ b/examples/type_system/test/strong_test.dart @@ -1,8 +1,7 @@ -// ignore_for_file: unused_local_variable, strict_raw_type +// ignore_for_file: unused_local_variable import 'package:test/test.dart'; import 'package:type_system_examples/animal.dart'; -import 'package:type_system_examples/bounded/my_collection.dart'; Matcher _throwsA(String msg) => throwsA( allOf(TypeMatcher(), predicate((e) => e.toString().contains(msg))), @@ -36,92 +35,5 @@ void main() { const msg = "type 'List' is not a subtype of type 'List'"; expect(main, _throwsA(msg)); }); - - test('downcast check fails', () { - void downcastCheck() { - // #docregion fail-downcast-check - assumeStrings([1, 2, 3]); - // #enddocregion fail-downcast-check - } - - // #docregion downcast-check-msg - const msg = "type 'List' is not a subtype of type 'List'"; - // #enddocregion downcast-check-msg - expect(downcastCheck, _throwsA(msg)); - }); - - final expectedOutput = 'a string\n'; - - test('downcast check ok for []', () { - void downcastCheck() { - // #docregion typed-list-lit - var list = []; - list.add('a string'); - list.add('another'); - assumeStrings(list); - // #enddocregion typed-list-lit - } - - expect(downcastCheck, prints(expectedOutput)); - }); - - test('downcast check ok for List', () { - void downcastCheck() { - // #docregion typed-list - List list = []; - list.add('a string'); - list.add('another'); - assumeStrings(list); - // #enddocregion typed-list - } - - expect(downcastCheck, prints(expectedOutput)); - }); - - Map fetchFromExternalSource() => { - 'names': ['a string'], - }; - - test('downcast check ok: use cast()', () { - void downcastCheck() { - // #docregion cast - Map json = fetchFromExternalSource(); - var names = json['names'] as List; - assumeStrings(names.cast()); - // #enddocregion cast - } - - expect(downcastCheck, prints(expectedOutput)); - }); - - test('instantiate-to-bound sanity', () { - final b = B(); - expect(b.typeOfS, 'int'); - expect(b.typeOfT, 'dynamic'); - }); - - test('instantiate-to-bound fix: add type arg', () { - // #docregion add-type-arg - var c = C([]).collection; - c.add(2); - // #enddocregion add-type-arg - expect(c, [2]); - }); }); } - -// #docregion downcast-check -void assumeStrings(dynamic objects) { - // ignore: stable, beta, dev, invalid_assignment - List strings = objects; // Runtime downcast check - String string = strings[0]; // Expect a String value - // #enddocregion downcast-check - print(string); - // #docregion downcast-check -} -// #enddocregion downcast-check - -class B { - String get typeOfS => '$S'; - String get typeOfT => '$T'; -} diff --git a/firebase.json b/firebase.json index 0e5a2164c4..7e9b03833c 100644 --- a/firebase.json +++ b/firebase.json @@ -116,6 +116,7 @@ { "source": "/dart-vm{,/**}", "destination": "/server", "type": 301 }, { "source": "/dart2js-reflection", "destination": "https://github.com/dart-lang/sdk/issues/21654", "type": 301 }, { "source": "/dartium{,/**}", "destination": "/tools#editors", "type": 301 }, + { "source": "/deprecated/sound-problems", "destination": "/language/type-system", "type": 301 }, { "source": "/devices", "destination": "/overview#platform", "type": 301 }, { "source": "/dev{,/**}", "destination": "https://api.dart.dev/dev", "type": 301 }, { "source": "/diagnostics", "destination": "/tools/diagnostic-messages", "type": 301 }, @@ -217,7 +218,7 @@ { "source": "/guides/language/cheatsheet", "destination": "/language", "type": 301 }, { "source": "/guides/language/coming-from/js-to-dart", "destination": "/resources/coming-from/js-to-dart", "type": 301 }, { "source": "/guides/language/coming-from/swift-to-dart", "destination": "/resources/coming-from/swift-to-dart", "type": 301 }, - { "source": "/guides/language/common-prob", "destination": "/deprecated/sound-problems", "type": 301 }, + { "source": "/guides/language/common-prob", "destination": "/language/type-system", "type": 301 }, { "source": "/guides/language/concurrency", "destination": "/language/concurrency", "type": 301 }, { "source": "/guides/language/effective-dart", "destination": "/effective-dart", "type": 301 }, { "source": "/guides/language/effective-dart/:page*", "destination": "/effective-dart/:page*", "type": 301 }, @@ -229,7 +230,7 @@ { "source": "/guides/language/numbers", "destination": "/resources/language/number-representation", "type": 301 }, { "source": "/guides/language/sound-dart", "destination": "/language/type-system", "type": 301 }, { "source": "/guides/language/sound-faq", "destination": "/language/type-system", "type": 301 }, - { "source": "/guides/language/sound-problems", "destination": "/deprecated/sound-problems", "type": 301 }, + { "source": "/guides/language/sound-problems", "destination": "/language/type-system", "type": 301 }, { "source": "/guides/language/spec", "destination": "/resources/language/spec", "type": 301 }, { "source": "/guides/language/specifications", "destination": "/resources/language/spec", "type": 301 }, { "source": "/guides/language/specifications/:page*", "destination": "/resources/language/spec/versions/:page*", "type": 301 }, diff --git a/src/_data/sidenav.yml b/src/_data/sidenav.yml index 168b0181e9..e9ef0ee4ec 100644 --- a/src/_data/sidenav.yml +++ b/src/_data/sidenav.yml @@ -317,8 +317,6 @@ children: - title: Customizing static analysis permalink: /tools/analysis - - title: Fixing common type problems - permalink: /deprecated/sound-problems - title: Fixing type promotion failures permalink: /tools/non-promotion-reasons - title: Linter rules diff --git a/src/content/deprecated/sound-problems.md b/src/content/deprecated/sound-problems.md deleted file mode 100644 index 4b97ffd354..0000000000 --- a/src/content/deprecated/sound-problems.md +++ /dev/null @@ -1,622 +0,0 @@ ---- -title: Fixing common type problems -description: Common type issues you may have and how to fix them. ---- - - - - -If you're having problems with type checks, -this page can help. To learn more, read about -[Dart's type system](/language/type-system), -and see [these other resources](/language/type-system#other-resources). - -:::note Help us improve this page! -If you encounter a warning or error that isn't -listed here, please file an issue by clicking the **bug icon** at the top -right. Include the **warning or error message** and, if possible, the code for -both a small reproducible case and its correct equivalent. -::: - -## Troubleshooting - -Dart enforces a sound type system. -This means you can't write code where a -variable's value differs from its static type. -A variable with an `int` type can't store a number with a decimal place. -Dart checks variable values against their types at -[compile-time](#static-errors-and-warnings) and [runtime](#runtime-errors). - -You can't get into a situation where the value stored in a variable is -different from the variable's static type. Like most modern statically -typed languages, Dart accomplishes this with a combination of -[static (compile-time)](#static-errors-and-warnings) and [dynamic (runtime)](#runtime-errors) checking. - -For example, the following type error is detected at compile-time: - -```dart tag=fails-sa -List numbers = [1, 2, 3]; -List [!string = numbers!]; -``` - -Since neither `List` nor `List` is a subtype of the other, -Dart rules this out statically. - -You can see other examples of static analysis errors, -as well as other error types, in the following sections. - - -## No type errors {:#no-type-errors} - -If you're not seeing expected errors or warnings, -make sure that you're using the latest version of Dart -and you have properly configured your [IDE or editor](/tools#editors). - -You can also run analysis on your program using the command line -with the [`dart analyze`](/tools/dart-analyze) command. - -To verify that analysis is working as expected, -try adding the following code to a Dart file. - - -```dart tag=fails-sa -bool b = [0][0]; -``` - -If properly configured, the analyzer produces the following error: - - -```plaintext -error - A value of type 'int' can't be assigned to a variable of type 'bool'. Try changing the type of the variable, or casting the right-hand type to 'bool'. - invalid_assignment -``` - - -## Static errors and warnings - -This section shows how to fix some of the errors and warnings -you might see from the analyzer or an IDE. - -Static analysis can't catch all errors. -For help fixing errors that appear only at runtime, -see [Runtime errors](#common-errors-and-warnings). - -### Undefined member - - -```plaintext -error - The '...' isn't defined for the type '...' - undefined_ -``` - -These errors can appear under the following conditions: - -- A variable is statically known to be some supertype, but the code assumes a subtype. -- A generic class has a bounded type parameter, but an instance creation - expression of the class omits the type argument. - -#### Example 1: A variable is statically known to be some supertype, but the code assumes a subtype - -In the following code, the analyzer complains that `context2D` is undefined: - - -```dart tag=fails-sa -var canvas = document.querySelector('canvas')!; -canvas.[!context2D!].lineTo(x, y); -``` - - -```plaintext -error - The getter 'context2D' isn't defined for the type 'Element'. Try importing the library that defines 'context2D', correcting the name to the name of an existing getter, or defining a getter or field named 'context2D'. - undefined_getter -``` - -#### Fix: Replace the definition of the member with an explicit type declaration or a downcast - -The return type of `querySelector()` is `Element?` -(which the `!` converts to `Element`), -but the code assumes that it's the subtype `CanvasElement` -(which defines `context2D`). -The `canvas` field is declared as `var`, -which allows Dart to infer `canvas` to be an `Element`. - -You can fix this error with an explicit downcast: - - -```dart tag=passes-sa -var canvas = document.querySelector('canvas') [!as HTMLCanvasElement!]; -canvas.context2D.lineTo(x, y); -``` - -Otherwise, use `dynamic` in situations where you can't use a single type: - - -```dart tag=passes-sa -var canvasOrImg = document.querySelector('canvas, img') as [!dynamic!]; -var width = canvasOrImg.width; -``` - -#### Example 2: Omitted type parameters default to their type bounds - -Consider the following **generic class** with a **bounded type parameter** -that extends `Iterable`: - - -```dart -class C { - final T collection; - C(this.collection); -} -``` - -The following code creates a new instance of this class -(omitting the type argument) and accesses its `collection` member: - - -```dart tag=fails-sa -var c = C(Iterable.empty()).collection; -[!c.add(2)!]; -``` - - -```plaintext -error - The method 'add' isn't defined for the type 'Iterable'. Try correcting the name to the name of an existing method, or defining a method named 'add'. - undefined_method -``` - -While the [List][] type has an `add()` method, [Iterable][] does not. - -#### Fix: Specify type arguments or fix downstream errors - -When a generic class is instantiated without explicit type arguments, -each type parameter defaults to its type bound (`Iterable` in this example) if -one is explicitly given, or `dynamic` otherwise. - -You need to approach fixing such errors on a case-by-case basis. It helps to -have a good understanding of the original design intent. - -Explicitly passing type arguments is an effective way to help identify type -errors. For example, if you change the code to specify `List` as a type -argument, the analyzer can detect the type mismatch in the constructor argument. -Fix the error by providing a constructor argument of the appropriate type, -such as a list literal: - - -```dart tag=passes-sa -var c = C[!!]([![]!]).collection; -c.add(2); -``` - -
- -### Invalid method override - - -```plaintext -error - '...' isn't a valid override of '...' - invalid_override -``` - -These errors typically occur when a subclass tightens up a method's -parameter types by specifying a subclass of the original class. - -:::note -This issue can also occur when a generic subclass neglects to specify a type. -For more information, see [Missing type arguments](#missing-type-arguments). -::: - -#### Example - -In the following example, the parameters to the `add()` method are of type `int`, -a subtype of `num`, which is the parameter type used in the parent class. - - -```dart tag=fails-sa -abstract class NumberAdder { - num add(num a, num b); -} - -class MyAdder extends NumberAdder { - @override - num add([!int!] a, [!int!] b) => a + b; -} -``` - - -```plaintext -error - 'MyAdder.add' ('num Function(int, int)') isn't a valid override of 'NumberAdder.add' ('num Function(num, num)'). - invalid_override -``` - -Consider the following scenario where floating -point values are passed to an `MyAdder`: - - -```dart tag=runtime-fail -NumberAdder adder = MyAdder(); -adder.add([!1.2!], [!3.4!]); -``` - -If the override were allowed, the code would raise an error at runtime. - -#### Fix: Widen the method's parameter types - -The subclass's method should accept every -object that the superclass's method takes. - -Fix the example by widening the types in the subclass: - - -```dart tag=passes-sa -abstract class NumberAdder { - num add(num a, num b); -} - -class MyAdder extends NumberAdder { - @override - num add([!num!] a, [!num!] b) => a + b; -} -``` - -For more information, see -[Use proper input parameter types when overriding methods](/language/type-system#use-proper-param-types). - -:::note -If you have a valid reason to use a subtype, you can use the -[covariant keyword](/language/type-system#covariant-keyword). -::: - -
- -### Missing type arguments - - -```plaintext -error - '...' isn't a valid override of '...' - invalid_override -``` - -#### Example - -In the following example, `Subclass` extends `Superclass` but doesn't -specify a type argument. The analyzer infers `Subclass`, -which results in an invalid override error on `method(int)`. - - -```dart tag=fails-sa -class Superclass { - void method(T param) { - ... - } -} - -class Subclass extends Superclass { - @override - void method([!int!] param) { - ... - } -} -``` - - -```plaintext -error - 'Subclass.method' ('void Function(int)') isn't a valid override of 'Superclass.method' ('void Function(dynamic)'). - invalid_override -``` - -#### Fix: Specify type arguments for the generic subclass - -When a generic subclass neglects to specify a type argument, -the analyzer infers the `dynamic` type. This is likely to cause -errors. - -You can fix the example by specifying the type on the subclass: - - -```dart tag=passes-sa -class Superclass { - void method(T param) { - ... - } -} - -class Subclass extends Superclass[!!] { - @override - void method(int param) { - ... - } -} -``` - -Consider using the analyzer in _strict raw types_ mode, -which ensures that your code specifies generic type arguments. -Here's an example of enabling strict raw types in -your project's `analysis_options.yaml` file: - -```yaml -analyzer: - language: - strict-raw-types: true -``` - -To learn more about customizing the analyzer's behavior, -see [Customizing static analysis](/tools/analysis). - -
- - -### Unexpected collection element type - - -```plaintext -error - A value of type '...' can't be assigned to a variable of type '...' - invalid_assignment -``` - -This sometimes happens when you create a simple dynamic collection -and the analyzer infers the type in a way you didn't expect. -When you later add values of a different type, the analyzer reports an issue. - -#### Example - -The following code initializes a map with several -(`String`, `int`) pairs. The analyzer infers that map to be of type `` -but the code seems to assume either `` or ``. -When the code adds a (`String`, `double`) pair, the analyzer complains: - - -```dart tag=fails-sa -// Inferred as Map -var map = {'a': 1, 'b': 2, 'c': 3}; -map['d'] = [!1.5!]; -``` - - -```plaintext -error - A value of type 'double' can't be assigned to a variable of type 'int'. Try changing the type of the variable, or casting the right-hand type to 'int'. - invalid_assignment -``` - -#### Fix: Specify the type explicitly - -The example can be fixed by explicitly defining -the map's type to be ``. - - -```dart tag=passes-sa -var map = [!!]{'a': 1, 'b': 2, 'c': 3}; -map['d'] = 1.5; -``` - -Alternatively, if you want this map to accept any value, -specify the type as ``. - -
- - -### Constructor initialization list super() call - - -```plaintext -error - The superconstructor call must be last in an initializer list: '...'. - super_invocation_not_last -``` - -This error occurs when the `super()` call is not last in a constructor's -initialization list. - -#### Example - - -```dart tag=fails-sa -HoneyBadger(Eats food, String name) - : [!super!](food), - _name = name { - ... -} -``` - - -```plaintext -error - The superconstructor call must be last in an initializer list: 'Animal'. - super_invocation_not_last -``` - -#### Fix: Put the `super()` call last - -The compiler can generate simpler code if it relies on the -`super()` call appearing last. - -Fix this error by moving the `super()` call: - - -```dart tag=passes-sa -HoneyBadger(Eats food, String name) : _name = name, [!super!](food) { - ... -} -``` - -
- - -### The argument type ... can't be assigned to the parameter type ... - - -```plaintext -error - The argument type '...' can't be assigned to the parameter type '...'. - argument_type_not_assignable -``` - -In Dart 1.x `dynamic` was both a [top type][] (supertype of all types) and a -[bottom type][] (subtype of all types) -depending on the context. This meant it was valid to assign, for example, -a function with a parameter of type `String` to a place that expected a -function type with a parameter of `dynamic`. - -However, in Dart 2 using a parameter type other than `dynamic` (or another _top_ -type, such as `Object?`) results in a compile-time error. - -#### Example - - -```dart tag=fails-sa -void filterValues(bool Function(dynamic) filter) {} -filterValues(([!String!] x) => x.contains('Hello')); -``` - - -```plaintext -error - The argument type 'bool Function(String)' can't be assigned to the parameter type 'bool Function(dynamic)'. - argument_type_not_assignable -``` - -#### Fix: Add type parameters _or_ cast from dynamic explicitly - -When possible, avoid this error by adding type parameters: - - -```dart tag=passes-sa -void filterValues[!!](bool Function(T) filter) {} -filterValues[!!]((x) => x.contains('Hello')); -``` - -Otherwise use casting: - - -```dart tag=passes-sa -void filterValues(bool Function(dynamic) filter) {} -filterValues((x) => (x [!as String!]).contains('Hello')); -``` - -
- -### Incorrect type inference - -On rare occasions, Dart's type inference might infer the -wrong type for function literal arguments in a generic constructor invocation. -This primarily affects `Iterable.fold`. - -#### Example - -In the following code, -type inference will infer that `a` has a type of `Null`: - - -```dart tag=fails-sa -var ints = [1, 2, 3]; -var maximumOrNull = ints.fold(null, (a, b) => a == null || a < b ? b : a); -``` - -#### Fix: Supply appropriate type as explicit type argument - - -```dart tag=passes-sa -var ints = [1, 2, 3]; -var maximumOrNull = ints.fold( - null, - (a, b) => a == null || a < b ? b : a, -); -``` - -
- -### Conflicting Superinterfaces - -A class which `implements` more than one superinterface must be able to -implement valid overrides for every member of every superinterface. -Each member with a given name requires compatible signatures across the -superinterfaces. - -Superinterfaces must not include conflicting generics. -A class can't implement both `C` and `C`, including indirect -superinterfaces. - -#### Example - -In the following code, -class `C` has conflicting generic interfaces. -Definitions of valid overrides for some members would be impossible. - - -```dart tag=fails-sa -abstract class C implements List, Iterable {} -``` - -#### Fix: Use consistent generics or avoid repeating transitive interfaces - - -```dart tag=passes-sa -abstract class C implements List {} -``` - - - -## Runtime errors - -The errors discussed in this section are reported at -[runtime](/language/type-system#runtime-checks). - -### Invalid casts - -To ensure type safety, Dart needs to insert _runtime_ checks in some cases. -Consider the following `assumeStrings` method: - - -```dart tag=passes-sa -void assumeStrings(dynamic objects) { - List strings = objects; // Runtime downcast check - String string = strings[0]; // Expect a String value -} -``` - -The assignment to `strings` is _downcasting_ the `dynamic` to `List` -implicitly (as if you wrote `as List`), so if the value you pass in -`objects` at runtime is a `List`, then the cast succeeds. - -Otherwise, the cast will fail at runtime: - - -```dart tag=runtime-fail -assumeStrings([![1, 2, 3]!]); -``` - - -```plaintext -Exception: type 'List' is not a subtype of type 'List' -``` - -#### Fix: Tighten or correct types - -Sometimes, lack of a type, especially with empty collections, means that -a `` collection is created, instead of the typed one you intended. -Adding an explicit type argument can help: - - -```dart tag=runtime-success -var list = [!!][]; -list.add('a string'); -list.add('another'); -assumeStrings(list); -``` - -You can also more precisely type the local variable, and let inference help: - - -```dart tag=runtime-success -List[!!] list = []; -list.add('a string'); -list.add('another'); -assumeStrings(list); -``` - -In cases where you are working with a collection that you don't create, such -as from JSON or an external data source, you can use the [cast()][] method -provided by `Iterable` implementations, such as `List`. - -Here's an example of the preferred solution: tightening the object's type. - - -```dart tag=runtime-success -Map json = fetchFromExternalSource(); -var names = json['names'] as List; -assumeStrings(names.[!cast!]()); -``` - -## Appendix - -### The covariant keyword - -The documentation on the `covariant` keyword has been -moved to [The Dart Type system](/language/type-system#covariant-keyword). - -[bottom type]: https://en.wikipedia.org/wiki/Bottom_type -[cast()]: {{site.dart-api}}/dart-core/Iterable/cast.html -[Iterable]: {{site.dart-api}}/dart-core/Iterable-class.html -[List]: {{site.dart-api}}/dart-core/List-class.html -[top type]: https://en.wikipedia.org/wiki/Top_type diff --git a/src/content/language/type-system.md b/src/content/language/type-system.md index 7d35aeb34e..e51708d172 100644 --- a/src/content/language/type-system.md +++ b/src/content/language/type-system.md @@ -658,13 +658,11 @@ also supported on setters and fields. The following resources have further information on sound Dart: -* [Fixing common type problems](/deprecated/sound-problems) - - Errors you may encounter when writing sound Dart code, and how to fix them. -* [Fixing type promotion failures](/tools/non-promotion-reasons) - +* [Fixing type promotion failures](/tools/non-promotion-reasons) - Understand and learn how to fix type promotion errors. -* [Sound null safety](/null-safety) - +* [Sound null safety](/null-safety) - Learn about writing code with sound null safety. -* [Customizing static analysis][analysis] - +* [Customizing static analysis][analysis] - How to set up and customize the analyzer and linter using an analysis options file. diff --git a/src/content/resources/whats-new.md b/src/content/resources/whats-new.md index 1359321b82..017bc77a40 100644 --- a/src/content/resources/whats-new.md +++ b/src/content/resources/whats-new.md @@ -642,7 +642,7 @@ we made the following changes to this site: * Introduced the [Objective-C and Swift interop][] page, which explains how to use Dart packages to call APIs from those languages. -* Added a workaround to [Fixing common type problems][], +* Added a workaround to Fixing common type problems, for the rare case where type inference might incorrectly infer an argument type is null. * Removed all mention of discontinued `.packages` files from [What not to commit][]. If you still need to generate a `.packages` file due to third-party legacy dependencies, @@ -658,7 +658,6 @@ we made the following changes to this site: * Added a section on customizing [`dart fix`][]. [Objective-C and Swift interop]: /interop/objective-c-interop -[Fixing common type problems]: /deprecated/sound-problems [What not to commit]: /tools/pub/private-files [`dart pub get` Options]: /tools/pub/cmd/pub-get#options [`dart compile`]: /tools/dart-compile