prefer-const-literals-to-create-immutables

Same as prefer_const_literals_to_create_immutables in Dart lints

Group
Style
Path
lint/style/prefer-const-literals-to-create-immutables
Default
Off, opt in
Origin
Dart lints
Rule
330 of 512

Prefers const list, set, and map literals as arguments to constructors of @immutable classes.

An instance of an @immutable class should not hold a mutable collection. A non-const collection literal passed directly to such a constructor — or nested only inside other collection literals in that argument — is flagged when it could be const: every element is a provable constant and set elements and map keys have primitive equality. A class is immutable when it or a class on its extends chain is annotated @immutable or @Immutable(...) from package:meta. Literals already in a constant context are implicitly const and are left alone, as are arguments to classes whose immutability cannot be established. Diagnostic ranges exclude parentheses surrounding the collection literal.

@immutable
class A {
  A(this.values);
  final List<int> values;
}

final a = A([1]);       // BAD
final b = A(const [1]); // GOOD

Invalid

example.dartdart
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'package:meta/meta.dart' as meta;

@immutable
class Config {
  const Config(this.values, {this.names = const {}, this.lookup = const {}});

  final Object values;
  final Object names;
  final Object lookup;
}

class Special extends Config {
  const Special(super.values);
}

class Tags extends StatelessWidget {
  const Tags({super.key, required this.tags});

  final List<String> tags;

  @override
  Widget build(BuildContext context) => const SizedBox();
}

const int base = 3;

void literals() {
  print(Config([1, 2, base]));
  print(Config(const [], names: {'a', 'b'}));
  print(Config(const [], lookup: {'a': 1}));
  print(Config(([1])));
  print(Config(<int>[]));
  print(Config([[1], const [2]]));
  print(Tags(tags: ['x', 'y']));
  print(Special([1]));
}

@immutable
abstract mixin class Base {
  const Base();
}

class Derived extends Base {
  const Derived(this.data);
  final Object data;
}

void inherited() {
  const local = 1;
  print(Derived({'a': local}));
  print(Derived(<String>{'x'}));
}

// Constructor-form meta annotations have the same immutable identity.
@Immutable('')
class ReasonedImmutable {
  const ReasonedImmutable(this.values);
  final List<Object> values;
}

void constructorAnnotation() {
  print(ReasonedImmutable([]));
}

@Immutable('Collection arguments must remain immutable')
class ReasonedBase {
  const ReasonedBase(this.values);
  final Object values;
}

class ReasonedChild extends ReasonedBase {
  const ReasonedChild(super.values);
}

void inheritedConstructorAnnotation() {
  print(ReasonedChild([1]));
}

@meta.Immutable('')
class PrefixedImmutable {
  const PrefixedImmutable(this.values);
  final Object values;
}

void prefixedConstructorAnnotation() {
  print(PrefixedImmutable({'key': 1}));
}
Use `const` literals as arguments to constructors of `@immutable` classes.
29void literals() {
30 print(Config([1, 2, base]));
Use `const` literals as arguments to constructors of `@immutable` classes.
30 print(Config([1, 2, base]));
31 print(Config(const [], names: {'a', 'b'}));
Use `const` literals as arguments to constructors of `@immutable` classes.
31 print(Config(const [], names: {'a', 'b'}));
32 print(Config(const [], lookup: {'a': 1}));
Use `const` literals as arguments to constructors of `@immutable` classes.
32 print(Config(const [], lookup: {'a': 1}));
33 print(Config(([1])));
Use `const` literals as arguments to constructors of `@immutable` classes.
33 print(Config(([1])));
34 print(Config(<int>[]));
Use `const` literals as arguments to constructors of `@immutable` classes.
34 print(Config(<int>[]));
35 print(Config([[1], const [2]]));
Use `const` literals as arguments to constructors of `@immutable` classes.
34 print(Config(<int>[]));
35 print(Config([[1], const [2]]));
Use `const` literals as arguments to constructors of `@immutable` classes.
35 print(Config([[1], const [2]]));
36 print(Tags(tags: ['x', 'y']));
Use `const` literals as arguments to constructors of `@immutable` classes.
36 print(Tags(tags: ['x', 'y']));
37 print(Special([1]));
Use `const` literals as arguments to constructors of `@immutable` classes.
51 const local = 1;
52 print(Derived({'a': local}));
Use `const` literals as arguments to constructors of `@immutable` classes.
52 print(Derived({'a': local}));
53 print(Derived(<String>{'x'}));
Use `const` literals as arguments to constructors of `@immutable` classes.
63void constructorAnnotation() {
64 print(ReasonedImmutable([]));
Use `const` literals as arguments to constructors of `@immutable` classes.
77void inheritedConstructorAnnotation() {
78 print(ReasonedChild([1]));
Use `const` literals as arguments to constructors of `@immutable` classes.
87void prefixedConstructorAnnotation() {
88 print(PrefixedImmutable({'key': 1}));

Valid

example.dartdart
import 'package:meta/meta.dart';

@immutable
class Config {
  const Config(this.values, {this.names = const {}});

  final Object values;
  final Object names;
}

class Mutable {
  Mutable(this.values);

  final Object values;
}

class Lookalike implements Config {
  Lookalike(this.values);

  @override
  final Object values;

  @override
  Object get names => const {};
}

void literals(int x, List<int> other) {
  print(Config(const [1, 2]));
  print(const Config([1, 2], names: {'a'}));
  print(Config([x]));
  print(Config([...other]));
  print(Config([for (var i = 0; i < 3; i++) i]));
  print(Config([if (x > 0) 1]));
  print(Mutable([1, 2]));
  final values = [1, 2];
  print(Config(values));
  print(Config(other.toList(), names: {x}));
  print(Unknown([1]));
  print(Lookalike([1]));
}

class EqualityKey {
  const EqualityKey();
  @override
  bool operator ==(Object other) => other is EqualityKey;
  @override
  int get hashCode => 0;
}

void keysWithoutPrimitiveEquality() {
  print(Config({EqualityKey(): 1}));
  print(Config({1.5}));
}

@Immutable('')
class ReasonedImmutable {
  const ReasonedImmutable(this.values);
  final List<Object> values;
}

void constructorAnnotation(List<Object> values) {
  print(ReasonedImmutable(const []));
  print(const ReasonedImmutable([]));
  print(ReasonedImmutable(values));
}

class ReasonedInterface implements ReasonedImmutable {
  const ReasonedInterface(this.values);
  @override
  final List<Object> values;
}

void constructorAnnotationInterface() {
  print(ReasonedInterface([]));
}

Configure prefer-const-literals-to-create-immutables

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "prefer-const-literals-to-create-immutables": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/style/prefer-const-literals-to-create-immutables: <reason>