[analyzer] Dot shorthands: Refactoring MethodInvocationResolver to handle dot shorthands.

This is the base preliminary work for resolving dot shorthand invocations. I'll be calling `resolveDotShorthand` from the `Resolver` in a future CL.

Dot shorthand invocation resolution is very similar to normal MethodInvocation resolution, with a few exceptions (like no `target` expression), so it made sense to re-use the logic we had in the `MethodInvocationResolver`.

I refactored `_rewriteAsFunctionExpressionInvocation` heavily to support both dot shorthands and method invocations, which involved pulling out all of the members into parameters.

Most `_report<some error>` methods were refactored to support dot shorthands as well. Half of them called `_setInvalidTypeResolution` and that ended up just being invoked at the call site rather than in the report helper itself.

Dot shorthands has a very basic `DotShorthandInvocationInferrer` in this CL. None of the overrides for a `MethodInvocationInferrer` seemed to apply since we don't have a target.

No tests yet. Tests will be added once I make the next CL that calls this `resolveDotShorthand` entry point.

Bug: https://github.com/dart-lang/sdk/issues/59835
Change-Id: I8ebeb772c30c88b85ae68d805e062accb1d6d17d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/421560
Commit-Queue: Kallen Tu <kallentu@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
index cbfd50c..eb6e8de 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
@@ -155,6 +155,27 @@
     return tearOffType;
   }
 
+  /// Finish resolution of the [DotShorthandInvocation].
+  ///
+  /// We have already found the invoked [ExecutableElement2], and the [rawType]
+  /// is its not yet instantiated type. Here we perform downwards inference,
+  /// resolution of arguments, and upwards inference.
+  void resolveDotShorthandInvocation({
+    required DotShorthandInvocationImpl node,
+    required FunctionTypeImpl rawType,
+    required List<WhyNotPromotedGetter> whyNotPromotedArguments,
+    required TypeImpl contextType,
+  }) {
+    var returnType = DotShorthandInvocationInferrer(
+      resolver: _resolver,
+      node: node,
+      argumentList: node.argumentList,
+      contextType: contextType,
+      whyNotPromotedArguments: whyNotPromotedArguments,
+    ).resolveInvocation(rawType: rawType);
+    node.recordStaticType(returnType, resolver: _resolver);
+  }
+
   /// Finish resolution of the [MethodInvocation].
   ///
   /// We have already found the invoked [ExecutableElement2], and the [rawType]
@@ -162,7 +183,7 @@
   /// resolution of arguments, and upwards inference.
   void resolveMethodInvocation({
     required MethodInvocationImpl node,
-    required FunctionType rawType,
+    required FunctionTypeImpl rawType,
     required List<WhyNotPromotedGetter> whyNotPromotedArguments,
     required TypeImpl contextType,
   }) {
@@ -172,11 +193,7 @@
       argumentList: node.argumentList,
       contextType: contextType,
       whyNotPromotedArguments: whyNotPromotedArguments,
-    ).resolveInvocation(
-        // TODO(paulberry): eliminate this cast by changing the type of
-        // `rawType`.
-        rawType: rawType as FunctionTypeImpl);
-
+    ).resolveInvocation(rawType: rawType);
     node.recordStaticType(returnType, resolver: _resolver);
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
index 43bce49..ef78b1a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
@@ -132,6 +132,19 @@
 }
 
 /// Specialization of [InvocationInferrer] for performing type inference on AST
+/// nodes of type [DotShorthandInvocation].
+class DotShorthandInvocationInferrer
+    extends InvocationExpressionInferrer<DotShorthandInvocationImpl> {
+  DotShorthandInvocationInferrer(
+      {required super.resolver,
+      required super.node,
+      required super.argumentList,
+      required super.contextType,
+      required super.whyNotPromotedArguments})
+      : super._();
+}
+
+/// Specialization of [InvocationInferrer] for performing type inference on AST
 /// nodes that require full downward and upward inference.
 abstract class FullInvocationInferrer<Node extends AstNodeImpl>
     extends InvocationInferrer<Node> {
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index cffeee3..d21fb245 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -4,6 +4,7 @@
 
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
 import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
+import 'package:analyzer/dart/ast/token.dart' show Token;
 import 'package:analyzer/dart/element/element2.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart';
@@ -159,8 +160,10 @@
     }
 
     if (receiverType is VoidType) {
-      _reportUseOfVoidType(node, receiver, whyNotPromotedArguments,
+      _setInvalidTypeResolution(node,
+          whyNotPromotedArguments: whyNotPromotedArguments,
           contextType: contextType);
+      _reportUseOfVoidType(receiver);
       return null;
     }
 
@@ -197,6 +200,24 @@
     );
   }
 
+  /// Resolves the dot shorthand invocation, [node].
+  ///
+  /// If [node] is rewritten to be a [FunctionExpressionInvocation] in the
+  /// process, then returns that new node. Otherwise, returns `null`.
+  FunctionExpressionInvocationImpl? resolveDotShorthand(
+      DotShorthandInvocationImpl node,
+      List<WhyNotPromotedGetter> whyNotPromotedArguments) {
+    var contextType = _resolver.getDotShorthandContext().unwrapTypeSchemaView();
+    // TODO(kallentu): Dot shorthands work - Support other context types
+    if (contextType is InterfaceTypeImpl) {
+      var contextElement = contextType.element3;
+      return _resolveReceiverTypeLiteralForDotShorthand(node, contextElement,
+          node.memberName, node.memberName.name, whyNotPromotedArguments,
+          contextType: contextType);
+    }
+    return null;
+  }
+
   bool _hasMatchingObjectMethod(
       MethodElement2 target, NodeListImpl<ExpressionImpl> arguments) {
     return arguments.length == target.formalParameters.length &&
@@ -258,17 +279,11 @@
     }
   }
 
-  void _reportInvocationOfNonFunction(MethodInvocationImpl node,
-      List<WhyNotPromotedGetter> whyNotPromotedArguments,
-      {required TypeImpl contextType}) {
-    _setInvalidTypeResolution(node,
-        setNameTypeToDynamic: false,
-        whyNotPromotedArguments: whyNotPromotedArguments,
-        contextType: contextType);
+  void _reportInvocationOfNonFunction(SimpleIdentifierImpl methodName) {
     _resolver.errorReporter.atNode(
-      node.methodName,
+      methodName,
       CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION,
-      arguments: [node.methodName.name],
+      arguments: [methodName.name],
     );
   }
 
@@ -313,18 +328,52 @@
     );
   }
 
