avoid_types_on_closure_parameters false positive with implicit-dynamic
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
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.
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) {
});
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
];
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