-
Notifications
You must be signed in to change notification settings - Fork 225
Description
(Please feel free to update the title with a more descriptive one.)
Repro from @mraleph:
class A<T> {}
class B<T> extends A<T> {}
Type typeOf<T>(T v) => T;
void main() {
B<String>? b;
print(typeOf(b ?? A()));
}
Here ideally we want to see String
, but it prints dynamic
instead.
So in b ?? A()
, the type parameter of A
is inferred as dynamic
instead of String
even though type of b
is B<String>
.
In practice, this causes a lot of headache in a change in the protobuf library. Recently we made a change to return more precise types in generated message classes. Instead of List<T>
, we now return PbList<T>
. PbList<T>
extends ListBase<T>
which implements List<T>
.
This change caused a lot of breakage in user code, because a lot of types became dynamic
after this change.
The fix is not always trivial: we have to add type annotations, but sometimes the types are not even in scope, and sometimes we can't even import the types because they're not exported in a direct dependency.
The fix is also triggers the omit_local_variable_types
lint, which shouldn't be a lint as it changes semantics (without type annotations, the element type becomes dynamic
).
The changes needed in user code can be seen in cl/809933607. There are two kinds of code that breaks with this change:
-
myMessage?.myList ?? []
-
var myList = myMessage.myList; // PbList<T> ... if (...) { myList = [...]; // List<T> }