Consolidate type inference logic for invocations.

Moves all of the analyzer's type inference logic for invocations into
a single `resolveInvocation` method, defined on an abstract base class
`InvocationInferrer`.  There are concrete derived classes to
specialize this logic for all of the types of AST nodes require this
sort of inference (Annotation, ExtensionOverride,
FunctionExpressionInvocation, InstanceCreationExpression,
MethodInvocation, RedirectingConstructorInvocation, and
SuperConstructorInvocation), and the special logic for each node type
is slotted into the core algorithm using virtual dispatch.

In addition to making the code more maintainable by reducing code
duplication, this change paves the way toward modifying the core
algorithm to allow inference information to flow between arguments in
a generic function call
(https://github.com/dart-lang/language/issues/731).

Also partially addresses #48500 (Expression.staticParameterElement
sometimes points to a synthetic element).

Change-Id: I82788d58a62b6555589da16163317b6bbddd53c1
Bug: https://github.com/dart-lang/language/issues/731, https://github.com/dart-lang/sdk/issues/48500
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/234864
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
index 98fe2d9..46980c7 100644
--- a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
@@ -2,36 +2,25 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
-import 'package:analyzer/src/dart/ast/extensions.dart';
-import 'package:analyzer/src/dart/element/member.dart';
-import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/type_algebra.dart';
-import 'package:analyzer/src/dart/resolver/instance_creation_resolver_helper.dart';
 import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inferrer.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 
-class AnnotationResolver with InstanceCreationResolverMixin {
+class AnnotationResolver {
   final ResolverVisitor _resolver;
 
   AnnotationResolver(this._resolver);
 
-  @override
-  ResolverVisitor get resolver => _resolver;
-
   LibraryElement get _definingLibrary => _resolver.definingLibrary;
 
   ErrorReporter get _errorReporter => _resolver.errorReporter;
 
-  bool get _genericMetadataIsEnabled =>
-      _definingLibrary.featureSet.isEnabled(Feature.generic_metadata);
-
   void resolve(
       AnnotationImpl node, List<WhyNotPromotedGetter> whyNotPromotedList) {
     node.typeArguments?.accept(_resolver);
@@ -116,137 +105,35 @@
     constructorElement = _resolver.toLegacyElement(constructorElement);
     constructorName?.staticElement = constructorElement;
     node.element = constructorElement;
+    var annotationInferrer =
+        AnnotationInferrer(constructorName: constructorName);
 
     if (constructorElement == null) {
       _errorReporter.reportErrorForNode(
         CompileTimeErrorCode.INVALID_ANNOTATION,
         node,
       );
-      _resolver.analyzeArgumentList(argumentList, null,
+      annotationInferrer.resolveInvocation(
+          resolver: _resolver,
+          node: node,
+          rawType: null,
+          contextType: null,
           whyNotPromotedList: whyNotPromotedList);
       return;
     }
 
-    // If no type parameters, the elements are correct.
-    if (typeParameters.isEmpty) {
-      var typeArgumentList = node.typeArguments;
-      if (typeArgumentList != null) {
-        _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
-          typeArgumentList,
-          [
-            typeDisplayName,
-            typeParameters.length,
-            typeArgumentList.arguments.length,
-          ],
-        );
-      }
-      _resolveConstructorInvocationArguments(node);
-      _resolver.analyzeArgumentList(argumentList, constructorElement.parameters,
-          whyNotPromotedList: whyNotPromotedList);
-      return;
-    }
-
-    void resolveWithFixedTypeArguments(
-      List<DartType> typeArguments,
-      ConstructorElement constructorElement,
-    ) {
-      var type = instantiateElement(typeArguments);
-      constructorElement = ConstructorMember.from(constructorElement, type);
-      constructorName?.staticElement = constructorElement;
-      node.element = constructorElement;
-      _resolveConstructorInvocationArguments(node);
-
-      _resolver.analyzeArgumentList(argumentList, constructorElement.parameters,
-          whyNotPromotedList: whyNotPromotedList);
-    }
-
-    if (!_genericMetadataIsEnabled) {
-      var typeArguments = List.filled(
-        typeParameters.length,
-        DynamicTypeImpl.instance,
-      );
-      resolveWithFixedTypeArguments(typeArguments, constructorElement);
-      return;
-    }
-
-    var typeArgumentList = node.typeArguments;
-    if (typeArgumentList != null) {
-      List<DartType> typeArguments;
-      if (typeArgumentList.arguments.length == typeParameters.length) {
-        typeArguments = typeArgumentList.arguments
-            .map((element) => element.typeOrThrow)
-            .toList();
-        var substitution = Substitution.fromPairs(
-          typeParameters,
-          typeArguments,
-        );
-        for (var i = 0; i < typeParameters.length; i++) {
-          var typeParameter = typeParameters[i];
-          var bound = typeParameter.bound;
-          if (bound != null) {
-            bound = substitution.substituteType(bound);
-            var typeArgument = typeArguments[i];
-            if (!_resolver.typeSystem.isSubtypeOf(typeArgument, bound)) {
-              _errorReporter.reportErrorForNode(
-                CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
-                typeArgumentList.arguments[i],
-                [typeArgument, typeParameter.name, bound],
-              );
-            }
-          }
-        }
-      } else {
-        _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
-          typeArgumentList,
-          [
-            typeDisplayName,
-            typeParameters.length,
-            typeArgumentList.arguments.length,
-          ],
-        );
-        typeArguments = List.filled(
-          typeParameters.length,
-          DynamicTypeImpl.instance,
-        );
-      }
-      resolveWithFixedTypeArguments(typeArguments, constructorElement);
-      return;
-    }
-
     var elementToInfer = ConstructorElementToInfer(
       typeParameters,
       constructorElement,
     );
-    var inferenceResult = inferArgumentTypes(
-        inferenceNode: node,
-        constructorElement: constructorElement,
-        elementToInfer: elementToInfer,
-        typeArguments: node.typeArguments,
-        arguments: node.arguments!,
-        errorNode: node,
-        isConst: true,
-        contextReturnType: null);
-    if (inferenceResult != null) {
-      constructorElement = inferenceResult.constructorElement;
-    }
-    _resolver.analyzeArgumentList(argumentList, constructorElement.parameters,
-        whyNotPromotedList: whyNotPromotedList);
-
     var constructorRawType = elementToInfer.asType;
 
-    var inferred = _resolver.inferenceHelper.inferGenericInvoke(
-        node, constructorRawType, typeArgumentList, argumentList, node,
-        isConst: true, contextReturnType: null)!;
-
-    constructorElement = ConstructorMember.from(
-      constructorElement,
-      inferred.returnType as InterfaceType,
-    );
-    constructorName?.staticElement = constructorElement;
-    node.element = constructorElement;
-    _resolveConstructorInvocationArguments(node);
+    annotationInferrer.resolveInvocation(
+        resolver: _resolver,
+        node: node,
+        rawType: constructorRawType,
+        contextType: null,
+        whyNotPromotedList: whyNotPromotedList);
   }
 
   void _extensionGetter(
@@ -446,24 +333,6 @@
     }
   }
 
-  void _resolveConstructorInvocationArguments(AnnotationImpl node) {
-    var argumentList = node.arguments;
-    // error will be reported in ConstantVerifier
-    if (argumentList == null) {
-      return;
-    }
-    // resolve arguments to parameters
-    var constructor = node.element;
-    if (constructor is ConstructorElement) {
-      argumentList.correspondingStaticParameters =
-          ResolverVisitor.resolveArgumentsToParameters(
-        argumentList: argumentList,
-        parameters: constructor.parameters,
-        errorReporter: _errorReporter,
-      );
-    }
-  }
-
   void _typeAliasConstructorInvocation(
     AnnotationImpl node,
     TypeAliasElement typeAliasElement,
@@ -530,7 +399,11 @@
       AnnotationImpl node, List<WhyNotPromotedGetter> whyNotPromotedList) {
     var arguments = node.arguments;
     if (arguments != null) {
-      _resolver.analyzeArgumentList(arguments, null,
+      AnnotationInferrer(constructorName: null).resolveInvocation(
+          resolver: _resolver,
+          node: node,
+          rawType: null,
+          contextType: null,
           whyNotPromotedList: whyNotPromotedList);
     }
   }
diff --git a/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart
index 7c09b9d..db7e1df 100644
--- a/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart
@@ -97,7 +97,9 @@
     //
     // Otherwise we'll have a ConstructorElement, and we can skip inference
     // because there's nothing to infer in a non-generic type.
-    if (elementToInfer != null) {
+    if (elementToInfer != null &&
+        elementToInfer.typeParameters.isNotEmpty &&
+        constructorName.type.typeArguments == null) {
       // TODO(leafp): Currently, we may re-infer types here, since we
       // sometimes resolve multiple times.  We should really check that we
       // have not already inferred something.  However, the obvious ways to
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 5a75cfd..ddbdfdb 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
@@ -11,6 +11,7 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
 import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inferrer.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/error/nullable_dereference_verifier.dart';
@@ -59,7 +60,8 @@
     }
 
     if (_checkForUseOfVoidResult(function, receiverType)) {
-      _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList);
+      _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList,
+          contextType: contextType);
       return;
     }
 
