linter icon indicating copy to clipboard operation
linter copied to clipboard

avoid_types_on_closure_parameters false positive with implicit-dynamic

Open rrousselGit opened this issue 3 years ago • 4 comments

Describe the issue Some SDK functions type their error callback parameter as Function to accept both Function(Object) and Function(Object, StackTrace):

Future future;
future.then(..., onError: <this callback>);

As such, writing the following will trigger implicit-dynamic:

Future future;
future.then(..., onError: (err, stack) {
  // err and stack are both dynamic
});

The solution should be to explicitly write the type:

Future future;
future.then(..., onError: (Object err, StackTrace stack) {
  // fixed implicit-dynamic
});

but doing this now causes avoid_types_on_closure_parameters on both parameters

Expected behavior

I would expect avoid_types_on_closure_parameters to detect that Object/StackTrace are types more specific than dynamic, and therefore allow it.

Additional context

Possibly related to https://github.com/dart-lang/linter/issues/695 and https://github.com/dart-lang/linter/issues/2131

rrousselGit avatar Apr 05 '22 07:04 rrousselGit

I think this would be a special case we'd have to hard-code into the linter. The type of that callback is Function, since we don't have union types. The real type (as enforced by the analyzer, in special case code) is void Function(Object)|void Function(Object, StackTrace), I think.

I believe special casing in this lint rule would be a prudent, practical, beneficial policy.

srawlins avatar Apr 05 '22 14:04 srawlins

Assuming the special casing is based on Function not Future.then(onError:) then I think that's fine

Because ultimately folks may write utilities around such as:

void doSomething(Function fn) {
  Stream().handleError(fn);
}

// will warn
doSomething((Object err, StackTrace stack) {

});

rrousselGit avatar Apr 07 '22 08:04 rrousselGit

In my opinion the issue is more general and arises at several places (assignments, arguments, declarations...) where a dynamic, Object, Function is expected. For instance in the following case I don't think the lint should trigger:

  dynamic f1;
  f1 = (int a) {}; // LINT
  Function f2;
  f2 = (int a) {}; // LINT
  Object f3;
  f3 = (int a) {}; // LINT
  var l = [
    (int a) => 1, // LINT
  ];

a14n avatar Apr 07 '22 09:04 a14n

this is quite a pain point for me, because I do want the lint to prevent me and my colleagues from putting type annotations on closures wherever possible, but I also don't want to have to pepper the code with // ignore: comments whereever I use provider's SelectContext.select method: https://pub.dev/documentation/provider/latest/provider/SelectContext/select.html

context.select((SomeModel m) => m.attr), //LINT

NANASHI0X74 avatar Jul 27 '22 12:07 NANASHI0X74