-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
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"