@@ -77,11 +79,13 @@
     if (identical(receiverType, NeverTypeImpl.instance)) {
       _errorReporter.reportErrorForNode(
           HintCode.RECEIVER_OF_TYPE_NEVER, function);
-      _unresolved(node, NeverTypeImpl.instance, whyNotPromotedList);
+      _unresolved(node, NeverTypeImpl.instance, whyNotPromotedList,
+          contextType: contextType);
       return;
     }
 
-    _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList);
+    _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList,
+        contextType: contextType);
   }
 
   /// Check for situations where the result of a method or function is used,
@@ -111,26 +115,19 @@
   void _resolve(FunctionExpressionInvocationImpl node, FunctionType rawType,
       List<WhyNotPromotedGetter> whyNotPromotedList,
       {required DartType? contextType}) {
-    _inferenceHelper.resolveFunctionExpressionInvocation(
+    var returnType =
+        const FunctionExpressionInvocationInferrer().resolveInvocation(
+      resolver: _resolver,
       node: node,
       rawType: rawType,
       whyNotPromotedList: whyNotPromotedList,
       contextType: contextType,
     );
 
-    var returnType = _inferenceHelper.computeInvokeReturnType(
-      node.staticInvokeType,
-    );
     _inferenceHelper.recordStaticType(node, returnType,
         contextType: contextType);
   }
 
-  void _resolveArguments(FunctionExpressionInvocationImpl node,
-      List<WhyNotPromotedGetter> whyNotPromotedList) {
-    _resolver.analyzeArgumentList(node.argumentList, null,
-        whyNotPromotedList: whyNotPromotedList);
-  }
-
   void _resolveReceiverExtensionOverride(FunctionExpressionInvocationImpl node,
       ExtensionOverride function, List<WhyNotPromotedGetter> whyNotPromotedList,
       {required DartType? contextType}) {
@@ -147,7 +144,8 @@
         function,
         [function.extensionName.name],
       );
-      return _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList);
+      return _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList,
+          contextType: contextType);
     }
 
     if (callElement.isStatic) {
@@ -183,7 +181,8 @@
           function,
         );
       }
-      _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList);
+      _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList,
+          contextType: contextType);
       return;
     }
 
@@ -192,7 +191,8 @@
         CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION,
         function,
       );
-      _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList);
+      _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList,
+          contextType: contextType);
       return;
     }
 
@@ -202,9 +202,15 @@
   }
 
   void _unresolved(FunctionExpressionInvocationImpl node, DartType type,
-      List<WhyNotPromotedGetter> whyNotPromotedList) {
+      List<WhyNotPromotedGetter> whyNotPromotedList,
+      {required DartType? contextType}) {
     _setExplicitTypeArgumentTypes(node);
-    _resolveArguments(node, whyNotPromotedList);
+    const FunctionExpressionInvocationInferrer().resolveInvocation(
+        resolver: _resolver,
+        node: node,
+        rawType: null,
+        contextType: contextType,
+        whyNotPromotedList: whyNotPromotedList);
     node.staticInvokeType = DynamicTypeImpl.instance;
     node.staticType = type;
   }
diff --git a/pkg/analyzer/lib/src/dart/resolver/instance_creation_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/instance_creation_expression_resolver.dart
index e139af8..bfdf73f 100644
--- a/pkg/analyzer/lib/src/dart/resolver/instance_creation_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/instance_creation_expression_resolver.dart
@@ -5,7 +5,7 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
-import 'package:analyzer/src/dart/resolver/instance_creation_resolver_helper.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inferrer.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 
 /// A resolver for [InstanceCreationExpression] nodes.
@@ -14,15 +14,12 @@
 /// [InstanceCreationExpression] as a [MethodInvocation] if the parsed
 /// [ConstructorName]'s `type` resolves to a [FunctionReference] or
 /// [ConstructorReference], instead of a [NamedType].
-class InstanceCreationExpressionResolver with InstanceCreationResolverMixin {
+class InstanceCreationExpressionResolver {
   /// The resolver driving this participant.
   final ResolverVisitor _resolver;
 
   InstanceCreationExpressionResolver(this._resolver);
 
-  @override
-  ResolverVisitor get resolver => _resolver;
-
   void resolve(InstanceCreationExpressionImpl node,
       {required DartType? contextType}) {
     // The parser can parse certain code as [InstanceCreationExpression] when it
@@ -60,32 +57,20 @@
     constructorName.accept(_resolver);
     // Re-assign constructorName in case the node got replaced.
     constructorName = node.constructorName;
+    _resolver.elementResolver.visitInstanceCreationExpression(node);
     var elementToInfer = _resolver.inferenceHelper.constructorElementToInfer(
       constructorName: constructorName,
       definingLibrary: _resolver.definingLibrary,
     );
-    var typeName = constructorName.type;
-    var constructorElement = constructorName.staticElement;
-    var inferenceResult = inferArgumentTypes(
-        inferenceNode: node,
-        constructorElement: constructorElement,
-        elementToInfer: elementToInfer,
-        typeArguments: typeName.typeArguments,
-        arguments: node.argumentList,
-        errorNode: constructorName,
-        isConst: node.isConst,
-        contextReturnType: contextType);
-    if (inferenceResult != null) {
-      typeName.type = inferenceResult.constructedType;
-      constructorElement =
-          constructorName.staticElement = inferenceResult.constructorElement;
-    }
-    _resolver.analyzeArgumentList(
-        node.argumentList, constructorElement?.parameters,
+    const InstanceCreationInferrer().resolveInvocation(
+        resolver: _resolver,
+        node: node,
+        rawType: elementToInfer?.asType,
+        contextType: contextType,
         whyNotPromotedList: whyNotPromotedList);
-    _resolver.elementResolver.visitInstanceCreationExpression(node);
-    _resolver.typeAnalyzer
-        .visitInstanceCreationExpression(node, contextType: contextType);
+    _resolver.inferenceHelper.recordStaticType(
+        node, node.constructorName.type.type!,
+        contextType: contextType);
     _resolver.checkForArgumentTypesNotAssignableInList(
         node.argumentList, whyNotPromotedList);
   }
diff --git a/pkg/analyzer/lib/src/dart/resolver/instance_creation_resolver_helper.dart b/pkg/analyzer/lib/src/dart/resolver/instance_creation_resolver_helper.dart
deleted file mode 100644
index 0f99c2d..0000000
--- a/pkg/analyzer/lib/src/dart/resolver/instance_creation_resolver_helper.dart
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/ast/ast.dart';
-import 'package:analyzer/src/dart/element/member.dart';
-import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
-import 'package:analyzer/src/generated/resolver.dart';
-
-/// Data constructor containing information about the result of performing type
-/// inference on an instance creation (either an InstanceCreationExpression or
-/// an Annotation that refers to a constructor).
-class InstanceCreationInferenceResult {
-  /// The refined constructor element (after type inference)
-  final ConstructorElement constructorElement;
-
-  /// The type that was constructed (after type inference)
-  final DartType constructedType;
-
-  InstanceCreationInferenceResult(
-      {required this.constructorElement, required this.constructedType});
-}
-
-/// Mixin containing shared functionality for resolving AST nodes that may
-/// create instances (InstanceCreationExpression and Annotation).
-mixin InstanceCreationResolverMixin {
-  ResolverVisitor get resolver;
-
-  /// Performs the first step of type inference for a constructor invocation.
-  InstanceCreationInferenceResult? inferArgumentTypes(
-      {required AstNode inferenceNode,
-      required ConstructorElement? constructorElement,
-      required ConstructorElementToInfer? elementToInfer,
-      required TypeArgumentListImpl? typeArguments,
-      required ArgumentListImpl arguments,
-      required AstNode errorNode,
-      required bool isConst,
-      required DartType? contextReturnType}) {
-    InstanceCreationInferenceResult? inferenceResult;
-    FunctionType? inferred;
-
-    // If the constructor is generic, we'll have a ConstructorMember that
-    // substitutes in type arguments (possibly `dynamic`) from earlier in
-    // resolution.
-    //
-    // Otherwise we'll have a ConstructorElement, and we can skip inference
-    // because there's nothing to infer in a non-generic type.
-    if (elementToInfer != null) {
-      // TODO(leafp): Currently, we may re-infer types here, since we
-      // sometimes resolve multiple times.  We should really check that we
-      // have not already inferred something.  However, the obvious ways to
-      // check this don't work, since we may have been instantiated
-      // to bounds in an earlier phase, and we *do* want to do inference
-      // in that case.
-
-      // Get back to the uninstantiated generic constructor.
-      // TODO(jmesserly): should we store this earlier in resolution?
-      // Or look it up, instead of jumping backwards through the Member?
-      var rawElement = elementToInfer.element;
-      var constructorType = elementToInfer.asType;
-
-      inferred = resolver.inferenceHelper.inferArgumentTypesForGeneric(
-          inferenceNode, constructorType, typeArguments,
-          isConst: isConst,
-          errorNode: errorNode,
-          contextReturnType: contextReturnType);
-
-      if (inferred != null) {
-        // Fix up the parameter elements based on inferred method.
-        arguments.correspondingStaticParameters =
-            ResolverVisitor.resolveArgumentsToParameters(
-          argumentList: arguments,
-          parameters: inferred.parameters,
-        );
-
-        // Update the static element as well. This is used in some cases, such
-        // as computing constant values. It is stored in two places.
-        constructorElement = ConstructorMember.from(
-          rawElement,
-          inferred.returnType as InterfaceType,
-        );
-        inferenceResult = InstanceCreationInferenceResult(
-            constructorElement: constructorElement,
-            constructedType: inferred.returnType);
-      }
-    }
-
-    if (inferred == null) {
-      if (constructorElement != null) {
-        var type = constructorElement.type;
-        type = resolver.toLegacyTypeIfOptOut(type) as FunctionType;
-      }
-    }
-
-    return inferenceResult;
-  }
-}
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 1e5f7a6..945c794 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
@@ -9,12 +9,10 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
-import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
-import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inferrer.dart';
 import 'package:analyzer/src/generated/migration.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 
@@ -46,12 +44,15 @@
   /// For example given the type `class C<T> { C(T arg); }`, the generic
   /// function type is `<T>(T) -> C<T>`.
   FunctionType get asType {
-    return FunctionTypeImpl(
-      typeFormals: typeParameters,
-      parameters: element.parameters,
-      returnType: element.returnType,
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
+    var typeParameters = this.typeParameters;
+    return typeParameters.isEmpty
+        ? element.type
+        : FunctionTypeImpl(
+            typeFormals: typeParameters,
+            parameters: element.parameters,
+            returnType: element.returnType,
+            nullabilitySuffix: NullabilitySuffix.none,
+          );
   }
 }
 
@@ -62,9 +63,6 @@
   final MigrationResolutionHooks? _migrationResolutionHooks;
   final bool _genericMetadataIsEnabled;
 
-  List<DartType>? _typeArgumentTypes;
-  FunctionType? _invokeType;
-
   InvocationInferenceHelper({
     required ResolverVisitor resolver,
     required ErrorReporter errorReporter,
@@ -77,16 +75,6 @@
         _genericMetadataIsEnabled = resolver.definingLibrary.featureSet
             .isEnabled(Feature.generic_metadata);
 
-  /// Compute the return type of the method or function represented by the given
-  /// type that is being invoked.
-  DartType computeInvokeReturnType(DartType? type) {
-    if (type is FunctionType) {
-      return type.returnType;
-    } else {
-      return DynamicTypeImpl.instance;
-    }
-  }
-
   /// If the constructor referenced by the [constructorName] is generic,
   /// and the [constructorName] does not have explicit type arguments,
   /// return the element and type parameters to infer. Otherwise return `null`.
@@ -94,159 +82,44 @@
     required ConstructorName constructorName,
     required LibraryElement definingLibrary,
   }) {
-    List<TypeParameterElement>? typeParameters;
+    List<TypeParameterElement> typeParameters;
     ConstructorElement? rawElement;
 
     var typeName = constructorName.type;
-    var typeArguments = typeName.typeArguments;
     var typeElement = typeName.name.staticElement;
     if (typeElement is ClassElement) {
       typeParameters = typeElement.typeParameters;
-      if (typeParameters.isNotEmpty && typeArguments == null) {
-        var constructorIdentifier = constructorName.name;
-        if (constructorIdentifier == null) {
-          rawElement = typeElement.unnamedConstructor;
-        } else {
-          var name = constructorIdentifier.name;
-          rawElement = typeElement.getNamedConstructor(name);
-          if (rawElement != null &&
-              !rawElement.isAccessibleIn(definingLibrary)) {
-            rawElement = null;
-          }
+      var constructorIdentifier = constructorName.name;
+      if (constructorIdentifier == null) {
+        rawElement = typeElement.unnamedConstructor;
+      } else {
+        var name = constructorIdentifier.name;
+        rawElement = typeElement.getNamedConstructor(name);
+        if (rawElement != null && !rawElement.isAccessibleIn(definingLibrary)) {
+          rawElement = null;
         }
       }
     } else if (typeElement is TypeAliasElement) {
       typeParameters = typeElement.typeParameters;
       var aliasedType = typeElement.aliasedType;
       if (aliasedType is InterfaceType) {
-        if (typeParameters.isNotEmpty && typeArguments == null) {
-          var constructorIdentifier = constructorName.name;
-          rawElement = aliasedType.lookUpConstructor(
-            constructorIdentifier?.name,
-            definingLibrary,
-          );
-        }
+        var constructorIdentifier = constructorName.name;
+        rawElement = aliasedType.lookUpConstructor(
+          constructorIdentifier?.name,
+          definingLibrary,
+        );
       }
+    } else {
+      return null;
     }
 
-    if (typeParameters == null || rawElement == null) {
+    if (rawElement == null) {
       return null;
     }
     rawElement = _resolver.toLegacyElement(rawElement);
     return ConstructorElementToInfer(typeParameters, rawElement);
   }
 
-  FunctionType? inferArgumentTypesForGeneric(AstNode inferenceNode,
-      DartType? uninstantiatedType, TypeArgumentList? typeArguments,
-      {AstNode? errorNode,
-      bool isConst = false,
-      required DartType? contextReturnType}) {
-    errorNode ??= inferenceNode;
-    uninstantiatedType = _getFreshType(uninstantiatedType);
-    if (typeArguments == null &&
-        uninstantiatedType is FunctionType &&
-        uninstantiatedType.typeFormals.isNotEmpty) {
-      var typeArguments = _typeSystem.inferGenericFunctionOrType(
-        typeParameters: uninstantiatedType.typeFormals,
-        parameters: const <ParameterElement>[],
-        declaredReturnType: uninstantiatedType.returnType,
-        argumentTypes: const <DartType>[],
-        contextReturnType: contextReturnType,
-        downwards: true,
-        isConst: isConst,
-        errorReporter: _errorReporter,
-        errorNode: errorNode,
-        genericMetadataIsEnabled: _genericMetadataIsEnabled,
-      );
-      if (typeArguments != null) {
-        return uninstantiatedType.instantiate(typeArguments);
-      }
-    }
-    return null;
-  }
-
-  DartType? inferArgumentTypesForInvocation(
-      InvocationExpression node, DartType? type,
-      {required DartType? contextType}) {
-    return inferArgumentTypesForGeneric(node, type, node.typeArguments,
-            contextReturnType: contextType) ??
-        node.staticInvokeType;
-  }
-
-  /// Given a possibly generic invocation like `o.m(args)` or `(f)(args)` try to
-  /// infer the instantiated generic function type.
-  ///
-  /// This takes into account both the context type, as well as information from
-  /// the argument types.
-  void inferGenericInvocationExpression(
-      InvocationExpressionImpl node, DartType? type,
-      {required DartType? contextType}) {
-    var arguments = node.argumentList;
-    var freshType = _getFreshType(type);
-
-    var inferred = inferGenericInvoke(
-        node, freshType, node.typeArguments, arguments, node.function,
-        contextReturnType: contextType);
-    if (inferred != null && inferred != node.staticInvokeType) {
-      // Fix up the parameter elements based on inferred method.
-      arguments.correspondingStaticParameters =
-          ResolverVisitor.resolveArgumentsToParameters(
-        argumentList: arguments,
-        parameters: inferred.parameters,
-      );
-      node.staticInvokeType = inferred;
-    }
-  }
-
-  /// Given a possibly generic invocation or instance creation, such as
-  /// `o.m(args)` or `(f)(args)` or `new T(args)` try to infer the instantiated
-  /// generic function type.
-  ///
-  /// This takes into account both the context type, as well as information from
-  /// the argument types.
-  FunctionType? inferGenericInvoke(
-      AstNode node,
-      DartType? fnType,
-      TypeArgumentList? typeArguments,
-      ArgumentList argumentList,
-      AstNode errorNode,
-      {bool isConst = false,
-      required DartType? contextReturnType}) {
-    if (typeArguments == null &&
-        fnType is FunctionType &&
-        fnType.typeFormals.isNotEmpty) {
-      // Get the parameters that correspond to the uninstantiated generic.
-      var typeArgs = _inferUpwards(
-        rawType: fnType,
-        argumentList: argumentList,
-        contextType: contextReturnType,
-        isConst: isConst,
-        errorNode: errorNode,
-      );
-      if (node is InvocationExpressionImpl) {
-        node.typeArgumentTypes = typeArgs;
-      }
-      if (typeArgs != null) {
-        return fnType.instantiate(typeArgs);
-      }
-      return fnType;
-    }
-
-    // There is currently no other place where we set type arguments
-    // for FunctionExpressionInvocation(s), so set it here, if not inferred.
-    if (node is FunctionExpressionInvocationImpl) {
-      if (typeArguments != null) {
-        var typeArgs =
-            typeArguments.arguments.map((n) => n.typeOrThrow).toList();
-        node.typeArgumentTypes = typeArgs;
-      } else {
-        node.typeArgumentTypes = const <DartType>[];
-      }
-    }
-
-    return null;
-  }
-
   /// Given an uninstantiated generic function type, referenced by the
   /// [identifier] in the tear-off [expression], try to infer the instantiated
   /// generic function type from the surrounding context.
@@ -286,31 +159,6 @@
     }
   }
 
-  /// Finish resolution of the [FunctionExpressionInvocation].
-  ///
-  /// We have already found the invoked [ExecutableElement], and the [rawType]
-  /// is its not yet instantiated type. Here we perform downwards inference,
-  /// resolution of arguments, and upwards inference.
-  void resolveFunctionExpressionInvocation({
-    required FunctionExpressionInvocationImpl node,
-    required FunctionType rawType,
-    required List<WhyNotPromotedGetter> whyNotPromotedList,
-    required DartType? contextType,
-  }) {
-    _resolveInvocation(
-      rawType: rawType,
-      typeArgumentList: node.typeArguments,
-      argumentList: node.argumentList,
-      contextType: contextType,
-      isConst: false,
-      errorNode: node.function,
-      whyNotPromotedList: whyNotPromotedList,
-    );
-
-    node.typeArgumentTypes = _typeArgumentTypes;
-    node.staticInvokeType = _invokeType;
-  }
-
   /// Finish resolution of the [MethodInvocation].
   ///
   /// We have already found the invoked [ExecutableElement], and the [rawType]
@@ -322,245 +170,14 @@
     required List<WhyNotPromotedGetter> whyNotPromotedList,
     required DartType? contextType,
   }) {
-    _resolveInvocation(
+    var returnType = MethodInvocationInferrer.forNode(node).resolveInvocation(
+      resolver: _resolver,
+      node: node,
       rawType: rawType,
-      typeArgumentList: node.typeArguments,
-      argumentList: node.argumentList,
       contextType: contextType,
-      isConst: false,
-      errorNode: node.function,
       whyNotPromotedList: whyNotPromotedList,
     );
 
-    node.typeArgumentTypes = _typeArgumentTypes;
-    node.staticInvokeType = _invokeType;
-
-    var returnType = computeInvokeReturnType(_invokeType);
-    var targetType = node.realTarget?.staticType;
-    if (targetType != null) {
-      returnType = _typeSystem.refineNumericInvocationType(
-        targetType,
-        node.methodName.staticElement,
-        [
-          for (var argument in node.argumentList.arguments) argument.typeOrThrow
-        ],
-        returnType,
-      );
-    }
     recordStaticType(node, returnType, contextType: contextType);
   }
-
-  List<DartType>? _inferDownwards({
-    required FunctionType rawType,
-    required DartType? contextType,
-    required bool isConst,
-    required AstNode errorNode,
-  }) {
-    return _typeSystem.inferGenericFunctionOrType(
-      typeParameters: rawType.typeFormals,
-      parameters: const <ParameterElement>[],
-      declaredReturnType: rawType.returnType,
-      argumentTypes: const <DartType>[],
-      contextReturnType: contextType,
-      downwards: true,
-      isConst: isConst,
-      errorReporter: _errorReporter,
-      errorNode: errorNode,
-      genericMetadataIsEnabled: _genericMetadataIsEnabled,
-    );
-  }
-
-  /// TODO(scheglov) Instead of [isConst] sanitize [contextType] before calling.
-  List<DartType>? _inferUpwards({
-    required FunctionType rawType,
-    required DartType? contextType,
-    required ArgumentList argumentList,
-    required bool isConst,
-    required AstNode errorNode,
-  }) {
-    rawType = _getFreshType(rawType) as FunctionType;
-
-    // Get the parameters that correspond to the uninstantiated generic.
-    List<ParameterElement?> rawParameters =
-        ResolverVisitor.resolveArgumentsToParameters(
-      argumentList: argumentList,
-      parameters: rawType.parameters,
-    );
-
-    List<ParameterElement> params = <ParameterElement>[];
-    List<DartType> argTypes = <DartType>[];
-    for (int i = 0, length = rawParameters.length; i < length; i++) {
-      ParameterElement? parameter = rawParameters[i];
-      if (parameter != null) {
-        params.add(parameter);
-        argTypes.add(argumentList.arguments[i].typeOrThrow);
-      }
-    }
-    var typeArgs = _typeSystem.inferGenericFunctionOrType(
-      typeParameters: rawType.typeFormals,
-      parameters: params,
-      declaredReturnType: rawType.returnType,
-      argumentTypes: argTypes,
-      contextReturnType: contextType,
-      isConst: isConst,
-      errorReporter: _errorReporter,
-      errorNode: errorNode,
-      genericMetadataIsEnabled: _genericMetadataIsEnabled,
-    );
-    return typeArgs;
-  }
-
-  bool _isCallToIdentical(AstNode? invocation) {
-    if (invocation is MethodInvocation) {
-      var invokedMethod = invocation.methodName.staticElement;
-      return invokedMethod != null &&
-          invokedMethod.name == 'identical' &&
-          invokedMethod.library!.isDartCore;
-    }
-    return false;
-  }
-
-  void _resolveArguments(
-      ArgumentList argumentList,
-      List<WhyNotPromotedGetter> whyNotPromotedList,
-      List<ParameterElement> parameters,
-      {required DartType? methodInvocationContext}) {
-    _resolver.analyzeArgumentList(argumentList, parameters,
-        isIdentical: _isCallToIdentical(argumentList.parent),
-        whyNotPromotedList: whyNotPromotedList,
-        methodInvocationContext: methodInvocationContext);
-  }
-
-  void _resolveInvocation({
-    required FunctionType rawType,
-    required DartType? contextType,
-    required TypeArgumentList? typeArgumentList,
-    required ArgumentListImpl argumentList,
-    required bool isConst,
-    required AstNode errorNode,
-    required List<WhyNotPromotedGetter> whyNotPromotedList,
-  }) {
-    if (typeArgumentList != null) {
-      _resolveInvocationWithTypeArguments(
-        rawType: rawType,
-        typeArgumentList: typeArgumentList,
-        argumentList: argumentList,
-        whyNotPromotedList: whyNotPromotedList,
-        methodInvocationContext: contextType,
-      );
-    } else {
-      _resolveInvocationWithoutTypeArguments(
-        rawType: rawType,
-        contextType: contextType,
-        argumentList: argumentList,
-        isConst: isConst,
-        errorNode: errorNode,
-        whyNotPromotedList: whyNotPromotedList,
-      );
-    }
-    _setCorrespondingParameters(argumentList, _invokeType!);
-  }
-
-  void _resolveInvocationWithoutTypeArguments({
-    required FunctionType rawType,
-    required DartType? contextType,
-    required ArgumentList argumentList,
-    required bool isConst,
-    required AstNode errorNode,
-    required List<WhyNotPromotedGetter> whyNotPromotedList,
-  }) {
-    var typeParameters = rawType.typeFormals;
-
-    if (typeParameters.isEmpty) {
-      _resolveArguments(argumentList, whyNotPromotedList, rawType.parameters,
-          methodInvocationContext: contextType);
-
-      _typeArgumentTypes = const <DartType>[];
-      _invokeType = rawType;
-    } else {
-      rawType = _getFreshType(rawType) as FunctionType;
-
-      var downwardsTypeArguments = _inferDownwards(
-        rawType: rawType,
-        contextType: contextType,
-        isConst: isConst,
-        errorNode: errorNode,
-      )!;
-
-      var downwardsInvokeType = rawType.instantiate(downwardsTypeArguments);
-
-      _resolveArguments(
-          argumentList, whyNotPromotedList, downwardsInvokeType.parameters,
-          methodInvocationContext: contextType);
-
-      _typeArgumentTypes = _inferUpwards(
-        rawType: rawType,
-        argumentList: argumentList,
-        contextType: contextType,
-        isConst: isConst,
-        errorNode: errorNode,
-      );
-      _invokeType = rawType.instantiate(_typeArgumentTypes!);
-    }
-  }
-
-  void _resolveInvocationWithTypeArguments({
-    required FunctionType rawType,
-    required TypeArgumentList typeArgumentList,
-    required ArgumentList argumentList,
-    required List<WhyNotPromotedGetter> whyNotPromotedList,
-    required DartType? methodInvocationContext,
-  }) {
-    var typeParameters = rawType.typeFormals;
-
-    List<DartType> typeArguments;
-    if (typeArgumentList.arguments.length != typeParameters.length) {
-      _errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
-        typeArgumentList,
-        [
-          rawType,
-          typeParameters.length,
-          typeArgumentList.arguments.length,
-        ],
-      );
-      typeArguments = List.filled(
-        typeParameters.length,
-        DynamicTypeImpl.instance,
-      );
-    } else {
-      typeArguments = typeArgumentList.arguments
-          .map((typeArgument) => typeArgument.typeOrThrow)
-          .toList(growable: true);
-    }
-
-    var invokeType = rawType.instantiate(typeArguments);
-
-    _resolveArguments(argumentList, whyNotPromotedList, invokeType.parameters,
-        methodInvocationContext: methodInvocationContext);
-
-    _typeArgumentTypes = typeArguments;
-    _invokeType = invokeType;
-  }
-
-  void _setCorrespondingParameters(
-    ArgumentListImpl argumentList,
-    FunctionType invokeType,
-  ) {
-    var parameters = ResolverVisitor.resolveArgumentsToParameters(
-      argumentList: argumentList,
-      parameters: invokeType.parameters,
-      errorReporter: _errorReporter,
-    );
-    argumentList.correspondingStaticParameters = parameters;
-  }
-
-  static DartType? _getFreshType(DartType? type) {
-    if (type is FunctionType) {
-      var parameters = getFreshTypeParameters(type.typeFormals);
-      return parameters.applyToFunctionType(type);
-    } else {
-      return type;
-    }
-  }
 }
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
new file mode 100644
index 0000000..c40a4ff
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
@@ -0,0 +1,545 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:_fe_analyzer_shared/src/base/errors.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/extensions.dart';
+import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_algebra.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+
+/// Specialization of [InvocationInferrer] for performing type inference on AST
+/// nodes of type [Annotation] that resolve to a constructor invocation.
+class AnnotationInferrer extends FullInvocationInferrer<AnnotationImpl> {
+  /// The identifier pointing to the constructor that's being invoked, or `null`
+  /// if a constructor name couldn't be found (should only happen when
+  /// recovering from errors).  If the constructor is generic, this identifier's
+  /// static element will be updated to point to a [ConstructorMember] with type
+  /// arguments filled in.
+  final SimpleIdentifierImpl? constructorName;
+
+  AnnotationInferrer({required this.constructorName}) : super._();
+
+  @override
+  bool get _needsTypeArgumentBoundsCheck => true;
+
+  @override
+  ErrorCode get _wrongNumberOfTypeArgumentsErrorCode =>
+      CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS;
+
+  @override
+  ArgumentListImpl _getArgumentList(AnnotationImpl node) => node.arguments!;
+
+  @override
+  bool _getIsConst(AnnotationImpl node) => true;
+
+  @override
+  TypeArgumentListImpl? _getTypeArguments(AnnotationImpl node) =>
+      node.typeArguments;
+
+  @override
+  bool _isGenericInferenceDisabled(ResolverVisitor resolver) =>
+      !resolver.genericMetadataIsEnabled;
+
+  @override
+  List<ParameterElement>? _storeResult(AnnotationImpl node,
+      List<DartType>? typeArgumentTypes, FunctionType? invokeType) {
+    if (invokeType != null) {
+      var constructorElement = ConstructorMember.from(
+        node.element as ConstructorElement,
+        invokeType.returnType as InterfaceType,
+      );
+      constructorName?.staticElement = constructorElement;
+      node.element = constructorElement;
+      return constructorElement.parameters;
+    }
+    return null;
+  }
+}
+
+/// Specialization of [InvocationInferrer] for performing type inference on AST
+/// nodes of type [ExtensionOverride].
+class ExtensionOverrideInferrer
+    extends InvocationInferrer<ExtensionOverrideImpl> {
+  const ExtensionOverrideInferrer() : super._();
+
+  @override
+  ArgumentListImpl _getArgumentList(ExtensionOverrideImpl node) =>
+      node.argumentList;
+}
+
+/// 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> {
+  const FullInvocationInferrer._() : super._();
+
+  bool get _needsTypeArgumentBoundsCheck => false;
+
+  ErrorCode get _wrongNumberOfTypeArgumentsErrorCode =>
+      CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD;
+
+  @override
+  DartType resolveInvocation({
+    required ResolverVisitor resolver,
+    required Node node,
+    required FunctionType? rawType,
+    required DartType? contextType,
+    required List<WhyNotPromotedGetter> whyNotPromotedList,
+  }) {
+    var typeArgumentList = _getTypeArguments(node);
+
+    List<DartType>? typeArgumentTypes;
+    FunctionType? invokeType;
+    if (_isGenericInferenceDisabled(resolver)) {
+      if (rawType != null && rawType.typeFormals.isNotEmpty) {
+        typeArgumentTypes = List.filled(
+          rawType.typeFormals.length,
+          DynamicTypeImpl.instance,
+        );
+      } else {
+        typeArgumentTypes = const <DartType>[];
+        invokeType = rawType;
+      }
+
+      invokeType = rawType?.instantiate(typeArgumentTypes);
+    } else if (typeArgumentList != null) {
+      if (rawType != null &&
+          typeArgumentList.arguments.length != rawType.typeFormals.length) {
+        var typeParameters = rawType.typeFormals;
+        _reportWrongNumberOfTypeArguments(
+            resolver, typeArgumentList, rawType, typeParameters);
+        typeArgumentTypes = List.filled(
+          typeParameters.length,
+          DynamicTypeImpl.instance,
+        );
+      } else {
+        typeArgumentTypes = typeArgumentList.arguments
+            .map((typeArgument) => typeArgument.typeOrThrow)
+            .toList(growable: true);
+        if (rawType != null && _needsTypeArgumentBoundsCheck) {
+          var typeParameters = rawType.typeFormals;
+          var substitution = Substitution.fromPairs(
+            typeParameters,
+            typeArgumentTypes,
+          );
+          for (var i = 0; i < typeParameters.length; i++) {
+            var typeParameter = typeParameters[i];
+            var bound = typeParameter.bound;
+            if (bound != null) {
+              bound = resolver.definingLibrary.toLegacyTypeIfOptOut(bound);
+              bound = substitution.substituteType(bound);
+              var typeArgument = typeArgumentTypes[i];
+              if (!resolver.typeSystem.isSubtypeOf(typeArgument, bound)) {
+                resolver.errorReporter.reportErrorForNode(
+                  CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
+                  typeArgumentList.arguments[i],
+                  [typeArgument, typeParameter.name, bound],
+                );
+              }
+            }
+          }
+        }
+      }
+
+      invokeType = rawType?.instantiate(typeArgumentTypes);
+    } else if (rawType == null || rawType.typeFormals.isEmpty) {
+      typeArgumentTypes = const <DartType>[];
+      invokeType = rawType;
+    } else {
+      rawType = getFreshTypeParameters(rawType.typeFormals)
+          .applyToFunctionType(rawType);
+
+      var downwardsTypeArguments =
+          resolver.typeSystem.inferGenericFunctionOrType(
+        typeParameters: rawType.typeFormals,
+        parameters: const <ParameterElement>[],
+        declaredReturnType: rawType.returnType,
+        argumentTypes: const <DartType>[],
+        contextReturnType: contextType,
+        downwards: true,
+        isConst: _getIsConst(node),
+        errorReporter: resolver.errorReporter,
+        errorNode: _getErrorNode(node),
+        genericMetadataIsEnabled: resolver.genericMetadataIsEnabled,
+      )!;
+
+      invokeType = rawType.instantiate(downwardsTypeArguments);
+    }
+
+    super.resolveInvocation(
+        resolver: resolver,
+        node: node,
+        rawType: invokeType,
+        contextType: contextType,
+        whyNotPromotedList: whyNotPromotedList);
+
+    var argumentList = _getArgumentList(node);
+
+    if (typeArgumentTypes == null) {
+      if (rawType != null) {
+        // Get the parameters that correspond to the uninstantiated generic.
+        List<ParameterElement?> rawParameters =
+            ResolverVisitor.resolveArgumentsToParameters(
+          argumentList: argumentList,
+          parameters: rawType.parameters,
+        );
+
+        List<ParameterElement> params = <ParameterElement>[];
+        List<DartType> argTypes = <DartType>[];
+        for (int i = 0, length = rawParameters.length; i < length; i++) {
+          ParameterElement? parameter = rawParameters[i];
+          if (parameter != null) {
+            params.add(parameter);
+            argTypes.add(argumentList.arguments[i].typeOrThrow);
+          }
+        }
+        typeArgumentTypes = resolver.typeSystem.inferGenericFunctionOrType(
+          typeParameters: rawType.typeFormals,
+          parameters: params,
+          declaredReturnType: rawType.returnType,
+          argumentTypes: argTypes,
+          contextReturnType: contextType,
+          isConst: _getIsConst(node),
+          errorReporter: resolver.errorReporter,
+          errorNode: _getErrorNode(node),
+          genericMetadataIsEnabled: resolver.genericMetadataIsEnabled,
+        )!;
+        invokeType = rawType.instantiate(typeArgumentTypes);
+      } else {
+        typeArgumentTypes = const [];
+      }
+    }
+
+    var parameters = _storeResult(node, typeArgumentTypes, invokeType);
+    if (parameters != null) {
+      argumentList.correspondingStaticParameters =
+          ResolverVisitor.resolveArgumentsToParameters(
+        argumentList: argumentList,
+        parameters: parameters,
+        errorReporter: resolver.errorReporter,
+      );
+    }
+    var returnType = InvocationInferrer.computeInvokeReturnType(invokeType);
+    return _refineReturnType(resolver, node, returnType);
+  }
+
+  AstNode _getErrorNode(Node node) => node;
+
+  bool _getIsConst(Node node) => false;
+
+  TypeArgumentListImpl? _getTypeArguments(Node node);
+
+  bool _isGenericInferenceDisabled(ResolverVisitor resolver) => false;
+
+  DartType _refineReturnType(
+          ResolverVisitor resolver, Node node, DartType returnType) =>
+      returnType;
+
+  void _reportWrongNumberOfTypeArguments(
+      ResolverVisitor resolver,
+      TypeArgumentList typeArgumentList,
+      FunctionType rawType,
+      List<TypeParameterElement> typeParameters) {
+    resolver.errorReporter.reportErrorForNode(
+      _wrongNumberOfTypeArgumentsErrorCode,
+      typeArgumentList,
+      [
+        rawType,
+        typeParameters.length,
+        typeArgumentList.arguments.length,
+      ],
+    );
+  }
+
+  List<ParameterElement>? _storeResult(
+      Node node, List<DartType>? typeArgumentTypes, FunctionType? invokeType) {
+    return invokeType?.parameters;
+  }
+}
+
+/// Specialization of [InvocationInferrer] for performing type inference on AST
+/// nodes of type [FunctionExpressionInvocation].
+class FunctionExpressionInvocationInferrer
+    extends InvocationExpressionInferrer<FunctionExpressionInvocationImpl> {
+  const FunctionExpressionInvocationInferrer() : super._();
+
+  @override
+  ExpressionImpl _getErrorNode(FunctionExpressionInvocationImpl node) =>
+      node.function;
+}
+
+/// Specialization of [InvocationInferrer] for performing type inference on AST
+/// nodes of type [InstanceCreationExpression].
+class InstanceCreationInferrer
+    extends FullInvocationInferrer<InstanceCreationExpressionImpl> {
+  const InstanceCreationInferrer() : super._();
+
+  @override
+  bool get _needsTypeArgumentBoundsCheck => true;
+
+  @override
+  ArgumentListImpl _getArgumentList(InstanceCreationExpressionImpl node) =>
+      node.argumentList;
+
+  @override
+  ConstructorNameImpl _getErrorNode(InstanceCreationExpressionImpl node) =>
+      node.constructorName;
+
+  @override
+  bool _getIsConst(InstanceCreationExpressionImpl node) => node.isConst;
+
+  @override
+  TypeArgumentListImpl? _getTypeArguments(InstanceCreationExpressionImpl node) {
+    // For an instance creation expression the type arguments are on the
+    // constructor name.
+    return node.constructorName.type.typeArguments;
+  }
+
+  @override
+  void _reportWrongNumberOfTypeArguments(
+      ResolverVisitor resolver,
+      TypeArgumentList typeArgumentList,
+      FunctionType rawType,
+      List<TypeParameterElement> typeParameters) {
+    // Error reporting for instance creations is done elsewhere.
+  }
+
+  @override
+  List<ParameterElement>? _storeResult(InstanceCreationExpressionImpl node,
+      List<DartType>? typeArgumentTypes, FunctionType? invokeType) {
+    if (invokeType != null) {
+      var constructedType = invokeType.returnType;
+      node.constructorName.type.type = constructedType;
+      var constructorElement = ConstructorMember.from(
+        node.constructorName.staticElement!,
+        constructedType as InterfaceType,
+      );
+      node.constructorName.staticElement = constructorElement;
+      return constructorElement.parameters;
+    }
+    return null;
+  }
+}
+
+/// Specialization of [InvocationInferrer] for performing type inference on AST
+/// nodes derived from [InvocationExpression].
+abstract class InvocationExpressionInferrer<
+        Node extends InvocationExpressionImpl>
+    extends FullInvocationInferrer<Node> {
+  const InvocationExpressionInferrer._() : super._();
+
+  @override
+  ArgumentListImpl _getArgumentList(Node node) => node.argumentList;
+
+  @override
+  Expression _getErrorNode(Node node) => node.function;
+
+  @override
+  TypeArgumentListImpl? _getTypeArguments(Node node) => node.typeArguments;
+
+  @override
+  List<ParameterElement>? _storeResult(
+      Node node, List<DartType>? typeArgumentTypes, FunctionType? invokeType) {
+    node.typeArgumentTypes = typeArgumentTypes;
+    node.staticInvokeType = invokeType ?? DynamicTypeImpl.instance;
+    return super._storeResult(node, typeArgumentTypes, invokeType);
+  }
+}
+
+/// Base class containing functionality for performing type inference on AST
+/// nodes that invoke a method, function, or constructor.
+abstract class InvocationInferrer<Node extends AstNodeImpl> {
+  const InvocationInferrer._();
+
+  /// Performs type inference on an invocation expression of type [Node].
+  /// [rawType] should be the type of the function the invocation is resolved to
+  /// (with type arguments not applied yet).
+  void resolveInvocation({
+    required ResolverVisitor resolver,
+    required Node node,
+    required FunctionType? rawType,
+    required DartType? contextType,
+    required List<WhyNotPromotedGetter> whyNotPromotedList,
+  }) {
+    var parameters = rawType?.parameters;
+    var namedParameters = <String, ParameterElement>{};
+    if (parameters != null) {
+      for (var i = 0; i < parameters.length; i++) {
+        var parameter = parameters[i];
+        if (parameter.isNamed) {
+          namedParameters[parameter.name] = parameter;
+        }
+      }
+    }
+    var argumentList = _getArgumentList(node);
+    resolver.checkUnreachableNode(argumentList);
+    var flow = resolver.flowAnalysis.flow;
+    var positionalParameterIndex = 0;
+    for (var argument in _iterateArguments(resolver, argumentList)) {
+      ParameterElement? parameter;
+      if (argument is NamedExpression) {
+        parameter = namedParameters[argument.name.label.name];
+      } else if (parameters != null) {
+        while (positionalParameterIndex < parameters.length) {
+          parameter = parameters[positionalParameterIndex++];
+          if (!parameter.isNamed) {
+            break;
+          }
+        }
+      }
+      DartType? parameterContextType;
+      if (parameter != null) {
+        var parameterType = parameter.type;
+        parameterContextType = _computeContextForArgument(
+            resolver, node, parameterType, contextType);
+      }
+      resolver.analyzeExpression(argument, parameterContextType);
+      if (flow != null) {
+        whyNotPromotedList.add(flow.whyNotPromoted(argument));
+      }
+    }
+  }
+
+  /// Computes the type context that should be used when evaluating a particular
+  /// argument of the invocation.  Usually this is just the type of the
+  /// corresponding parameter, but it can be different for certain primitive
+  /// numeric operations.
+  DartType? _computeContextForArgument(ResolverVisitor resolver, Node node,
+          DartType parameterType, DartType? methodInvocationContext) =>
+      parameterType;
+
+  /// Gets the argument list for the invocation.  TODO(paulberry): remove?
+  ArgumentListImpl _getArgumentList(Node node);
+
+  /// Iterates through the argument list for the invocation.  Usually this is
+  /// just a simple iteration through the arguments, but in certain cases, some
+  /// flow analysis methods need to be called in between visiting the various
+  /// arguments.
+  Iterable<Expression> _iterateArguments(
+          ResolverVisitor resolver, ArgumentList argumentList) =>
+      argumentList.arguments;
+
+  /// Computes the return type of the method or function represented by the
+  /// given type that is being invoked.
+  static DartType computeInvokeReturnType(DartType? type) {
+    if (type is FunctionType) {
+      return type.returnType;
+    } else {
+      return DynamicTypeImpl.instance;
+    }
+  }
+}
+
+/// Specialization of [InvocationInferrer] for performing type inference on AST
+/// nodes of type [MethodInvocation].
+class MethodInvocationInferrer
+    extends InvocationExpressionInferrer<MethodInvocationImpl> {
+  /// Gets the appropriate instance of [MethodInvocation] for the given [node].
+  ///
+  /// This factory takes care of the fact that invocations of `identical` need
+  /// to have special integration with flow analysis.
+  factory MethodInvocationInferrer.forNode(MethodInvocationImpl node) {
+    var invokedMethod = node.methodName.staticElement;
+    if (invokedMethod != null &&
+        invokedMethod.name == 'identical' &&
+        invokedMethod.library!.isDartCore &&
+        node.argumentList.arguments.length == 2) {
+      return const _IdenticalInvocationInferrer._();
+    } else {
+      return const MethodInvocationInferrer._();
+    }
+  }
+
+  const MethodInvocationInferrer._() : super._();
+
+  @override
+  DartType? _computeContextForArgument(
+      ResolverVisitor resolver,
+      MethodInvocationImpl node,
+      DartType parameterType,
+      DartType? methodInvocationContext) {
+    var contextType = super._computeContextForArgument(
+        resolver, node, parameterType, methodInvocationContext);
+    var targetType = node.realTarget?.staticType;
+    if (targetType != null) {
+      contextType = resolver.typeSystem.refineNumericInvocationContext(
+          targetType,
+          node.methodName.staticElement,
+          methodInvocationContext,
+          parameterType);
+    }
+    return contextType;
+  }
+
+  @override
+  DartType _refineReturnType(ResolverVisitor resolver,
+      MethodInvocationImpl node, DartType returnType) {
+    var targetType = node.realTarget?.staticType;
+    if (targetType != null) {
+      returnType = resolver.typeSystem.refineNumericInvocationType(
+        targetType,
+        node.methodName.staticElement,
+        [
+          for (var argument in node.argumentList.arguments) argument.typeOrThrow
+        ],
+        returnType,
+      );
+    }
+    return returnType;
+  }
+}
+
+/// Specialization of [InvocationInferrer] for performing type inference on AST
+/// nodes of type [RedirectingConstructorInvocation].
+class RedirectingConstructorInvocationInferrer
+    extends InvocationInferrer<RedirectingConstructorInvocationImpl> {
+  const RedirectingConstructorInvocationInferrer() : super._();
+
+  @override
+  ArgumentListImpl _getArgumentList(
+          RedirectingConstructorInvocationImpl node) =>
+      node.argumentList;
+}
+
+/// Specialization of [InvocationInferrer] for performing type inference on AST
+/// nodes of type [SuperConstructorInvocation].
+class SuperConstructorInvocationInferrer
+    extends InvocationInferrer<SuperConstructorInvocationImpl> {
+  const SuperConstructorInvocationInferrer() : super._();
+
+  @override
+  ArgumentListImpl _getArgumentList(SuperConstructorInvocationImpl node) =>
+      node.argumentList;
+}
+
+/// Specialization of [InvocationInferrer] for performing type inference on AST
+/// nodes of type [MethodInvocation] that resolve to the core function
+/// `identical`.  (Such nodes need to be handled in a special way due to the
+/// interaction between `identical` and flow analysis).
+class _IdenticalInvocationInferrer extends MethodInvocationInferrer {
+  const _IdenticalInvocationInferrer._() : super._();
+
+  @override
+  Iterable<Expression> _iterateArguments(
+      ResolverVisitor resolver, ArgumentList argumentList) sync* {
+    var flow = resolver.flowAnalysis.flow;
+    var arguments = argumentList.arguments;
+    assert(arguments.length == 2);
+    var firstArg = arguments[0];
+    yield firstArg;
+    firstArg = arguments[0]; // In case it was rewritten
+    flow?.equalityOp_rightBegin(firstArg, firstArg.typeOrThrow);
+    var secondArg = arguments[1];
+    yield secondArg;
+    secondArg = arguments[1]; // In case it was rewritten
+    flow?.equalityOp_end(
+        argumentList.parent as Expression, secondArg, secondArg.typeOrThrow);
+  }
+}
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 0cc6306..724f3c1 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -15,6 +15,7 @@
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
 import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inferrer.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/migratable_ast_info_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -323,38 +324,17 @@
     );
   }
 
