I have class that takes to generics (for example A
and B
) and then i have a subclass which specifies one of those generics, like that:
class Foo<A, B>{
void f() {}
}
class Boo<A> extends Foo<A, String> {
void b() {}
}
When i am trying to cast a Foo
variable to Boo
the smart cast some how is not working:
void test<A, B>(Foo<A, B> foo) {
if (foo is Boo<A>)
foo.b();
}
The error message is: Error: The method 'b' isn't defined for the class 'Foo<A, B>'.
But when i drop the generic types the function compiles:
void test(Foo foo) {
if (foo is Boo)
foo.b();
}
Is there any way i can get the smart cast to work without dropping the generic types?
This is working as intended.
Dart only promotes variables to subtypes (a more precise type) to ensure that you don't lose information. That's why it's called "promotion", not just "casting".
When you do foo is Boo<A>
, then it's checking whether Boo<A>
is a subtype of the currently known type of the foo
variable, which is Foo<A, B>
.
It is not.
The type Boo<A>
a subtype of Foo<A, String>
(because it extends that), but String
is not (statically known to be) a subtype of the type variable B
. So as static types, Boo<A>
is not a subtype of Foo<A, B>
, and the promotion doesn't promote the static type of the foo
variable.
There is not a lot you can do about this as written. The type B
could be bound to Never
at runtime, so no other type would be sound to assume to be a subtype of B
at compile time.
When you drop the generics, the type of foo
becomes Foo<Object?, Object?>
, and any type implementing Foo
is a subtype of that, so you do get promotion to Bar<whatever>
.
If you declared test
as:
void test<A>(Foo<A, String> foo) {
then the promotion would succeed.