-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Consider the following example:
class A {
void m(covariant int i) {}
}
abstract class I {
void m(num n);
}
class B extends A implements I {
// Has member signature `void m(covariant num)`.
}
void main() {
B().m(3.1); // OK statically, but throws at run time.
}This situation is unfortunate, because it is known statically that an instance of C has the member signature void m(covariant int); but because the method implementation is inherited and a superinterface says otherwise, the static analysis reports the member signature void m(covariant num).
This means that we will have a run-time type error, and it is known statically, but there is no indication that there is a problem at compile-time.
As a matter of style, we could eliminate this problem by always declaring the actual member signature of the inherited method in the case where there is a covariant parameter whose type is a subtype of the one in the class interface:
// ...
class B extends A implements I {
void m(covariant int i);
}
void main() {
B().m(3.1); // A compile-time error, as it should be.
}The situation may not arise very often, but this is just one more reason why developers shouldn't have to think about it, when they could have it flagged by a lint:
LINT declare_covariant_parameter_type: A parameter p in the interface of a concrete class C is covariant-by-declaration and has type T, but the implementation in an instance of C of the enclosing method is inherited, and the corresponding parameter has type S such that S <: T and S != T.
The lint advice would be to add an abstract declaration with the same signature as the inherited method. There could be a quick fix.