-  /// [InvocationExpression.staticInvokeType] has been set for the [node].
-  /// Use it to set context for arguments, and resolve them.
-  void _resolveArguments(
-      MethodInvocationImpl node, List<WhyNotPromotedGetter> whyNotPromotedList,
-      {required DartType? contextType}) {
-    // TODO(scheglov) This is bad, don't write raw type, carry it
-    var callerType = _inferenceHelper.inferArgumentTypesForInvocation(
-      node,
-      node.methodName.staticType,
-      contextType: contextType,
-    );
-    _resolver.analyzeArgumentList(node.argumentList,
-        callerType is FunctionType ? callerType.parameters : null,
-        whyNotPromotedList: whyNotPromotedList,
-        methodInvocationContext: contextType);
-  }
-
   void _resolveArguments_finishInference(
       MethodInvocationImpl node, List<WhyNotPromotedGetter> whyNotPromotedList,
       {required DartType? contextType}) {
-    _resolveArguments(node, whyNotPromotedList, contextType: contextType);
-
-    // TODO(scheglov) This is bad, don't put / get raw FunctionType this way.
-    _inferenceHelper.inferGenericInvocationExpression(
-      node,
-      node.methodName.staticType,
-      contextType: contextType,
-    );
-
-    DartType staticStaticType = _inferenceHelper.computeInvokeReturnType(
-      node.staticInvokeType,
-    );
+    var methodInvocationInferrer = MethodInvocationInferrer.forNode(node);
+    var rawType = node.methodName.staticType;
+    DartType staticStaticType = methodInvocationInferrer.resolveInvocation(
+        resolver: _resolver,
+        node: node,
+        rawType: rawType is FunctionType ? rawType : null,
+        contextType: contextType,
+        whyNotPromotedList: whyNotPromotedList);
     _inferenceHelper.recordStaticType(node, staticStaticType,
         contextType: contextType);
   }
@@ -473,29 +453,32 @@
     var objectElement = _typeSystem.typeProvider.objectElement;
     var target = objectElement.getMethod(nameNode.name);
 
-    var hasMatchingObjectMethod = false;
+    FunctionType? rawType;
     if (target is MethodElement && !target.isStatic) {
       var arguments = node.argumentList.arguments;
-      hasMatchingObjectMethod = arguments.length == target.parameters.length &&
-          !arguments.any((e) => e is NamedExpression);
+      var hasMatchingObjectMethod =
+          arguments.length == target.parameters.length &&
+              !arguments.any((e) => e is NamedExpression);
       if (hasMatchingObjectMethod) {
         target = _resolver.toLegacyElement(target);
         nameNode.staticElement = target;
-        node.staticInvokeType = target.type;
+        rawType = target.type;
         node.staticType = target.returnType;
       }
     }
 
-    if (!hasMatchingObjectMethod) {
+    if (rawType == null) {
       nameNode.staticType = DynamicTypeImpl.instance;
-      node.staticInvokeType = DynamicTypeImpl.instance;
       node.staticType = DynamicTypeImpl.instance;
     }
 
     _setExplicitTypeArgumentTypes();
-    _resolver.analyzeArgumentList(node.argumentList, null,
+    MethodInvocationInferrer.forNode(node).resolveInvocation(
+        resolver: _resolver,
+        node: node,
+        rawType: rawType,
         whyNotPromotedList: whyNotPromotedList,
-        methodInvocationContext: contextType);
+        contextType: contextType);
   }
 
   void _resolveReceiverFunctionBounded(
@@ -563,7 +546,12 @@
       node.staticInvokeType = _dynamicType;
       node.staticType = NeverTypeImpl.instance;
 
-      _resolveArguments(node, whyNotPromotedList, contextType: contextType);
+      MethodInvocationInferrer.forNode(node).resolveInvocation(
+          resolver: _resolver,
+          node: node,
+          rawType: null,
+          contextType: contextType,
+          whyNotPromotedList: whyNotPromotedList);
 
       _resolver.errorReporter.reportErrorForNode(
         HintCode.RECEIVER_OF_TYPE_NEVER,
@@ -577,7 +565,12 @@
       node.staticInvokeType = _dynamicType;
       node.staticType = _dynamicType;
 
-      _resolveArguments(node, whyNotPromotedList, contextType: contextType);
+      MethodInvocationInferrer.forNode(node).resolveInvocation(
+          resolver: _resolver,
+          node: node,
+          rawType: null,
+          contextType: contextType,
+          whyNotPromotedList: whyNotPromotedList);
       return;
     }
   }
diff --git a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
index 4cc71c9..9667c37f 100644
--- a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
@@ -14,6 +14,7 @@
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/dart/resolver/assignment_expression_resolver.dart';
 import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inferrer.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -97,11 +98,11 @@
       // We are invoking a getter and then invoking the returned function.
       //
       FunctionType propertyType = element.type;
-      return _resolver.inferenceHelper.computeInvokeReturnType(
+      return InvocationInferrer.computeInvokeReturnType(
         propertyType.returnType,
       );
     } else if (element is ExecutableElement) {
-      return _resolver.inferenceHelper.computeInvokeReturnType(element.type);
+      return InvocationInferrer.computeInvokeReturnType(element.type);
     }
     return DynamicTypeImpl.instance;
   }
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
index 484e305..fc71e4f 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -14,6 +14,7 @@
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/resolver/assignment_expression_resolver.dart';
 import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inferrer.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -108,11 +109,11 @@
       // We are invoking a getter and then invoking the returned function.
       //
       var propertyType = element.type;
-      return _resolver.inferenceHelper.computeInvokeReturnType(
+      return InvocationInferrer.computeInvokeReturnType(
         propertyType.returnType,
       );
     } else if (element is ExecutableElement) {
-      return _resolver.inferenceHelper.computeInvokeReturnType(element.type);
+      return InvocationInferrer.computeInvokeReturnType(element.type);
     }
     return DynamicTypeImpl.instance;
   }
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 5d242c3..92f03a7 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -43,6 +43,7 @@
 import 'package:analyzer/src/dart/resolver/function_reference_resolver.dart';
 import 'package:analyzer/src/dart/resolver/instance_creation_expression_resolver.dart';
 import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inferrer.dart';
 import 'package:analyzer/src/dart/resolver/lexical_lookup.dart';
 import 'package:analyzer/src/dart/resolver/method_invocation_resolver.dart';
 import 'package:analyzer/src/dart/resolver/postfix_expression_resolver.dart';
