-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Future.wait([b, c]) does not have the correct return type #27151
Comments
ah great catch! One thing I noticed while investigating another bug, is we push down |
Filed #27155 to track the "push down dynamic" issue, but leaving this one open because I think it's related to ListLiteral specifically (and MapLiteral probably has a similar problem). |
@leafpetersen want to run this by you. So we'd currently perform the following inference: List/*<T>*/ f/*<T>*/(/*=T*/ a,/*=T*/ b) => null;
class C<T> {
C(T a, T b);
}
main() {
List<num> x = f/*infer <int>*/(123, 456); // 1
C<num> y = new C/*infer <int>*/(123, 456); // 2
List<num> z = /*infer <num>*/[123, 456]; // 3
} My inclination would be to make 3 consistent with 1 and 2: use the most precise type, let someone weaken it if they want to via explicit annotation. Why this relates to the bug: await creates a but you should be able reproduce it with |
I agree, consistency between all 1, 2 and 3 would be good. |
Agreed that they should all be consistent. I'm not sure what the best thing to choose is when you have a less precise type from context. Choosing the downwards type ('num' here) is the safest option, since any uses of the value will be at the downwards type (or will be mediated by a cast). You can certainly have code that looks like: void addStuffToList(List<num> l) {
l.add(3.0);
l.add(4);
}
addStuffToList([1]); where choosing the more precise type will cause a runtime failure. Of course, if you do: List<num> l = b ? [1] : [1.0];
....
if (b) {
List<int> li = l as List<int>
} You get the runtime failure if you choose the less precise type. Is the choice of Concretely on the |
agreed we should not push
yeah, it's a result of the heuristic, which we weren't sure we had right. Perhaps when we have a return context, we should choose the type parameter in such a way that it ends up as close as possible to the return context. Concretely, if the type parameter appears in an return position (e.g. return type is That is backwards the normal heuristic, which tries to pick the tightest type, but seems reasonable because as you noted, accesses are mediated by the (weaker) return context type. |
@leafpetersen here's a straw man proposal for this issue: I'll have list/map literals (3) go through the same code path as generic functions (1) and constructors (2). But I'll change the heuristic on all of them, as described above, to pick a type closer to the return context. WDYT? |
I'm on board with making list/map literals use the same code path. I'd like to think through the details of the heuristic change a bit before committing to it. |
thanks! sounds great. |
clarification to one of my comments:
This was not enough to fix it. We still instantiate Future.wait's type parameter as @leafpetersen I think that's the other reason the current heuristic in generic methods is necessary for now. We don't have unified upwards+downwards so our downwards types are too weak for parameters to generic methods. Hence we benefit from finding the tightest type. Once we get unified inference that won't matter, but it's a useful stopgap. |
another interesting find: unifying results in a worse errors, because of #26992 (inference failures silently result in "dynamic"). if nothing else this has been a good exercise in finding some rough spots in the current system :) |
i'm going to mark this blocked on that other bug. I have the CL working for lists, but I don't want to go further if it makes a bunch of precise downwards errors into "down cast" warnings. e.g. if you use |
CL for this in https://codereview.chromium.org/2343713002/ |
https://codereview.chromium.org/2338293003/ for a changelog entry |
R=leafp@google.com Review URL: https://codereview.chromium.org/2338293003 .
This might be an extension of #27134.
But in contrast to it, this is not the code I have seen in internal codebase.
Just accidentally occurred when I was testing after you fixed #27134.
In the code below
result
has the static typeList<A>
.But
result2
isList<dynamic>
.Even if
b
andc
are bothFuture<A>
,result2
andawait
don't get the ideal type.The text was updated successfully, but these errors were encountered: