Closed
Description
The following code behaves inconsistently between CFE and the analyzer:
class A {
int call(int x) => x;
}
T foo<T>(T Function(T) f) => null;
T bar<T>(T Function(int x) f) => null;
T baz<T>(int Function(T x) f) => null;
void main() {
foo(new A());
bar(new A());
baz(new A());
}
The analyzer seems to insert call tearoffs as follows:
void main() {
foo<dynamic)>(new A());
bar<dynamic>(new A().call);
baz<dynamic>(new A());
}
emitting error messages on the call to foo
and baz
:
error • The constructor returns type 'A' that isn't of expected type '(dynamic) → dynamic' at /Users/leafp/tmp/ddctest.dart:10:7 • strong_mode_invalid_cast_new_expr
error • The constructor returns type 'A' that isn't of expected type '(dynamic) → int' at /Users/leafp/tmp/ddctest.dart:12:7 • strong_mode_invalid_cast_new_expr
warning • A function of type 'A' can't be assigned to a location of type '(dynamic) → dynamic' at /Users/leafp/tmp/ddctest.dart:10:7 • strong_mode_uses_dynamic_as_bottom
warning • A function of type 'A' can't be assigned to a location of type '(dynamic) → int' at /Users/leafp/tmp/ddctest.dart:12:7 • strong_mode_uses_dynamic_as_bottom
The CFE seems to insert call tearoffs as follows,
void main() {
foo<dynamic)>(new A().call);
bar<dynamic>(new A().call);
baz<dynamic>(new A().call);
}
producing the following error message:
file:///Users/leafp/tmp/ddctest.dart:10:11: Error: A value of type '(dart.core::int) → dart.core::int' can't be assigned to a variable of type '(dynamic) → dynamic'.
Try changing the type of the left hand side, or casting the right hand side to '(dynamic) → dynamic'.
foo(new A());
^
If the call to foo
is commented out, then a case failure occurs on the call to baz
:
Unhandled exception:
type '(int) => int' is not a subtype of type '(dynamic) => int'
There are two issues here:
- The CFE and the analyzer should produce the same choices for the tearoffs.
- I think we should be able to infer these correctly, rather than falling to dynamic.
On the inference front, it seems to me that for foo
, we are doing downwards inference in a _ Function(_)
context. This forces a tearoff on new A()
, and from there the upwards type should be int Function(int)
which should then resolve the type argument to foo
appropriately.
cc @lrhn @stereotype441 @kmillikin @jmesserly for thoughts on the inference and the tearoff behavior.