CFE inference issue on generic method type param? #32291
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
Comments
The analyzer is correct, because of the asymmetry in our treatment of
My guess is that the CFE is using |
@leafpetersen I dug into the CFE behavior and it's not exactly what you guessed. Two things are going on: First of all, the context passed down when inferring Secondly, the CFE contains code to try to mimic the analyzer's (incorrect) handling of
Taking both of these into account explains the error message from the CFE, because it infers If I disable the code that mimics the analyzer's the analyzer's handling of AFAICT, the analyzer's behavior is to consider any context satisfying
Under these rules, As a temporary workaround, I'll see if I can get the front end to mimic the analyzer's behavior even more precisely. But for a long term solution, I think I need clarification from @leafpetersen, @lrhn, or @eernstg about what behavior we really want here. |
I've uploaded a temporary workaround that causes the front end to treat Even though I'm waiting to hear from @leafpetersen, after some discussion with @lrhn and @eernstg, I am becoming more inclined to suspect that the correct solution will be to change the front end type inference behavior so that it treats a context of |
And here's the speculative CL to treat I'll wait for further discussion on this bug before sending it out for review. |
cc @jmesserly
The invariant is that if we infer This points out a second area where I think the spec draft is just wrong (but the analyzer, and it looks like kernel as well both do the right thing). We should use the more precise upwards type for subsequent inference. For example, the draft spec says:
which implies that even if
Both implementations seem to do the right thing here:
produces:
on both implementations. The final question is what to do about a downwards context of I'll work on an update to the draft spec this week. |
Some examples to contemplate: T foo<T>(T x) {
print(T);
return x;
}
List<T> bar<T>(T x) {
print(T);
return [x];
}
List<S> baz<S, T>(Map<S, T> x) {
print("S = $S, T = $T");
}
void main() {
var y0 = foo(4);
dynamic y1 = foo(4);
Object y2 = foo(4);
print("Bar");
var z0 = bar(4);
List<dynamic> z1 = bar(4);
List<Object> z2 = bar(4);
print("[foo]");
z1 = [foo(4)];
z2 = [foo(4)];
List<int> z3 = [foo(4)];
print("baz");
List<dynamic> a0 = baz({3: "hello"});
List<int> a1 = baz({3: "hello"});
List<num> a2 = baz({3: "hello"});
List<num> a3 = baz({3: "hello"} ?? {3: "hello"});
} Currently
|
Just to clarify: do you mean in all cases, or just for |
In all cases. |
I can see the reasoning behind differentiating a context of This probably even generalizes to the top-level, so Object y2 = foo(4); // prints "Object" makes sense in the same way. It doesn't matter as much, since you can't create an object containing the type. List<T> foo<T>(T x) { print(T); return <T>[x]; }
Object o1 = foo(42);
dynamic o2 = foo(42);
/// And how does FutureOr fit into this?
FutureOr<Object> o3 = foo(42);
FutureOr<dynamic> o3 = foo(42); |
Ok, https://dart-review.googlesource.com/c/sdk/+/43761 is now out for review--it should fix the error Vijay saw. I won't close this bug when it lands, since other open questions were raised during the discussion. |
They don't quite implement the above algorithm. Here is an example of where they don't do the right thing:
Both the analyzer and the CFE complain that the call to |
any updates on this? |
I've filed #32357 to track the question around |
If that's the case, is there any reason to have a notion of an 'empty (expectation) context' at all? |
My two cents: that notion should go away, and everywhere we're using |
We do this by requiring that the context argument to inferExpression is non-null (since `_` is represented by `null`). Instead of passing `null` as a type context, we pass `const UnknownType()`, which represents `?`. See #32291. Change-Id: I9a0d0f3bcd74e6226004c85f63cf8be49934388a Reviewed-on: https://dart-review.googlesource.com/43761 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Kevin Millikin <kmillikin@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Fixed by 90098c6. |
Agreed. |
The following gives no static error with the analyzer and runs without runtime error on DDC:
With the CFE, I get the following static error:
I believe the analyzer is computing the static type of
i1
as anIterable<List<String>>
and the CFE asIterable<List<dynamic>>
.@leafpetersen @lrhn - can you please double check that the analyzer behavior is as expected? I'm not entirely sure given the
??
operator.This appears to come up in an internal Flutter app. We can probably workaround this.
The text was updated successfully, but these errors were encountered: