void-checks

Same as void_checks in Dart lints

Path
lint/correctness/void-checks
Default
On (recommended)
Origin
Dart lints
Rule
511 of 512
recommended

Don't pass or assign values to void (or FutureOr<void>) locations.

void accept<T>(T value) {}
accept<void>(1); // BAD
accept<void>(null); // GOOD

Arguments of direct function, method, and constructor invocations, assignments (including assigned-variable patterns and cascades), and index assignments are checked against the instantiated parameter type, including receiver and inferred method type arguments in cascade calls: a void location accepts only void, Null, Never, and Futures of those; a FutureOr<void> location additionally accepts dynamic and any FutureOr or Future of an acceptable type. Only block-bodied function literals have their inferred return type checked, inferring the literal against the location's type; expression bodies and tear-offs are not checked as callbacks. Return statements use the enclosing function's return type (a function literal's inferred one, not its context); returning to void is checked only for a dynamic value. Assignments and returns report at the whole statement, arguments at the value expression. Calls through function-valued variables, fields, and getters are excluded; an explicit .call(...) remains a method invocation and is checked. Grouped callees, including instantiated generic tear-offs, remain excluded; grouping a direct invocation does not exclude the invocation itself. Unresolved values stay silent.

Invalid

example.dartdart
import 'dart:async';

void accept<T>(T value) {}
void acceptFuture<T>(Future<T> value) {}
void acceptFutureOr<T>(FutureOr<T> value) {}
void acceptCallback<T>(T Function() callback) {}
int makeInt() => 1;

class Box<T> {
  Box(T value);
  T field;
  void setValue(T value) {}
}

void bad(Future<int> integerFuture) {
  accept<void>(1);
  accept<void>(makeInt());
  acceptFutureOr<void>('text');
  Box<void>(1);
  Box<void> box = Box<void>(null);
  box.setValue(1);
  box.field = 1;
  List<void> list = [];
  list.add(1);
  list[0] = 1;
}

// Analyzer 3.13.5: adv-AdvB/repro/vc_local.dart and vc_misc.dart.
void voidLocal(dynamic value) {
  void local;
  local = 1;
  local = value;
}
void voidPatterns(void parameter) {
  [parameter] = <int>[7];
  (parameter, _) = (1, 2);
}
class VoidLocations<T> {
  set value(T value) {}
  static void accept(void value) {}
  set dynamicReturn(dynamic value) {
    return value;
  }
}
extension VoidExtension on int {
  void accept(void value) {}
}
void voidCalls(void Function(void) callback, dynamic value) {
  VoidLocations<void>().value = 1;
  VoidLocations.accept(1);
  callback.call(1);
  VoidExtension(1).accept(value);
}
This value is not valid for a generic type instantiated with void.
15void bad(Future<int> integerFuture) {
16 accept<void>(1);
This value is not valid for a generic type instantiated with void.
16 accept<void>(1);
17 accept<void>(makeInt());
This value is not valid for a generic type instantiated with void.
17 accept<void>(makeInt());
18 acceptFutureOr<void>('text');
This value is not valid for a generic type instantiated with void.
18 acceptFutureOr<void>('text');
19 Box<void>(1);
This value is not valid for a generic type instantiated with void.
20 Box<void> box = Box<void>(null);
21 box.setValue(1);
This value is not valid for a generic type instantiated with void.
21 box.setValue(1);
22 box.field = 1;
This value is not valid for a generic type instantiated with void.
23 List<void> list = [];
24 list.add(1);
This value is not valid for a generic type instantiated with void.
24 list.add(1);
25 list[0] = 1;
This value is not valid for a generic type instantiated with void.
30 void local;
31 local = 1;
This value is not valid for a generic type instantiated with void.
31 local = 1;
32 local = value;
This value is not valid for a generic type instantiated with void.
34void voidPatterns(void parameter) {
35 [parameter] = <int>[7];
This value is not valid for a generic type instantiated with void.
35 [parameter] = <int>[7];
36 (parameter, _) = (1, 2);
This value is not valid for a generic type instantiated with void.
41 set dynamicReturn(dynamic value) {
42 return value;
This value is not valid for a generic type instantiated with void.
48void voidCalls(void Function(void) callback, dynamic value) {
49 VoidLocations<void>().value = 1;
This value is not valid for a generic type instantiated with void.
49 VoidLocations<void>().value = 1;
50 VoidLocations.accept(1);
This value is not valid for a generic type instantiated with void.
50 VoidLocations.accept(1);
51 callback.call(1);
This value is not valid for a generic type instantiated with void.
51 callback.call(1);
52 VoidExtension(1).accept(value);

Valid

example.dartdart
import 'dart:async';

void accept<T>(T value) {}
void acceptFuture<T>(Future<T> value) {}
void acceptFutureOr<T>(FutureOr<T> value) {}
void acceptCallback<T>(T Function() callback) {}

class Box<T> {
  Box(T value);
  T field;
  void setValue(T value) {}
}

void ordinaryVoid() {
  return;
}

void good(
  Future<int> integerFuture,
  Future<void> voidFuture,
  Future<Null> nullFuture,
  dynamic dynamicValue,
) {
  accept<void>(null);
  acceptFuture<void>(voidFuture);
  acceptFuture<void>(nullFuture);
  acceptFutureOr<void>(voidFuture);
  acceptFutureOr<void>(dynamicValue);
  acceptCallback<void>(() => null);
  Box<void> box = Box<void>(null);
  box.setValue(null);
  box.field = null;
  // Only `void` and `FutureOr<void>` locations are checked.
  acceptFuture<void>(integerFuture);
  // Function literals are inferred against their `void Function()` context,
  // and function-typed locations never conflict.
  acceptCallback<void>(() => 1);
  acceptCallback<void>(() { return 'x'; });
  final inferredCallback = () => 3;
  acceptCallback<void>(inferredCallback);
  acceptCallback<void>(() {
    if (true) {
      return 'nested';
    }
    for (final value in <int>[1]) {
      print(value);
      return 2;
    }
    return null;
  });
}

Configure void-checks

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "correctness": {
        "void-checks": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/correctness/void-checks: <reason>