dart-lang / linter

Linter for Dart.
https://dart.dev/tools/linter-rules
BSD 3-Clause "New" or "Revised" License
629 stars 170 forks source link

False positive for "avoid_types_on_closure_parameters" when contravariance applies #2131

Open vsevolod19860507 opened 4 years ago

vsevolod19860507 commented 4 years ago

When contravariance applies

class Unused {
  const Unused();
}

const unused = Unused();

@immutable
class User {
  final String name;

  const User({this.name});

  User Function({String name}) get copyWith => ({
        Object name = unused, // False positive
      }) =>
          User(
            name: name == unused ? this.name : name as String,
          );
}
davidmorgan commented 4 years ago

+1

Along with https://github.com/dart-lang/linter/issues/2131 this would make the lint match omit_local_variable_types, which seems desirable.

srawlins commented 1 year ago

I find the motivating example to be extremely non-idiomatic. But I don't want to discount the idea.

In the example, we create a copyWith function, which is a User Function({String name}), but secretly under the covers, it is a User Function({Object name}), with a default value for name, which is not a String, but is a sentinel value. It's very clever, but I've never used or seen this design before.

The fix, to account for this example, would be to never complain about a parameter type if it is not exactly equal to the type that would be inferred, were the type omitted. I don't know that we have the tooling to answer hypothetical inference questions like this.

rrousselGit commented 8 months ago

I encountered this earlier.

The fix, to account for this example, would be to never complain about a parameter type if it is not exactly equal to the type that would be inferred, were the type omitted. I don't know that we have the tooling to answer hypothetical inference questions like this.

An alternative is to silence the lint if it is a downcast and is not required.

So:

Function(int) cb = (num a) {}; // KO

Function({int}) cb = ({int? a}) {}; // OK
Function({int}) cb = ({Object a = _sentinel}) {}; // OK