@@ -248,6 +249,8 @@
 
   late final AnnotationResolver _annotationResolver = AnnotationResolver(this);
 
+  final bool genericMetadataIsEnabled;
+
   /// Initialize a newly created visitor to resolve the nodes in an AST node.
   ///
   /// The [definingLibrary] is the element for the library containing the node
@@ -300,7 +303,9 @@
           isNonNullableByDefault: definingLibrary.isNonNullableByDefault,
         ),
         _featureSet = featureSet,
-        migrationResolutionHooks = migrationResolutionHooks {
+        migrationResolutionHooks = migrationResolutionHooks,
+        genericMetadataIsEnabled =
+            definingLibrary.featureSet.isEnabled(Feature.generic_metadata) {
     var analysisOptions =
         definingLibrary.context.analysisOptions as AnalysisOptionsImpl;
 
@@ -403,73 +408,6 @@
   bool get _isNonNullableByDefault =>
       _featureSet.isEnabled(Feature.non_nullable);
 
-  void analyzeArgumentList(
-      ArgumentList node, List<ParameterElement>? parameters,
-      {bool isIdentical = false,
-      List<WhyNotPromotedGetter>? whyNotPromotedList,
-      DartType? methodInvocationContext}) {
-    whyNotPromotedList ??= [];
-    NodeList<Expression> arguments = node.arguments;
-    var namedParameters = <String, ParameterElement>{};
-    DartType? targetType;
-    Element? methodElement;
-    if (parameters != null) {
-      for (var i = 0; i < parameters.length; i++) {
-        var parameter = parameters[i];
-        if (parameter.isNamed) {
-          namedParameters[parameter.name] = parameter;
-        }
-      }
-
-      var parent = node.parent;
-      if (parent is MethodInvocation) {
-        targetType = parent.realTarget?.staticType;
-        methodElement = parent.methodName.staticElement;
-      }
-    }
-    checkUnreachableNode(node);
-    int length = arguments.length;
-    var flow = flowAnalysis.flow;
-    var positionalParameterIndex = 0;
-    for (var i = 0; i < length; i++) {
-      if (isIdentical && length > 1 && i == 1) {
-        var firstArg = arguments[0];
-        flow?.equalityOp_rightBegin(firstArg, firstArg.typeOrThrow);
-      }
-      var argument = arguments[i];
-      ParameterElement? parameter;
-      if (argument is NamedExpression) {
-        parameter = namedParameters[argument.name.label.name];
-      } else if (parameters != null) {
-        while (positionalParameterIndex < parameters.length) {
-          parameter = parameters[positionalParameterIndex++];
-          if (!parameter.isNamed) {
-            break;
-          }
-        }
-      }
-      DartType? contextType;
-      if (parameter != null) {
-        var parameterType = parameter.type;
-        if (targetType != null) {
-          contextType = typeSystem.refineNumericInvocationContext(targetType,
-              methodElement, methodInvocationContext, parameterType);
-        } else {
-          contextType = parameterType;
-        }
-      }
-      analyzeExpression(argument, contextType);
-      if (flow != null) {
-        whyNotPromotedList.add(flow.whyNotPromoted(arguments[i]));
-      }
-    }
-    if (isIdentical && length > 1) {
-      var secondArg = arguments[1];
-      flow?.equalityOp_end(
-          node.parent as Expression, secondArg, secondArg.typeOrThrow);
-    }
-  }
-
   void analyzeExpression(Expression expression, DartType? contextType) {
     if (contextType != null && contextType.isDynamic) {
       contextType = null;
@@ -1042,12 +980,6 @@
   }
 
   @override
-  void visitArgumentList(ArgumentList node) {
-    assert(false, 'analyzeArgumentList should be used instead');
-    analyzeArgumentList(node, null);
-  }
-
-  @override
   void visitAsExpression(AsExpression node, {DartType? contextType}) {
     checkUnreachableNode(node);
     node.visitChildren(this);
@@ -1600,21 +1532,28 @@
   }
 
   @override
-  void visitExtensionOverride(ExtensionOverride node, {DartType? contextType}) {
+  void visitExtensionOverride(covariant ExtensionOverrideImpl node,
+      {DartType? contextType}) {
     var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
     node.extensionName.accept(this);
     node.typeArguments?.accept(this);
 
     var receiverContextType =
         ExtensionMemberResolver(this).computeOverrideReceiverContextType(node);
-    analyzeArgumentList(
-        node.argumentList,
-        receiverContextType == null
+    const ExtensionOverrideInferrer().resolveInvocation(
+        resolver: this,
+        node: node,
+        rawType: receiverContextType == null
             ? null
-            : [
-                ParameterElementImpl.synthetic(
-                    null, receiverContextType, ParameterKind.REQUIRED)
-              ],
+            : FunctionTypeImpl(
+                typeFormals: const [],
+                parameters: [
+                    ParameterElementImpl.synthetic(
+                        null, receiverContextType, ParameterKind.REQUIRED)
+                  ],
+                returnType: DynamicTypeImpl.instance,
+                nullabilitySuffix: NullabilitySuffix.none),
+        contextType: null,
         whyNotPromotedList: whyNotPromotedList);
 
     extensionResolver.resolveOverride(node, whyNotPromotedList);
@@ -2223,7 +2162,11 @@
     var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
     elementResolver.visitRedirectingConstructorInvocation(
         node as RedirectingConstructorInvocationImpl);
-    analyzeArgumentList(node.argumentList, node.staticElement?.parameters,
+    const RedirectingConstructorInvocationInferrer().resolveInvocation(
+        resolver: this,
+        node: node,
+        rawType: node.staticElement?.type,
+        contextType: null,
         whyNotPromotedList: whyNotPromotedList);
     checkForArgumentTypesNotAssignableInList(
         node.argumentList, whyNotPromotedList);
@@ -2327,7 +2270,11 @@
     var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
     elementResolver.visitSuperConstructorInvocation(
         node as SuperConstructorInvocationImpl);
-    analyzeArgumentList(node.argumentList, node.staticElement?.parameters,
+    const SuperConstructorInvocationInferrer().resolveInvocation(
+        resolver: this,
+        node: node,
+        rawType: node.staticElement?.type,
+        contextType: null,
         whyNotPromotedList: whyNotPromotedList);
     checkForArgumentTypesNotAssignableInList(
         node.argumentList, whyNotPromotedList);
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index a3ac1e3..946b08f 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -6,7 +6,6 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
-import 'package:analyzer/src/dart/element/member.dart' show ConstructorMember;
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
@@ -155,22 +154,6 @@
     node.staticType = _dynamicType;
   }
 
-  /// The Dart Language Specification, 12.11.1: <blockquote>The static type of a new expression of
-  /// either the form <i>new T.id(a<sub>1</sub>, &hellip;, a<sub>n</sub>)</i> or the form <i>new
-  /// T(a<sub>1</sub>, &hellip;, a<sub>n</sub>)</i> is <i>T</i>.</blockquote>
-  ///
-  /// The Dart Language Specification, 12.11.2: <blockquote>The static type of a constant object
-  /// expression of either the form <i>const T.id(a<sub>1</sub>, &hellip;, a<sub>n</sub>)</i> or the
-  /// form <i>const T(a<sub>1</sub>, &hellip;, a<sub>n</sub>)</i> is <i>T</i>. </blockquote>
-  void visitInstanceCreationExpression(
-      covariant InstanceCreationExpressionImpl node,
-      {required DartType? contextType}) {
-    _inferInstanceCreationExpression(node, contextType: contextType);
-    _inferenceHelper.recordStaticType(
-        node, node.constructorName.type.typeOrThrow,
-        contextType: contextType);
-  }
-
   /// <blockquote>
   /// An integer literal has static type \code{int}, unless the surrounding
   /// static context type is a type which \code{int} is not assignable to, and
@@ -342,56 +325,4 @@
     }
     return type;
   }
-
-  /// Given an instance creation of a possibly generic type, infer the type
-  /// arguments using the current context type as well as the argument types.
-  void _inferInstanceCreationExpression(InstanceCreationExpressionImpl node,
-      {required DartType? contextType}) {
-    // TODO(leafp): Currently, we may re-infer types here, since we
-    // sometimes resolve multiple times.  We should really check that we
-    // have not already inferred something.  However, the obvious ways to
-    // check this don't work, since we may have been instantiated
-    // to bounds in an earlier phase, and we *do* want to do inference
-    // in that case.
-
-    // Get back to the uninstantiated generic constructor.
-    // TODO(jmesserly): should we store this earlier in resolution?
-    // Or look it up, instead of jumping backwards through the Member?
-    var constructorName = node.constructorName;
-    var elementToInfer = _resolver.inferenceHelper.constructorElementToInfer(
-      constructorName: constructorName,
-      definingLibrary: _resolver.definingLibrary,
-    );
-
-    // If the constructor is not generic, we are done.
-    if (elementToInfer == null) {
-      return;
-    }
-
-    var typeName = constructorName.type;
-    var typeArguments = typeName.typeArguments;
-
-    var constructorType = elementToInfer.asType;
-    var arguments = node.argumentList;
-    var inferred = _resolver.inferenceHelper.inferGenericInvoke(
-        node, constructorType, typeArguments, arguments, constructorName,
-        isConst: node.isConst, contextReturnType: contextType);
-
-    if (inferred != null) {
-      // Fix up the parameter elements based on inferred method.
-      arguments.correspondingStaticParameters =
-          ResolverVisitor.resolveArgumentsToParameters(
-        argumentList: arguments,
-        parameters: inferred.parameters,
-      );
-      typeName.type = inferred.returnType;
-      // Update the static element as well. This is used in some cases, such as
-      // computing constant values. It is stored in two places.
-      var constructorElement = ConstructorMember.from(
-        elementToInfer.element,
-        inferred.returnType as InterfaceType,
-      );
-      constructorName.staticElement = constructorElement;
-    }
-  }
 }
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 456f594..bc4e648 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -1419,10 +1419,8 @@
 ''');
     var x = findNode.namedExpression('arg: true');
     var y = x.staticParameterElement!;
-    // Note: the staticParameterElement is synthetic; see
-    // https://github.com/dart-lang/sdk/issues/48500
-    expect(y, isNot(TypeMatcher<ParameterMember>()));
-    expect(y.enclosingElement, isNull);
+    expect(y, TypeMatcher<ParameterMember>());
+    expect(y.declaration, findElement.parameter('arg'));
   }
 
   test_generic_staticParameterElement_instanceCreation_implicitNew() async {
@@ -1447,10 +1445,8 @@
 ''');
     var x = findNode.namedExpression('arg: true');
     var y = x.staticParameterElement!;
-    // Note: the staticParameterElement is synthetic; see
-    // https://github.com/dart-lang/sdk/issues/48500
-    expect(y, isNot(TypeMatcher<ParameterMember>()));
-    expect(y.enclosingElement, isNull);
+    expect(y, TypeMatcher<ParameterMember>());
+    expect(y.declaration, findElement.parameter('arg'));
   }
 
   test_generic_staticParameterElement_methodCall() async {
diff --git a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
index 2944a2b..a4c3dd6 100644
--- a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
@@ -310,6 +310,21 @@
 ''');
   }
 
+  Future<void> test_nonFunctionTypeAlias_parameter() async {
+    await assertErrorsInCode('''
+class A {}
+class B extends A {}
+class D<T> {}
+typedef Alias<T extends B> = D<T>;
+main() {
+  D d = Alias<A>();
+}
+''', [
+      error(HintCode.UNUSED_LOCAL_VARIABLE, 94, 1),
+      error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 104, 1),
+    ]);
+  }
+
   test_notRegularBounded_notSuperBounded_parameter_invariant() async {
     await assertErrorsInCode(r'''
 typedef A<X> = X Function(X);