Strong Mode Dart: Fixing Common Problems

Send feedback

If you’re having problems converting your code to strong mode, this page can help. Be sure to also check out Strong Mode Dart for an overview of what “sound Dart” means, and how strong mode contributes to making Dart a sound language.

Contents

Troubleshooting:

Common errors and warnings:

Appendix:

For a complete list of sources about strong mode and sound Dart, see other resources in Strong Mode Dart.

Troubleshooting

Am I really using strong mode?

If you’re not seeing strong mode errors or warnings, make sure that you’re using strong mode. A good test is to add the following code to a file:

void test() {
  bool b = [0][0];
}

If you’re using strong mode, you’ll see the following warning from the analyzer:

[warning] A value of type 'int' can't be assigned to a variable of type 'bool'.

I’m not using strong mode and I think I should be

Strong mode is enforced by the Dart analyzer. How you troubleshoot strong mode depends on whether you are running dartanalyzer from the command line, or via one of the JetBrains IDEs.

Command line analyzer

If you are running dartanalyzer from the command line and you don’t see expected strong mode errors, try the following:

  • If your project contains an analysis options file, make sure you’ve specified strong mode: true correctly. For more information, see Specifying strong mode.

  • Run the analyzer with the --strong tag:

    dartanalyzer --strong <file-or-directory>
    

For information on how to set up an analysis options file, see Customize Static Analysis.

JetBrains IDEs

Make sure that you have an analysis options file with strong mode turned on. This file needs to be placed in a content root, or in a parent directory of your content root. The steps for viewing a project’s content root varies a bit for WebStorm and IntelliJ.

Note that a large project may have multiple content roots. The following instructions describe how to see a list of content roots in WebStorm or IntelliJ.

WebStorm
In the Preferences panel (WebStorm > Preferences), click Directories from the list on the left. The +Add Content Root button in the column on the far right appears above the content roots, shown in bold.
IntelliJ
In the Project Structure panel (File > Project Structure), Modules is selected from the list on the left by default. The +Add Content Root button in the column on the far right appears above the content roots, shown in bold.

For more information on where to put your analysis options file, see the analysis options file, part of Customize Static Analysis.

Common errors and warnings

How to fix some of the errors and warnings you may see from the analyzer when enabling strong mode.

Undefined member

Error: <member> isn't defined for the class <class>

These errors usually appear in code where a variable is statically known to be some supertype but the code assumes a subtype.

Fix: Replace the definition of the member with an explicit type declaration or a downcast.

For example, the analyzer complains that context2D in the following code is undefined:

var canvas = querySelector("canvas");
canvas.context2D; // <-- Error.

The querySelector() method statically returns an Element, but the code assumes it returns the subtype CanvasElement where context2D is defined. The canvas field is declared as var which, in classic Dart, types it as dynamic and silences all errors. Strong mode Dart infers canvas to be an Element.

Fix this error with an explicit type declaration:

CanvasElement canvas = querySelector("canvas");
canvas.context2D;

If you actually want a dynamic type, specify dynamic:

dynamic canvas = querySelector("canvas");
canvas.context2D;

Invalid method override

Error: Invalid override. The type of <type> is not a subtype of <type>.

These errors typically occur when a subclass tightens up a method’s parameter types by specifying a subclass of the original class.

Fix: Widen the types in the method’s parameter list. The subclass’s method should accept every object that the superclass’s method takes.

In the following example, the parameters in the add() method are changed from num to int, a subtype of num. This code passes static analysis in classic Dart, but is unsafe and fails analysis in strong mode Dart.

abstract class NumberAdder {
  num add(num a, num b);
}

class IntAdder extends NumberAdder {
  int add(int a, int b) => a + b;
}

Consider the following scenario where floating point values are passed to an IntAdder:

NumberAdder adder = new IntAdder(); // Upcast
adder.add(1.2, 3.4);                // Kaboom!

If the override were allowed, this code would crash at runtime.

Fix this error by widening the types in the subclass:

abstract class NumberAdder {
  num add(num a, num b);
}

class IntAdder extends NumberAdder {
  num add(num a, num b) => a + b;
}

For more information, see Use proper input parameter types when overriding methods.


Missing type arguments

Error: Invalid override. The type of <type> is not a subtype of <type>.

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.

In the following example, Subclass extends Superclass<T> but doesn’t specify a type argument. The analyzer infers Subclass<dynamic>, which results in an invalid override error on method(int).

class Superclass<T> {
  void method(T t) {}
}

class Subclass extends Superclass {
  void method(int i) {} // <-- Error.
}

You can fix this by specifying the type on the subclass:

class Superclass<T> {
  void method(T t) {}
}

class Subclass extends Superclass<int> {
  void method(int i) {}
}

Assigning mismatched types

Warning: A value of type '<type>' cannot be assigned to a variable of type 'type'.

This sometimes happens when you create a simple dynamic collection and the analyzer Dart infers the type in a way you didn’t expect. When you later add values of a different type, the analyzer produces a warning.

Fix: Specify the type explicitly.

For example, the following code initializes a map with several (String, integer) pairs. The analyzer infers that map to be of type <String, int> but the code assumes <String, dynamic>. When the code then adds a (String, float) pair, the analyzer complains.

void main() {
  var map = {
    'a': 7,
    'b': 11,
    'c': 13
  }; // <= inferred to be Map<String, int>

  map['d'] = 1.5;  // 1.5 is not int!
}

This can be fixed by explicitly defining the map’s type to be <String, dynamic>.

void main() {
  var map = <String, dynamic>{
    'a': 7,
    'b': 11,
    'c': 13
  };

  map['d'] = 1.5;
}

Alternatively, if you only want this map to accept integers and floats, you can specify the type as <String, num>.


Constructor initialization list super() call

Error: super call must be last in an initializer list (see https://goo.gl/EY6hDP): 'super(style)'.

This error occurs when the super() call is not last in a constructor’s initialization list.

Fix: Put the super() call last.

The Dart dev compiler generates simpler code if it relies on the super() call appearing last. The following example generates an error in strong mode Dart:

HoneyBadger(Eats food, String name)
  : super(food),
    _name = name { ... }

Fix the error by moving the super() call:

HoneyBadger(Eats food, String name)
  : _name = name,
    super(food) { ... }

For more information, see DO place the super() call last in a constructor initialization list in Effective Dart.


Appendix

The covariant keyword

Some (rarely used) coding patterns rely on tightening a type by overriding a parameter’s type with a subtype, which is illegal in strong mode Dart. In this case, you can use the covariant keyword to tell the analyzer that you are doing this intentionally. This removes the static error and instead checks for an invalid parameter type at runtime.

The following shows how you might use covariant:

import 'package:meta/meta.dart';

class Animal {
  void chase(Animal x) {}
}

class Mouse extends Animal {}

class Cat extends Animal {
  void chase(covariant Mouse x) {}
}

Although this example shows using covariant in the subtype, the covariant keyword can be placed in either the superclass or the subclass method. Usually the superclass method is the best place to put it. The covariant keyword applies to a single parameter and is also supported on setters and fields.