Skip to content

I wish type inference would not resolve to Null #34058

Open
@matanlurey

Description

@matanlurey

... best explained through a simple example (real issue: angulardart/angular#1533):

void main() {
  var comp1 = Comp1();
  var comp2 = Comp2();
  comp2.registerEvent(eventHandler1(comp1.onEventInt));
}

class Comp1 {
  void onEventInt(int event) {}
}

class Comp2 {
  void registerEvent(void Function(String) listener) {
    listener('Hello');
  }
}

void Function(E) eventHandler1<E, F extends E>(void Function(F) handler) {
  print('Function($E) for eventHandler1<$E, $F>(void Function($F))');
  return (E event) {
    handler(event as F);
  };
}

See the issue? If you run this program, you get the following:

Function(String) for eventHandler1<String, Null>(void Function(Null))
Uncaught exception:
CastError: "Hello": type 'JSString' is not a subtype of type 'Null'

It looks like type inference realizes (correctly) that int is not a sub-type of String, and recovers by falling back to bottom (i.e. Null). While this is correct, the user experience is degraded significantly - something that could have been a compile-time error is now a (very confusing) runtime one.

We slightly improved the runtime error by adding an assert:

 assert(
        E == Null || F != Null,
        "Event handler '$handler' isn't assignable to expected type "
        "'($E) => void'");

... of course this is a hack, and I'm not sure it is technically always correct.

I wish we could either:

  • Ban inferring Null, i.e. require the user to type <Null>.
  • Find a replacement pattern for the above use case that has correct static type checking

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-languageDart language related items (some items might be better tracked at github.com/dart-lang/language).strict-analysis-neededMark issues where strict-raw-types, strict-inference and similar analysis options were helpful

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions