Issue 51718. Support for function expression invocation on RecordType(s).
Bug: https://github.com/dart-lang/sdk/issues/51718
Change-Id: I1f4b52eb6f5a741b77b2d1b5e7d9131531c4c00a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/289740
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
index 331cb62..5168a31 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
@@ -48,29 +48,17 @@
}
var receiverType = function.typeOrThrow;
- if (receiverType is InterfaceType) {
- // Note: in this circumstance it's not necessary to call
- // `_nullableDereferenceVerifier.expression` because
- // `_resolveReceiverInterfaceType` calls `TypePropertyResolver.resolve`,
- // which does the necessary null checking.
- _resolveReceiverInterfaceType(
- node, function, receiverType, whyNotPromotedList,
- contextType: contextType);
- return;
- }
-
if (_checkForUseOfVoidResult(function, receiverType)) {
_unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList,
contextType: contextType);
return;
}
- _nullableDereferenceVerifier.expression(
- CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE,
- function,
- );
-
if (receiverType is FunctionType) {
+ _nullableDereferenceVerifier.expression(
+ CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE,
+ function,
+ );
_resolve(node, receiverType, whyNotPromotedList,
contextType: contextType);
return;
@@ -84,8 +72,40 @@
return;
}
- _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList,
- contextType: contextType);
+ var result = _typePropertyResolver.resolve(
+ receiver: function,
+ receiverType: receiverType,
+ name: FunctionElement.CALL_METHOD_NAME,
+ propertyErrorEntity: function,
+ nameErrorEntity: function,
+ );
+ var callElement = result.getter;
+
+ if (callElement == null) {
+ if (result.needsGetterError) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION,
+ function,
+ );
+ }
+ _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList,
+ contextType: contextType);
+ return;
+ }
+
+ if (callElement.kind != ElementKind.METHOD) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION,
+ function,
+ );
+ _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList,
+ contextType: contextType);
+ return;
+ }
+
+ node.staticElement = callElement;
+ var rawType = callElement.type;
+ _resolve(node, rawType, whyNotPromotedList, contextType: contextType);
}
/// Check for situations where the result of a method or function is used,
@@ -158,48 +178,6 @@
_resolve(node, rawType, whyNotPromotedList, contextType: contextType);
}
- void _resolveReceiverInterfaceType(
- FunctionExpressionInvocationImpl node,
- Expression function,
- InterfaceType receiverType,
- List<WhyNotPromotedGetter> whyNotPromotedList,
- {required DartType? contextType}) {
- var result = _typePropertyResolver.resolve(
- receiver: function,
- receiverType: receiverType,
- name: FunctionElement.CALL_METHOD_NAME,
- propertyErrorEntity: function,
- nameErrorEntity: function,
- );
- var callElement = result.getter;
-
- if (callElement == null) {
- if (result.needsGetterError) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION,
- function,
- );
- }
- _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList,
- contextType: contextType);
- return;
- }
-
- if (callElement.kind != ElementKind.METHOD) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION,
- function,
- );
- _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList,
- contextType: contextType);
- return;
- }
-
- node.staticElement = callElement;
- var rawType = callElement.type;
- _resolve(node, rawType, whyNotPromotedList, contextType: contextType);
- }
-
void _unresolved(FunctionExpressionInvocationImpl node, DartType type,
List<WhyNotPromotedGetter> whyNotPromotedList,
{required DartType? contextType}) {
diff --git a/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart
index 386bd8c..4c43c19 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart
@@ -273,6 +273,100 @@
''');
}
+ test_expression_interfaceType_nullable_hasCall() async {
+ await assertNoErrorsInCode(r'''
+void f(int? a) {
+ a();
+}
+
+extension on int? {
+ int call() => 0;
+}
+''');
+ final node = findNode.functionExpressionInvocation('();');
+ assertResolvedNodeText(node, r'''
+FunctionExpressionInvocation
+ function: SimpleIdentifier
+ token: a
+ staticElement: self::@function::f::@parameter::a
+ staticType: int?
+ argumentList: ArgumentList
+ leftParenthesis: (
+ rightParenthesis: )
+ staticElement: self::@extension::0::@method::call
+ staticInvokeType: int Function()
+ staticType: int
+''');
+ }
+
+ test_expression_recordType_hasCall() async {
+ await assertNoErrorsInCode(r'''
+void f() {
+ (int, String)();
+}
+
+extension on (Type, Type) {
+ int call() => 0;
+}
+''');
+ final node = findNode.functionExpressionInvocation('();');
+ assertResolvedNodeText(node, r'''
+FunctionExpressionInvocation
+ function: RecordLiteral
+ leftParenthesis: (
+ fields
+ SimpleIdentifier
+ token: int
+ staticElement: dart:core::@class::int
+ staticType: Type
+ SimpleIdentifier
+ token: String
+ staticElement: dart:core::@class::String
+ staticType: Type
+ rightParenthesis: )
+ staticType: (Type, Type)
+ argumentList: ArgumentList
+ leftParenthesis: (
+ rightParenthesis: )
+ staticElement: self::@extension::0::@method::call
+ staticInvokeType: int Function()
+ staticType: int
+''');
+ }
+
+ test_expression_recordType_noCall() async {
+ await assertErrorsInCode(r'''
+void f() {
+ (bool, String)();
+}
+''', [
+ error(CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, 13, 14),
+ ]);
+ final node = findNode.functionExpressionInvocation('();');
+ assertResolvedNodeText(node, r'''
+FunctionExpressionInvocation
+ function: RecordLiteral
+ leftParenthesis: (
+ fields
+ SimpleIdentifier
+ token: bool
+ staticElement: dart:core::@class::bool
+ staticType: Type
+ SimpleIdentifier
+ token: String
+ staticElement: dart:core::@class::String
+ staticType: Type
+ rightParenthesis: )
+ staticType: (Type, Type)
+ argumentList: ArgumentList
+ leftParenthesis: (
+ rightParenthesis: )
+ staticElement: <null>
+ staticInvokeType: dynamic
+ staticType: dynamic
+''');
+ }
+
test_never() async {
await assertErrorsInCode(r'''
void f(Never x) {