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) {