Skip to content

Inconsistent call method tearoff behavior between analyzer and CFE #32864

Closed
@leafpetersen

Description

@leafpetersen

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2A bug or feature request we're likely to work ondart-model-analyzer-specIssues with the analyzer's implementation of the language speclegacy-area-analyzerUse area-devexp instead.type-bugIncorrect behavior (everything from a crash to more subtle misbehavior)

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions