dart-lang / linter

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

proposal: `type_init_super_parameters` #3210

Open srawlins opened 2 years ago

srawlins commented 2 years ago

type_init_super_parameters

Description

There is a type_init_formals rule, which says "don't do C(int this.f)". Should we have a similar rule for "Don't do C(int super.f)".

Kind

Does this enforce style advice? Guard against errors? Other? Consistency with type_init_formals?

Good Examples

class C {
  C(int f);
}
class D extends C {
  D(super.f);
}

Bad Examples

class C {
  C(int f);
}
class D extends C {
  D(int super.f);
}
eernstg commented 2 years ago

I think type_init_formals and a new type_super_parameters should behave similarly.

However, type_init_formals is documented to behave in a slightly suboptimal manner, so I'd recommend that type_super_parameters behave in the same way as type_init_formals actually does, and the documentation of both should reflect this (cf. https://github.com/dart-lang/linter/issues/3214). So here are the relevant cases:

It makes sense to lint the case where an initializing formal or super parameter has a declared type, and it is exactly the same type as the one that would have been inferred:

class A {
  int x;
  A(int this.x); // Lint, we'd get the same type by inference anyway.
}

class B extends A {
  B(int super.x); // Lint, we'd get the same type by inference anyway.
}

However, it seems to be a false positive in the case where the types differ:

class Either {
  int? x, y; // Invariant: one of these is null, the other is non-null.

  // Public constructors enforce the invariant.
  Either.x(int this.x) : y = null;
  Either.y(int this.y) : x = null;

  // Private constructor, relies on correct invocations, but with assertion.
  Either._({this.x, this.y}) :
      assert((x != null && y == null) || (x == null && y != null));
}

class EitherDefault extends Either {
  EitherDefault.x({int super.x = 42}) : super._();
  EitherDefault.y({int super.y = 24}) : super._();
}

type_init_formals already omits a lint at int this.x and int this.y, and similarly I'd recommend that type_super_parameters should omit a lint at int super.x = 42 and int super.y = 24, because the declared type differs from the one that would have been inferred.

srawlins commented 1 year ago

I added a proposal to update Effective Dart: https://github.com/dart-lang/site-www/issues/4262