analyzer: Support implicit call tearoff from type variable

Fixes https://github.com/dart-lang/sdk/issues/54353

Change-Id: I0b7725efb6380de35832f1a713df3b4139990f0b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/346947
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
This commit is contained in:
Sam Rawlins 2024-01-18 17:19:50 +00:00 committed by Commit Queue
parent 6f97eb264a
commit 63399a992c
2 changed files with 70 additions and 0 deletions

View file

@ -293,6 +293,14 @@ mixin ErrorDetectionHelpers {
/// > is a function type or the type `Function`, `e` is treated as `e.call`.
MethodElement? getImplicitCallMethod(
DartType type, DartType? context, SyntacticEntity errorNode) {
var visitedTypes = {type};
while (type is TypeParameterType) {
type = type.bound;
if (!visitedTypes.add(type)) {
// A cycle!
return null;
}
}
if (context != null &&
typeSystem.acceptsFunctionType(context) &&
type is InterfaceType &&

View file

@ -538,6 +538,68 @@ ImplicitCallReference
staticType: C
staticElement: self::@class::C::@method::call
staticType: void Function(int)
''');
}
test_simpleIdentifier_typeAlias() async {
await assertNoErrorsInCode('''
class A {
void call() {}
}
typedef B = A;
Function f(B b) => b;
''');
final node = findNode.implicitCallReference('b;');
assertResolvedNodeText(node, r'''
ImplicitCallReference
expression: SimpleIdentifier
token: b
staticElement: self::@function::f::@parameter::b
staticType: A
alias: self::@typeAlias::B
staticElement: self::@class::A::@method::call
staticType: void Function()
''');
}
test_simpleIdentifier_typeVariable() async {
await assertNoErrorsInCode('''
class A {
void call() {}
}
Function f<X extends A>(X x) => x;
''');
final node = findNode.implicitCallReference('x;');
assertResolvedNodeText(node, r'''
ImplicitCallReference
expression: SimpleIdentifier
token: x
staticElement: self::@function::f::@parameter::x
staticType: X
staticElement: self::@class::A::@method::call
staticType: void Function()
''');
}
test_simpleIdentifier_typeVariable2() async {
await assertNoErrorsInCode('''
class A {
void call() {}
}
Function f<X extends A, Y extends X>(Y y) => y;
''');
final node = findNode.implicitCallReference('y;');
assertResolvedNodeText(node, r'''
ImplicitCallReference
expression: SimpleIdentifier
token: y
staticElement: self::@function::f::@parameter::y
staticType: Y
staticElement: self::@class::A::@method::call
staticType: void Function()
''');
}
}