Closed pq closed 3 years ago
What was the issue and how does this work around it?
Hey @natebosch. The basic issue has to do with type inference where the type of Future
is seen as dynamic
which doesn't agree with an expectation (and reality) of a more specific type required inside the wrapped unawaited expression.
I'll ping you with the internal issue (David has seen it) -- there's more context there...
Thanks for the context. I think this fix makes sense - it means that adding unawaited
around an expression is less likely to change the inference within that expression.
The reason this helps is that before the Future<void>
parameter type would cause inference on the expression for that argument to want to pick Future<void>
. It would push it "down" into the argument. But with a generic of <T>
that can't be filled in elsewhere, won't cause <void>
to be preferred.
Here is an example:
Future<E> genericIsImportant<E>(E arg) async {
print(E);
return arg;
}
void unawaitedOld(Future<void> f) {}
void unawaitedNew<T>(Future<T> f) {}
void main() {
unawaitedOld(genericIsImportant(1));
unawaitedNew(genericIsImportant(1));
}
In genericIsImportant
with no context the E
gets inferred base on the argument. But when there is a context it pushes the E
to it's argument. So this program prints void
pushed down from the Future<void>
by unawaitedOld
, and then int
inferred up from the 1
since unawaitedNew
doesn't stop that inference from happening.
@leafpetersen may be able to point out if I've made any mistakes.
Yes, that's right.
Sounds good--I'll run it through internal global presubmit just to be on the safe side...
Thanks!
I just recently hit a snag using
unawaited
that I believe could have been avoided were it generic.Thoughts? Reservations?
/cc @davidmorgan @bwilkerson