Skip to content

bad type inference #40856

@trinarytree

Description

@trinarytree

in the following program

import 'dart:async';

T max<T>(Iterable<T> items, Comparator<T> compare) => null;

class A {
  int x = 0;
}

Future<A> getA() async {
  A a;
  return a ?? max([A()], (a1, a2) => a1.x - a2.x);
}

clearly T ought to be bound to A, but the compiler doesn't do this. instead it tries to bind T to FutureOr<A>, which yields this error:

foo.dart:11:41: Error: The getter 'x' isn't defined for the class 'FutureOr<A>'.
 - 'FutureOr' is from 'dart:async'.
 - 'A' is from 'foo.dart'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'x'.
  return a ?? max([A()], (a1, a2) => a1.x - a2.x);
                                        ^

one way to work around this is

var m = max([A()], (a1, a2) => a1.x - a2.x);
return a ?? m;

but it's pretty counterintuitive why inlining an expression should cause a program to break. another workaround would be to explicitly bind T:

max<A>(...)

but why are these workarounds needed? part of the problem seems to be that in an async context, one is allowed to return a Future or a non-Future, which will automatically be wrapped in a Future. for some reason, this causes the compiler to gravitate toward guessing that the type of a returned value is a FutureOr, which makes using the dot operator on such a value nearly useless.

is there any way to make the compiler a bit smarter about these cases? e.g. here, it has at least 2 clues about how to bind T (the return type and the type of the param to max), one of which is ambiguous (the return type) and the other much less ambiguous (the type of the param to max). why doesn't it prefer to use the less ambiguous clue? another option would be to try both possibilities for binding T: A and Future<A>.

Dart VM version: 2.5.2 (Tue Oct 8 16:17:11 2019 +0200) on "macos_x64"

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-core-librarySDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries.closed-not-plannedClosed as we don't intend to take action on the reported issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions