Skip to content

Less than ideal type inference for type parameters in some cases #4518

@osa1

Description

@osa1

(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>
    }
    

Metadata

Metadata

Assignees

No one assigned

    Labels

    requestRequests to resolve a particular developer problemtype-inferenceType inference, issues or improvements

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions