Skip to content

Commit 63399a9

Browse files
srawlinsCommit Queue
authored and
Commit Queue
committed
analyzer: Support implicit call tearoff from type variable
Fixes #54353 Change-Id: I0b7725efb6380de35832f1a713df3b4139990f0b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/346947 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent 6f97eb2 commit 63399a9

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

pkg/analyzer/lib/src/generated/error_detection_helpers.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,14 @@ mixin ErrorDetectionHelpers {
293293
/// > is a function type or the type `Function`, `e` is treated as `e.call`.
294294
MethodElement? getImplicitCallMethod(
295295
DartType type, DartType? context, SyntacticEntity errorNode) {
296+
var visitedTypes = {type};
297+
while (type is TypeParameterType) {
298+
type = type.bound;
299+
if (!visitedTypes.add(type)) {
300+
// A cycle!
301+
return null;
302+
}
303+
}
296304
if (context != null &&
297305
typeSystem.acceptsFunctionType(context) &&
298306
type is InterfaceType &&

pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,68 @@ ImplicitCallReference
538538
staticType: C
539539
staticElement: self::@class::C::@method::call
540540
staticType: void Function(int)
541+
''');
542+
}
543+
544+
test_simpleIdentifier_typeAlias() async {
545+
await assertNoErrorsInCode('''
546+
class A {
547+
void call() {}
548+
}
549+
typedef B = A;
550+
Function f(B b) => b;
551+
''');
552+
553+
final node = findNode.implicitCallReference('b;');
554+
assertResolvedNodeText(node, r'''
555+
ImplicitCallReference
556+
expression: SimpleIdentifier
557+
token: b
558+
staticElement: self::@function::f::@parameter::b
559+
staticType: A
560+
alias: self::@typeAlias::B
561+
staticElement: self::@class::A::@method::call
562+
staticType: void Function()
563+
''');
564+
}
565+
566+
test_simpleIdentifier_typeVariable() async {
567+
await assertNoErrorsInCode('''
568+
class A {
569+
void call() {}
570+
}
571+
Function f<X extends A>(X x) => x;
572+
''');
573+
574+
final node = findNode.implicitCallReference('x;');
575+
assertResolvedNodeText(node, r'''
576+
ImplicitCallReference
577+
expression: SimpleIdentifier
578+
token: x
579+
staticElement: self::@function::f::@parameter::x
580+
staticType: X
581+
staticElement: self::@class::A::@method::call
582+
staticType: void Function()
583+
''');
584+
}
585+
586+
test_simpleIdentifier_typeVariable2() async {
587+
await assertNoErrorsInCode('''
588+
class A {
589+
void call() {}
590+
}
591+
Function f<X extends A, Y extends X>(Y y) => y;
592+
''');
593+
594+
final node = findNode.implicitCallReference('y;');
595+
assertResolvedNodeText(node, r'''
596+
ImplicitCallReference
597+
expression: SimpleIdentifier
598+
token: y
599+
staticElement: self::@function::f::@parameter::y
600+
staticType: Y
601+
staticElement: self::@class::A::@method::call
602+
staticType: void Function()
541603
''');
542604
}
543605
}

0 commit comments

Comments
 (0)