-  void _reportUseOfVoidType(MethodInvocationImpl node, AstNode errorNode,
-      List<WhyNotPromotedGetter> whyNotPromotedArguments,
-      {required TypeImpl contextType}) {
-    _setInvalidTypeResolution(node,
-        whyNotPromotedArguments: whyNotPromotedArguments,
-        contextType: contextType);
+  void _reportUndefinedMethodOrNew(
+      InterfaceElement2 receiver, SimpleIdentifierImpl methodName) {
+    if (methodName.name == 'new') {
+      // Attempting to invoke the unnamed constructor via `C.new(`.
+      if (_resolver.isConstructorTearoffsEnabled) {
+        _resolver.errorReporter.atNode(
+          methodName,
+          CompileTimeErrorCode.NEW_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT,
+          arguments: [receiver.displayName],
+        );
+      } else {
+        // [ParserErrorCode.EXPERIMENT_NOT_ENABLED] is reported by the parser.
+        // Do not report extra errors.
+      }
+    } else {
+      _resolver.errorReporter.atNode(
+        methodName,
+        CompileTimeErrorCode.UNDEFINED_METHOD,
+        arguments: [methodName.name, receiver.displayName],
+      );
+    }
+  }
+
+  void _reportUseOfVoidType(AstNode errorNode) {
     _resolver.errorReporter.atNode(
       errorNode,
       CompileTimeErrorCode.USE_OF_VOID_RESULT,
     );
   }
 
+  void _resolveArguments_finishDotShorthandInference(
+      DotShorthandInvocationImpl node,
+      List<WhyNotPromotedGetter> whyNotPromotedArguments,
+      {required TypeImpl contextType}) {
+    var rawType = node.memberName.staticType;
+    DartType staticStaticType = DotShorthandInvocationInferrer(
+            resolver: _resolver,
+            node: node,
+            argumentList: node.argumentList,
+            contextType: contextType,
+            whyNotPromotedArguments: whyNotPromotedArguments)
+        .resolveInvocation(
+            rawType: rawType is FunctionTypeImpl ? rawType : null);
+    node.recordStaticType(staticStaticType, resolver: _resolver);
+  }
+
   void _resolveArguments_finishInference(MethodInvocationImpl node,
       List<WhyNotPromotedGetter> whyNotPromotedArguments,
       {required TypeImpl contextType}) {
@@ -374,7 +423,15 @@
     if (getter != null) {
       nameNode.element = getter;
       _reportStaticAccessToInstanceMember(getter, nameNode);
-      return _rewriteAsFunctionExpressionInvocation(node, getter.returnType);
+      return _rewriteAsFunctionExpressionInvocation(
+          node,
+          node.target,
+          node.operator,
+          node.methodName,
+          node.typeArguments,
+          node.argumentList,
+          getter.returnType,
+          isCascaded: node.isCascaded);
     }
 
     var method = extension.getMethod2(name);
@@ -446,7 +503,15 @@
     nameNode.element = member.asElement2;
 
     if (member is PropertyAccessorElementOrMember) {
-      return _rewriteAsFunctionExpressionInvocation(node, member.returnType);
+      return _rewriteAsFunctionExpressionInvocation(
+          node,
+          node.target,
+          node.operator,
+          node.methodName,
+          node.typeArguments,
+          node.argumentList,
+          member.returnType,
+          isCascaded: node.isCascaded);
     }
 
     _setResolution(node, member.type, whyNotPromotedArguments,
@@ -585,7 +650,15 @@
         element = element.conflictingElements2[0];
       }
       if (element is PropertyAccessorElement2OrMember) {
-        return _rewriteAsFunctionExpressionInvocation(node, element.returnType);
+        return _rewriteAsFunctionExpressionInvocation(
+            node,
+            node.target,
+            node.operator,
+            node.methodName,
+            node.typeArguments,
+            node.argumentList,
+            element.returnType,
+            isCascaded: node.isCascaded);
       }
       if (element is ExecutableElement2OrMember) {
         _setResolution(node, element.type, whyNotPromotedArguments,
@@ -596,7 +669,15 @@
         _resolver.checkReadOfNotAssignedLocalVariable(nameNode, element);
         var targetType =
             _localVariableTypeProvider.getType(nameNode, isRead: true);
-        return _rewriteAsFunctionExpressionInvocation(node, targetType);
+        return _rewriteAsFunctionExpressionInvocation(
+            node,
+            node.target,
+            node.operator,
+            node.methodName,
+            node.typeArguments,
+            node.argumentList,
+            targetType,
+            isCascaded: node.isCascaded);
       }
       // TODO(scheglov): This is a questionable distinction.
       if (element is PrefixElement2) {
@@ -606,8 +687,11 @@
         _reportPrefixIdentifierNotFollowedByDot(nameNode);
         return null;
       }
-      _reportInvocationOfNonFunction(node, whyNotPromotedArguments,
+      _setInvalidTypeResolution(node,
+          setNameTypeToDynamic: false,
+          whyNotPromotedArguments: whyNotPromotedArguments,
           contextType: contextType);
+      _reportInvocationOfNonFunction(node.methodName);
       return null;
     }
 
@@ -712,7 +796,15 @@
     }
 
     if (element is PropertyAccessorElement2OrMember) {
-      return _rewriteAsFunctionExpressionInvocation(node, element.returnType);
+      return _rewriteAsFunctionExpressionInvocation(
+          node,
+          node.target,
+          node.operator,
+          node.methodName,
+          node.typeArguments,
+          node.argumentList,
+          element.returnType,
+          isCascaded: node.isCascaded);
     }
 
     if (element is ExecutableElement2OrMember) {
@@ -762,7 +854,15 @@
     if (target != null) {
       nameNode.element = target.asElement2;
       if (target is PropertyAccessorElementOrMember) {
-        return _rewriteAsFunctionExpressionInvocation(node, target.returnType,
+        return _rewriteAsFunctionExpressionInvocation(
+            node,
+            node.target,
+            node.operator,
+            node.methodName,
+            node.typeArguments,
+            node.argumentList,
+            target.returnType,
+            isCascaded: node.isCascaded,
             isSuperAccess: true);
       }
       _setResolution(node, target.type, whyNotPromotedArguments,
@@ -847,7 +947,15 @@
 
     var recordField = result.recordField;
     if (recordField != null) {
-      return _rewriteAsFunctionExpressionInvocation(node, recordField.type);
+      return _rewriteAsFunctionExpressionInvocation(
+          node,
+          node.target,
+          node.operator,
+          node.methodName,
+          node.typeArguments,
+          node.argumentList,
+          recordField.type,
+          isCascaded: node.isCascaded);
     }
 
     var target = result.getter2;
@@ -863,7 +971,15 @@
       }
 
       if (target is PropertyAccessorElement2) {
-        return _rewriteAsFunctionExpressionInvocation(node, target.returnType);
+        return _rewriteAsFunctionExpressionInvocation(
+            node,
+            node.target,
+            node.operator,
+            node.methodName,
+            node.typeArguments,
+            node.argumentList,
+            target.returnType,
+            isCascaded: node.isCascaded);
       }
       _setResolution(node, target.type, whyNotPromotedArguments,
           contextType: contextType);
@@ -917,13 +1033,23 @@
         nameNode.element = element;
         if (element is PropertyAccessorElement2OrMember) {
           return _rewriteAsFunctionExpressionInvocation(
-              node, element.returnType);
+              node,
+              node.target,
+              node.operator,
+              node.methodName,
+              node.typeArguments,
+              node.argumentList,
+              element.returnType,
+              isCascaded: node.isCascaded);
         }
         _setResolution(node, element.type, whyNotPromotedArguments,
             contextType: contextType);
       } else {
-        _reportInvocationOfNonFunction(node, whyNotPromotedArguments,
+        _setInvalidTypeResolution(node,
+            setNameTypeToDynamic: false,
+            whyNotPromotedArguments: whyNotPromotedArguments,
             contextType: contextType);
+        _reportInvocationOfNonFunction(nameNode);
       }
       return null;
     }
@@ -931,25 +1057,56 @@
     _setInvalidTypeResolution(node,
         whyNotPromotedArguments: whyNotPromotedArguments,
         contextType: contextType);
-    if (nameNode.name == 'new') {
-      // Attempting to invoke the unnamed constructor via `C.new(`.
-      if (_resolver.isConstructorTearoffsEnabled) {
-        _resolver.errorReporter.atNode(
-          nameNode,
-          CompileTimeErrorCode.NEW_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT,
-          arguments: [receiver.displayName],
-        );
+    _reportUndefinedMethodOrNew(receiver, nameNode);
+    return null;
+  }
+
+  /// Resolves the dot shorthand invocation, [node], as an method invocation
+  /// with a type literal target.
+  ///
+  /// If [node] is rewritten to be a [FunctionExpressionInvocation] in the
+  /// process, then returns that new node. Otherwise, returns `null`.
+  FunctionExpressionInvocationImpl? _resolveReceiverTypeLiteralForDotShorthand(
+      DotShorthandInvocationImpl node,
+      InterfaceElement2 receiver,
+      SimpleIdentifierImpl nameNode,
+      String name,
+      List<WhyNotPromotedGetter> whyNotPromotedArguments,
+      {required TypeImpl contextType}) {
+    var element = _resolveElement(receiver, node.memberName);
+    if (element != null) {
+      if (element is ExecutableElement2OrMember) {
+        node.memberName.element = element;
+        if (element is PropertyAccessorElement2OrMember) {
+          return _rewriteAsFunctionExpressionInvocation(
+              node,
+              null,
+              node.period,
+              node.memberName,
+              node.typeArguments,
+              node.argumentList,
+              element.returnType,
+              isCascaded: false);
+        }
+        _setResolutionForDotShorthand(
+            node, element.type, whyNotPromotedArguments,
+            contextType: contextType);
       } else {
-        // [ParserErrorCode.EXPERIMENT_NOT_ENABLED] is reported by the parser.
-        // Do not report extra errors.
+        _setInvalidTypeResolutionForDotShorthand(node,
+            setNameTypeToDynamic: false,
+            whyNotPromotedArguments: whyNotPromotedArguments,
+            contextType: contextType);
+        _reportInvocationOfNonFunction(nameNode);
       }
-    } else {
-      _resolver.errorReporter.atNode(
-        node.methodName,
-        CompileTimeErrorCode.UNDEFINED_METHOD,
-        arguments: [name, receiver.displayName],
-      );
+      return null;
     }
+
+    // TODO(kallentu): Dot shorthands - Could be constructor, replace with
+    // InstanceCreationExpressionImpl.
+    _setInvalidTypeResolutionForDotShorthand(node,
+        whyNotPromotedArguments: whyNotPromotedArguments,
+        contextType: contextType);
+    _reportUndefinedMethodOrNew(receiver, nameNode);
     return null;
   }
 
@@ -961,25 +1118,31 @@
   /// an [InterfaceType]. So, it should be represented as instead as a
   /// [FunctionExpressionInvocation].
   FunctionExpressionInvocationImpl _rewriteAsFunctionExpressionInvocation(
-      MethodInvocationImpl node, TypeImpl getterReturnType,
-      {bool isSuperAccess = false}) {
+      ExpressionImpl node,
+      ExpressionImpl? target,
+      Token? operator,
+      SimpleIdentifierImpl methodName,
+      TypeArgumentListImpl? typeArguments,
+      ArgumentListImpl argumentList,
+      TypeImpl getterReturnType,
+      {required bool isCascaded,
+      bool isSuperAccess = false}) {
     var targetType = getterReturnType;
 
     ExpressionImpl functionExpression;
-    var target = node.target;
     if (target == null) {
-      functionExpression = node.methodName;
-      var element = node.methodName.element;
+      functionExpression = methodName;
+      var element = methodName.element;
       if (element is ExecutableElement2 &&
           element.enclosingElement2 is InstanceElement2 &&
           !element.isStatic) {
         targetType = _resolver.flowAnalysis.flow
                 ?.propertyGet(
                     functionExpression,
-                    node.isCascaded
+                    isCascaded
                         ? CascadePropertyTarget.singleton
                         : ThisPropertyTarget.singleton,
-                    node.methodName.name,
+                    methodName.name,
                     element,
                     SharedTypeView(getterReturnType))
                 ?.unwrapTypeView() ??
@@ -989,14 +1152,14 @@
       if (target is SimpleIdentifierImpl && target.element is PrefixElement2) {
         functionExpression = PrefixedIdentifierImpl(
           prefix: target,
-          period: node.operator!,
-          identifier: node.methodName,
+          period: operator!,
+          identifier: methodName,
         );
       } else {
         functionExpression = PropertyAccessImpl(
           target: target,
-          operator: node.operator!,
-          propertyName: node.methodName,
+          operator: operator!,
+          propertyName: methodName,
         );
       }
       if (target is SuperExpressionImpl) {
@@ -1004,8 +1167,8 @@
                 ?.propertyGet(
                     functionExpression,
                     SuperPropertyTarget.singleton,
-                    node.methodName.name,
-                    node.methodName.element,
+                    methodName.name,
+                    methodName.element,
                     SharedTypeView(getterReturnType))
                 ?.unwrapTypeView() ??
             targetType;
@@ -1014,23 +1177,22 @@
                 ?.propertyGet(
                     functionExpression,
                     ExpressionPropertyTarget(target),
-                    node.methodName.name,
-                    node.methodName.element,
+                    methodName.name,
+                    methodName.element,
                     SharedTypeView(getterReturnType))
                 ?.unwrapTypeView() ??
             targetType;
       }
       functionExpression.setPseudoExpressionStaticType(targetType);
     }
-    inferenceLogWriter
-        ?.enterFunctionExpressionInvocationTarget(node.methodName);
-    node.methodName.recordStaticType(targetType, resolver: _resolver);
-    inferenceLogWriter?.exitExpression(node.methodName);
+    inferenceLogWriter?.enterFunctionExpressionInvocationTarget(methodName);
+    methodName.recordStaticType(targetType, resolver: _resolver);
+    inferenceLogWriter?.exitExpression(methodName);
 
     var invocation = FunctionExpressionInvocationImpl(
       function: functionExpression,
-      typeArguments: node.typeArguments,
-      argumentList: node.argumentList,
+      typeArguments: typeArguments,
+      argumentList: argumentList,
     );
     _resolver.replaceExpression(node, invocation);
     _resolver.flowAnalysis.transferTestData(node, invocation);
@@ -1051,6 +1213,20 @@
         contextType: contextType);
   }
 
+  void _setDynamicTypeResolutionForDotShorthand(DotShorthandInvocationImpl node,
+      {bool setNameTypeToDynamic = true,
+      required List<WhyNotPromotedGetter> whyNotPromotedArguments,
+      required TypeImpl contextType}) {
+    if (setNameTypeToDynamic) {
+      node.memberName.setPseudoExpressionStaticType(_dynamicType);
+    }
+    node.staticInvokeType = _dynamicType;
+    node.setPseudoExpressionStaticType(_dynamicType);
+    _setExplicitTypeArgumentTypes();
+    _resolveArguments_finishDotShorthandInference(node, whyNotPromotedArguments,
+        contextType: contextType);
+  }
+
   /// Set explicitly specified type argument types, or empty if not specified.
   /// Inference is done in type analyzer, so inferred type arguments might be
   /// set later.
@@ -1081,6 +1257,20 @@
     node.setPseudoExpressionStaticType(InvalidTypeImpl.instance);
   }
 
+  void _setInvalidTypeResolutionForDotShorthand(DotShorthandInvocationImpl node,
+      {bool setNameTypeToDynamic = true,
+      required List<WhyNotPromotedGetter> whyNotPromotedArguments,
+      required TypeImpl contextType}) {
+    if (setNameTypeToDynamic) {
+      node.memberName.setPseudoExpressionStaticType(InvalidTypeImpl.instance);
+    }
+    _setExplicitTypeArgumentTypes();
+    _resolveArguments_finishDotShorthandInference(node, whyNotPromotedArguments,
+        contextType: contextType);
+    node.staticInvokeType = InvalidTypeImpl.instance;
+    node.setPseudoExpressionStaticType(InvalidTypeImpl.instance);
+  }
+
   void _setResolution(MethodInvocationImpl node, TypeImpl type,
       List<WhyNotPromotedGetter> whyNotPromotedArguments,
       {required TypeImpl contextType}) {
@@ -1111,13 +1301,60 @@
     }
 
     if (type is VoidType) {
-      return _reportUseOfVoidType(
-          node, node.methodName, whyNotPromotedArguments,
+      _setInvalidTypeResolution(node,
+          whyNotPromotedArguments: whyNotPromotedArguments,
           contextType: contextType);
+      return _reportUseOfVoidType(node.methodName);
     }
 
-    _reportInvocationOfNonFunction(node, whyNotPromotedArguments,
+    _setInvalidTypeResolution(node,
+        setNameTypeToDynamic: false,
+        whyNotPromotedArguments: whyNotPromotedArguments,
         contextType: contextType);
+    _reportInvocationOfNonFunction(node.methodName);
+  }
+
+  void _setResolutionForDotShorthand(DotShorthandInvocationImpl node,
+      TypeImpl type, List<WhyNotPromotedGetter> whyNotPromotedArguments,
+      {required TypeImpl contextType}) {
+    inferenceLogWriter?.recordLookupResult(
+        expression: node,
+        type: type,
+        target: null,
+        methodName: node.memberName.name);
+    // TODO(scheglov): We need this for StaticTypeAnalyzer to run inference.
+    // But it seems weird. Do we need to know the raw type of a function?!
+    node.memberName.setPseudoExpressionStaticType(type);
+
+    if (type == _dynamicType || _isCoreFunction(type)) {
+      _setDynamicTypeResolutionForDotShorthand(node,
+          setNameTypeToDynamic: false,
+          whyNotPromotedArguments: whyNotPromotedArguments,
+          contextType: contextType);
+      return;
+    }
+
+    if (type is FunctionTypeImpl) {
+      _inferenceHelper.resolveDotShorthandInvocation(
+          node: node,
+          rawType: type,
+          whyNotPromotedArguments: whyNotPromotedArguments,
+          contextType: contextType);
+      return;
+    }
+
+    if (type is VoidType) {
+      _setInvalidTypeResolutionForDotShorthand(node,
+          whyNotPromotedArguments: whyNotPromotedArguments,
+          contextType: contextType);
+      return _reportUseOfVoidType(node.memberName);
+    }
+
+    _setInvalidTypeResolutionForDotShorthand(node,
+        setNameTypeToDynamic: false,
+        whyNotPromotedArguments: whyNotPromotedArguments,
+        contextType: contextType);
+    _reportInvocationOfNonFunction(node.memberName);
   }
 
   /// Checks whether the given [expression] is a reference to a class. If it is