// Copyright (c) 2017, 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.md file.

import 'package:_fe_analyzer_shared/src/deferred_function_literal_heuristic.dart';
import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
import 'package:_fe_analyzer_shared/src/testing/id.dart';
import 'package:_fe_analyzer_shared/src/util/link.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/canonical_name.dart' as kernel;
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:kernel/src/bounds_checks.dart'
    show calculateBounds, isGenericFunctionTypeOrAlias;
import 'package:kernel/src/future_value_type.dart';
import 'package:kernel/src/legacy_erasure.dart';
import 'package:kernel/type_algebra.dart';
import 'package:kernel/type_environment.dart';

import '../../api_prototype/experimental_flags.dart';
import '../../base/instrumentation.dart'
    show
        Instrumentation,
        InstrumentationValueForMember,
        InstrumentationValueForType,
        InstrumentationValueForTypeArgs;
import '../../base/nnbd_mode.dart';
import '../../testing/id_extractor.dart';
import '../../testing/id_testing_utils.dart';
import '../builder/extension_builder.dart';
import '../builder/member_builder.dart';
import '../fasta_codes.dart';
import '../kernel/benchmarker.dart' show BenchmarkSubdivides, Benchmarker;
import '../kernel/constructor_tearoff_lowering.dart';
import '../kernel/hierarchy/class_member.dart' show ClassMember;
import 'inference_visitor.dart';
import '../kernel/internal_ast.dart';
import '../kernel/invalid_type.dart';
import '../kernel/kernel_helper.dart';
import '../kernel/type_algorithms.dart' show hasAnyTypeVariables;
import '../names.dart';
import '../problems.dart' show internalProblem, unexpected, unhandled;
import '../source/source_constructor_builder.dart';
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
import 'inference_helper.dart' show InferenceHelper;
import 'type_constraint_gatherer.dart' show TypeConstraintGatherer;
import 'type_demotion.dart';
import 'type_inference_engine.dart';
import 'type_schema.dart' show isKnown, UnknownType;
import 'type_schema_elimination.dart' show greatestClosure;
import 'type_schema_environment.dart'
    show
        getNamedParameterType,
        getPositionalParameterType,
        TypeConstraint,
        TypeVariableEliminator,
        TypeSchemaEnvironment;

part 'closure_context.dart';

/// Given a [FunctionNode], gets the named parameter identified by [name], or
/// `null` if there is no parameter with the given name.
VariableDeclaration? getNamedFormal(FunctionNode function, String name) {
  for (VariableDeclaration formal in function.namedParameters) {
    if (formal.name == name) return formal;
  }
  return null;
}

/// Given a [FunctionNode], gets the [i]th positional formal parameter, or
/// `null` if there is no parameter with that index.
VariableDeclaration? getPositionalFormal(FunctionNode function, int i) {
  if (i < function.positionalParameters.length) {
    return function.positionalParameters[i];
  } else {
    return null;
  }
}

bool isOverloadableArithmeticOperator(String name) {
  return identical(name, '+') ||
      identical(name, '-') ||
      identical(name, '*') ||
      identical(name, '%');
}

/// Given a [FunctionExpression], computes a set whose elements consist of (a)
/// an integer corresponding to the zero-based index of each positional
/// parameter of the function expression that has an explicit type annotation,
/// and (b) a string corresponding to the name of each named parameter of the
/// function expression that has an explicit type annotation.
Set<Object> _computeExplicitlyTypedParameterSet(
    FunctionExpression functionExpression) {
  Set<Object> result = {};
  int unnamedParameterIndex = 0;
  for (VariableDeclaration positionalParameter
      in functionExpression.function.positionalParameters) {
    int key = unnamedParameterIndex++;
    if (!(positionalParameter as VariableDeclarationImpl).isImplicitlyTyped) {
      result.add(key);
    }
  }
  for (VariableDeclaration namedParameter
      in functionExpression.function.namedParameters) {
    String key = namedParameter.name!;
    if (!(namedParameter as VariableDeclarationImpl).isImplicitlyTyped) {
      result.add(key);
    }
  }
  return result;
}

/// Given an function type, computes a map based on the parameters whose keys
/// are either the parameter name (for named parameters) or the zero-based
/// integer index (for unnamed parameters), and whose values are the parameter
/// types.
Map<Object, DartType> _computeParameterMap(FunctionType functionType) => {
      for (int i = 0; i < functionType.positionalParameters.length; i++)
        i: functionType.positionalParameters[i],
      for (NamedType namedType in functionType.namedParameters)
        namedType.name: namedType.type
    };

/// Computes a list of [_ParamInfo] objects corresponding to the invocation
/// parameters that were *not* deferred.
List<_ParamInfo> _computeUndeferredParamInfo(List<DartType> formalTypes,
    List<_DeferredParamInfo> deferredFunctionLiterals) {
  Set<int> evaluationOrderIndicesAlreadyCovered = {
    for (_DeferredParamInfo functionLiteral in deferredFunctionLiterals)
      functionLiteral.evaluationOrderIndex
  };
  assert(evaluationOrderIndicesAlreadyCovered
      .every((i) => 0 <= i && i < formalTypes.length));
  return [
    for (int i = 0; i < formalTypes.length; i++)
      if (!evaluationOrderIndicesAlreadyCovered.contains(i))
        new _ParamInfo(formalTypes[i])
  ];
}

/// Enum denoting the kinds of contravariance check that might need to be
/// inserted for a method call.
enum MethodContravarianceCheckKind {
  /// No contravariance check is needed.
  none,

  /// The return value from the method call needs to be checked.
  checkMethodReturn,

  /// The method call needs to be desugared into a getter call, followed by an
  /// "as" check, followed by an invocation of the resulting function object.
  checkGetterReturn,
}

/// Keeps track of the local state for the type inference that occurs during
/// compilation of a single method body or top level initializer.
///
/// This class describes the interface for use by clients of type inference
/// (e.g. BodyBuilder).  Derived classes should derive from [TypeInferrerImpl].
abstract class TypeInferrer {
  SourceLibraryBuilder get libraryBuilder;

  /// Gets the [TypeSchemaEnvironment] being used for type inference.
  TypeSchemaEnvironment get typeSchemaEnvironment;

  /// Returns the [FlowAnalysis] used during inference.
  FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration, DartType>
      get flowAnalysis;

  /// The URI of the code for which type inference is currently being
  /// performed--this is used for testing.
  Uri get uriForInstrumentation;

  AssignedVariables<TreeNode, VariableDeclaration> get assignedVariables;

  /// Indicates whether the construct we are currently performing inference for
  /// is outside of a method body, and hence top level type inference rules
  /// should apply.
  bool get isTopLevel;

  /// Performs top level type inference on the given field initializer and
  /// returns the computed field type.
  DartType inferImplicitFieldType(
      InferenceHelper helper, Expression initializer);

  /// Performs full type inference on the given field initializer.
  ExpressionInferenceResult inferFieldInitializer(
      InferenceHelper helper, DartType declaredType, Expression initializer);

  /// Performs type inference on the given function body.
  InferredFunctionBody inferFunctionBody(InferenceHelper helper, int fileOffset,
      DartType returnType, AsyncMarker asyncMarker, Statement body);

  /// Performs type inference on the given constructor initializer.
  InitializerInferenceResult inferInitializer(
      InferenceHelper helper, Initializer initializer);

  /// Performs type inference on the given metadata annotations.
  void inferMetadata(
      InferenceHelper helper, TreeNode? parent, List<Expression>? annotations);

  /// Performs type inference on the given function parameter initializer
  /// expression.
  Expression inferParameterInitializer(
      InferenceHelper helper,
      Expression initializer,
      DartType declaredType,
      bool hasDeclaredInitializer);

  /// Infers the type arguments a redirecting factory target reference.
  List<DartType>? inferRedirectingFactoryTypeArguments(
      InferenceHelper helper,
      DartType typeContext,
      FunctionNode redirectingFactoryFunction,
      int fileOffset,
      Member target,
      FunctionType targetType);
}

/// Concrete implementation of [TypeInferrer] specialized to work with kernel
/// objects.
class TypeInferrerImpl implements TypeInferrer {
  /// Marker object to indicate that a function takes an unknown number
  /// of arguments.
  final FunctionType unknownFunction;

  final TypeInferenceEngine engine;

  @override
  late final FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration,
          DartType> flowAnalysis =
      libraryBuilder.isNonNullableByDefault
          ? new FlowAnalysis(
              new TypeOperationsCfe(engine.typeSchemaEnvironment),
              assignedVariables,
              respectImplicitlyTypedVarInitializers:
                  libraryBuilder.libraryFeatures.constructorTearoffs.isEnabled)
          : new FlowAnalysis.legacy(
              new TypeOperationsCfe(engine.typeSchemaEnvironment),
              assignedVariables);

  @override
  final AssignedVariables<TreeNode, VariableDeclaration> assignedVariables;

  final InferenceDataForTesting? dataForTesting;

  @override
  final Uri uriForInstrumentation;

  @override
  final bool isTopLevel;

  final ClassHierarchy classHierarchy;

  final Instrumentation? instrumentation;

  @override
  final TypeSchemaEnvironment typeSchemaEnvironment;

  final InterfaceType? thisType;

  @override
  final SourceLibraryBuilder libraryBuilder;

  TypeInferrerImpl(
      this.engine,
      this.uriForInstrumentation,
      this.isTopLevel,
      this.thisType,
      this.libraryBuilder,
      this.assignedVariables,
      this.dataForTesting)
      // ignore: unnecessary_null_comparison
      : assert(libraryBuilder != null),
        unknownFunction = new FunctionType(
            const [], const DynamicType(), libraryBuilder.nonNullable),
        classHierarchy = engine.classHierarchy,
        instrumentation = isTopLevel ? null : engine.instrumentation,
        typeSchemaEnvironment = engine.typeSchemaEnvironment {}

  InferenceVisitor _createInferenceVisitor(InferenceVisitorBase inferrer) {
    // For full (non-top level) inference, we need access to the
    // ExpressionGeneratorHelper so that we can perform error recovery.
    assert(isTopLevel || inferrer._helper != null,
        "Helper hasn't been set up for full inference.");
    return new InferenceVisitor(inferrer);
  }

  @override
  DartType inferImplicitFieldType(
      InferenceHelper helper, Expression initializer) {
    InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
    InferenceVisitor visitor = _createInferenceVisitor(inferrer);
    ExpressionInferenceResult result = visitor.inferExpression(
        initializer, const UnknownType(), true,
        isVoidAllowed: true);
    return inferrer.inferDeclarationType(result.inferredType);
  }

  @override
  ExpressionInferenceResult inferFieldInitializer(
      InferenceHelper helper, DartType declaredType, Expression initializer) {
    assert(!isTopLevel);
    InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
    InferenceVisitor visitor = _createInferenceVisitor(inferrer);
    ExpressionInferenceResult initializerResult = visitor
        .inferExpression(initializer, declaredType, true, isVoidAllowed: true);
    initializerResult = inferrer.ensureAssignableResult(
        declaredType, initializerResult,
        isVoidAllowed: declaredType is VoidType);
    return initializerResult;
  }

  @override
  InferredFunctionBody inferFunctionBody(InferenceHelper helper, int fileOffset,
      DartType returnType, AsyncMarker asyncMarker, Statement body) {
    // ignore: unnecessary_null_comparison
    assert(body != null);
    InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
    ClosureContext closureContext =
        new ClosureContext(inferrer, asyncMarker, returnType, false);
    InferenceVisitor visitor = _createInferenceVisitor(inferrer);
    StatementInferenceResult result =
        visitor.inferStatement(body, closureContext);
    if (dataForTesting != null) {
      if (!flowAnalysis.isReachable) {
        dataForTesting!.flowAnalysisResult.functionBodiesThatDontComplete
            .add(body);
      }
    }
    result =
        closureContext.handleImplicitReturn(inferrer, body, result, fileOffset);
    DartType? futureValueType = closureContext.futureValueType;
    assert(!(asyncMarker == AsyncMarker.Async && futureValueType == null),
        "No future value type computed.");
    flowAnalysis.finish();
    return new InferredFunctionBody(
        result.hasChanged ? result.statement : body, futureValueType);
  }

  @override
  List<DartType>? inferRedirectingFactoryTypeArguments(
      InferenceHelper helper,
      DartType typeContext,
      FunctionNode redirectingFactoryFunction,
      int fileOffset,
      Member target,
      FunctionType targetType) {
    InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
    InferenceVisitor visitor = _createInferenceVisitor(inferrer);
    List<Expression> positionalArguments = <Expression>[];
    for (VariableDeclaration parameter
        in redirectingFactoryFunction.positionalParameters) {
      flowAnalysis.declare(parameter, true);
      positionalArguments
          .add(new VariableGetImpl(parameter, forNullGuardedAccess: false));
    }
    List<NamedExpression> namedArguments = <NamedExpression>[];
    for (VariableDeclaration parameter
        in redirectingFactoryFunction.namedParameters) {
      flowAnalysis.declare(parameter, true);
      namedArguments.add(new NamedExpression(parameter.name!,
          new VariableGetImpl(parameter, forNullGuardedAccess: false)));
    }
    // If arguments are created using [Forest.createArguments], and the
    // type arguments are omitted, they are to be inferred.
    ArgumentsImpl targetInvocationArguments = engine.forest.createArguments(
        fileOffset, positionalArguments,
        named: namedArguments);

    InvocationInferenceResult result = inferrer.inferInvocation(
        visitor, typeContext, fileOffset, targetType, targetInvocationArguments,
        staticTarget: target);
    DartType resultType = result.inferredType;
    if (resultType is InterfaceType) {
      return resultType.typeArguments;
    } else {
      return null;
    }
  }

  @override
  InitializerInferenceResult inferInitializer(
      InferenceHelper helper, Initializer initializer) {
    // Use polymorphic dispatch on [KernelInitializer] to perform whatever
    // kind of type inference is correct for this kind of initializer.
    // TODO(paulberry): experiment to see if dynamic dispatch would be better,
    // so that the type hierarchy will be simpler (which may speed up "is"
    // checks).
    InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
    InferenceVisitor visitor = _createInferenceVisitor(inferrer);
    InitializerInferenceResult inferenceResult;
    if (initializer is InitializerJudgment) {
      inferenceResult = initializer.acceptInference(visitor);
    } else {
      inferenceResult = initializer.accept(visitor);
    }
    return inferenceResult;
  }

  @override
  void inferMetadata(
      InferenceHelper helper, TreeNode? parent, List<Expression>? annotations) {
    if (annotations != null) {
      // We bypass the check for assignment of the helper during top-level
      // inference and use `_helper = helper` instead of `this.helper = helper`
      // because inference on metadata requires the helper.
      InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
      InferenceVisitor visitor = _createInferenceVisitor(inferrer);
      inferrer.inferMetadataKeepingHelper(visitor, parent, annotations);
    }
  }

  @override
  Expression inferParameterInitializer(
      InferenceHelper helper,
      Expression initializer,
      DartType declaredType,
      bool hasDeclaredInitializer) {
    // ignore: unnecessary_null_comparison
    assert(declaredType != null);
    InferenceVisitorBase inferrer = new InferenceVisitorBase(this, helper);
    InferenceVisitor visitor = _createInferenceVisitor(inferrer);
    ExpressionInferenceResult result =
        visitor.inferExpression(initializer, declaredType, true);
    if (hasDeclaredInitializer) {
      initializer =
          inferrer.ensureAssignableResult(declaredType, result).expression;
    }
    return initializer;
  }
}

class InferenceVisitorBase {
  final TypeInferrerImpl _inferrer;

  final InferenceHelper? _helper;

  InferenceVisitorBase(this._inferrer, this._helper);

  AssignedVariables<TreeNode, VariableDeclaration> get assignedVariables =>
      _inferrer.assignedVariables;

  FunctionType get unknownFunction => _inferrer.unknownFunction;

  InterfaceType? get thisType => _inferrer.thisType;

  Uri get uriForInstrumentation => _inferrer.uriForInstrumentation;

  Instrumentation? get instrumentation => _inferrer.instrumentation;

  ClassHierarchy get classHierarchy => _inferrer.classHierarchy;

  InferenceDataForTesting? get dataForTesting => _inferrer.dataForTesting;

  FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration, DartType>
      get flowAnalysis => _inferrer.flowAnalysis;

  TypeSchemaEnvironment get typeSchemaEnvironment =>
      _inferrer.typeSchemaEnvironment;

  TypeInferenceEngine get engine => _inferrer.engine;

  bool get isTopLevel => _inferrer.isTopLevel;

  InferenceHelper get helper => _helper!;

  CoreTypes get coreTypes => engine.coreTypes;

  SourceLibraryBuilder get libraryBuilder => _inferrer.libraryBuilder;

  bool get isInferenceUpdate1Enabled =>
      libraryBuilder.isInferenceUpdate1Enabled;

  bool get isNonNullableByDefault => libraryBuilder.isNonNullableByDefault;

  NnbdMode get nnbdMode => libraryBuilder.loader.nnbdMode;

  LibraryFeatures get libraryFeatures => libraryBuilder.libraryFeatures;

  DartType get bottomType =>
      isNonNullableByDefault ? const NeverType.nonNullable() : const NullType();

  DartType computeGreatestClosure(DartType type) {
    return greatestClosure(type, const DynamicType(), bottomType);
  }

  DartType computeGreatestClosure2(DartType type) {
    return greatestClosure(
        type,
        isNonNullableByDefault
            ? coreTypes.objectNullableRawType
            : const DynamicType(),
        bottomType);
  }

  DartType computeNullable(DartType type) {
    if (type is NullType || type is NeverType) {
      return const NullType();
    }
    return type.withDeclaredNullability(libraryBuilder.nullable);
  }

  Expression createReachabilityError(
      int fileOffset, Message errorMessage, Message warningMessage) {
    if (libraryBuilder.loader.target.context.options.warnOnReachabilityCheck &&
        // ignore: unnecessary_null_comparison
        warningMessage != null &&
        !isTopLevel) {
      helper.addProblem(warningMessage, fileOffset, noLength);
    }
    Arguments arguments;
    // ignore: unnecessary_null_comparison
    if (errorMessage != null) {
      arguments = new Arguments([
        new StringLiteral(errorMessage.problemMessage)..fileOffset = fileOffset
      ])
        ..fileOffset = fileOffset;
    } else {
      arguments = new Arguments([])..fileOffset = fileOffset;
    }
    // ignore: unnecessary_null_comparison
    assert(coreTypes.reachabilityErrorConstructor != null);
    return new Throw(
        new ConstructorInvocation(
            coreTypes.reachabilityErrorConstructor, arguments)
          ..fileOffset = fileOffset)
      ..fileOffset = fileOffset;
  }

  /// Computes a list of context messages explaining why [receiver] was not
  /// promoted, to be used when reporting an error for a larger expression
  /// containing [receiver].  [node] is the containing tree node.
  List<LocatedMessage>? getWhyNotPromotedContext(
      Map<DartType, NonPromotionReason>? whyNotPromoted,
      TreeNode node,
      bool Function(DartType) typeFilter) {
    List<LocatedMessage>? context;
    if (whyNotPromoted != null && whyNotPromoted.isNotEmpty) {
      _WhyNotPromotedVisitor whyNotPromotedVisitor =
          new _WhyNotPromotedVisitor(this);
      for (MapEntry<DartType, NonPromotionReason> entry
          in whyNotPromoted.entries) {
        if (!typeFilter(entry.key)) continue;
        LocatedMessage? message = entry.value.accept(whyNotPromotedVisitor);
        if (dataForTesting != null) {
          String nonPromotionReasonText = entry.value.shortName;
          List<String> args = <String>[];
          if (whyNotPromotedVisitor.propertyReference != null) {
            Id id = computeMemberId(whyNotPromotedVisitor.propertyReference!);
            args.add('target: $id');
          }
          if (whyNotPromotedVisitor.propertyType != null) {
            String typeText = typeToText(whyNotPromotedVisitor.propertyType!,
                TypeRepresentation.analyzerNonNullableByDefault);
            args.add('type: $typeText');
          }
          if (args.isNotEmpty) {
            nonPromotionReasonText += '(${args.join(', ')})';
          }
          TreeNode origNode = node;
          while (origNode is VariableGet &&
              origNode.variable.name == null &&
              origNode.variable.initializer != null) {
            // This is a read of a synthetic variable, presumably from a "let".
            // Find the original expression.
            // TODO(johnniwinther): add a general solution for getting the
            // original node for testing.
            origNode = origNode.variable.initializer!;
          }
          dataForTesting!.flowAnalysisResult.nonPromotionReasons[origNode] =
              nonPromotionReasonText;
        }
        // Note: this will always pick the first viable reason (only).  I
        // (paulberry) believe this is the one that will be the most relevant,
        // but I need to do more testing to validate that.  I can't do that
        // additional testing yet because at the moment we only handle failed
        // promotions to non-nullable.
        // TODO(paulberry): do more testing and then expand on the comment
        // above.
        if (message != null) {
          context = [message];
        }
        break;
      }
    }
    return context;
  }

  /// Returns `true` if exceptions should be thrown in paths reachable only due
  /// to unsoundness in flow analysis in mixed mode.
  bool get shouldThrowUnsoundnessException =>
      isNonNullableByDefault && nnbdMode != NnbdMode.Strong;

  void registerIfUnreachableForTesting(TreeNode node, {bool? isReachable}) {
    if (dataForTesting == null) return;
    isReachable ??= flowAnalysis.isReachable;
    if (!isReachable) {
      dataForTesting!.flowAnalysisResult.unreachableNodes.add(node);
    }
  }

  /// Ensures that the type of [member] has been computed.
  void ensureMemberType(Member member) {
    if (member is Constructor) {
      inferConstructorParameterTypes(member);
    }
    TypeDependency? typeDependency = engine.typeDependencies.remove(member);
    if (typeDependency != null) {
      ensureMemberType(typeDependency.original);
      typeDependency.copyInferred();
    }
  }

  /// Ensures that all parameter types of [constructor] have been inferred.
  void inferConstructorParameterTypes(Constructor target) {
    SourceConstructorBuilder? constructor = engine.beingInferred[target];
    if (constructor != null) {
      // There is a cyclic dependency where inferring the types of the
      // initializing formals of a constructor required us to infer the
      // corresponding field type which required us to know the type of the
      // constructor.
      String name = target.enclosingClass.name;
      if (target.name.text.isNotEmpty) {
        // TODO(ahe): Use `inferrer.helper.constructorNameForDiagnostics`
        // instead. However, `inferrer.helper` may be null.
        name += ".${target.name.text}";
      }
      constructor.libraryBuilder.addProblem(
          templateCantInferTypeDueToCircularity.withArguments(name),
          target.fileOffset,
          name.length,
          target.fileUri);
      // TODO(johnniwinther): Is this needed? VariableDeclaration.type is
      // non-nullable so the loops have no effect.
      /*for (VariableDeclaration declaration
          in target.function.positionalParameters) {
        declaration.type ??= const InvalidType();
      }
      for (VariableDeclaration declaration in target.function.namedParameters) {
        declaration.type ??= const InvalidType();
      }*/
    } else if ((constructor = engine.toBeInferred[target]) != null) {
      engine.toBeInferred.remove(target);
      engine.beingInferred[target] = constructor!;
      constructor.inferFormalTypes(classHierarchy);
      engine.beingInferred.remove(target);
    }
  }

  bool isDoubleContext(DartType typeContext) {
    // A context is a double context if double is assignable to it but int is
    // not.  That is the type context is a double context if it is:
    //   * double
    //   * FutureOr<T> where T is a double context
    //
    // We check directly, rather than using isAssignable because it's simpler.
    while (typeContext is FutureOrType) {
      FutureOrType type = typeContext;
      typeContext = type.typeArgument;
    }
    return typeContext is InterfaceType &&
        typeContext.classNode == coreTypes.doubleClass;
  }

  bool isAssignable(DartType contextType, DartType expressionType) {
    if (isNonNullableByDefault) {
      if (expressionType is DynamicType) return true;
      return typeSchemaEnvironment
          .performNullabilityAwareSubtypeCheck(expressionType, contextType)
          .isSubtypeWhenUsingNullabilities();
    }
    return typeSchemaEnvironment
        .performNullabilityAwareSubtypeCheck(expressionType, contextType)
        .orSubtypeCheckFor(contextType, expressionType, typeSchemaEnvironment)
        .isSubtypeWhenIgnoringNullabilities();
  }

  /// Ensures that [expressionType] is assignable to [contextType].
  ///
  /// Checks whether [expressionType] can be assigned to the greatest closure of
  /// [contextType], and inserts an implicit downcast, inserts a tear-off, or
  /// reports an error if appropriate.
  ///
  /// If [declaredContextType] is provided, this is used instead of
  /// [contextType] for reporting the type against which [expressionType] isn't
  /// assignable. This is used when checking the assignability of return
  /// statements in async functions in which the assignability is checked
  /// against the future value type but the reporting should refer to the
  /// declared return type.
  ///
  /// If [runtimeCheckedType] is provided, this is used for the implicit cast,
  /// otherwise [contextType] is used. This is used for return from async
  /// where the returned expression is wrapped in a `Future`, if necessary,
  /// before returned and therefore shouldn't be checked to be a `Future`
  /// directly.
  Expression ensureAssignable(
      DartType expectedType, DartType expressionType, Expression expression,
      {int? fileOffset,
      DartType? declaredContextType,
      DartType? runtimeCheckedType,
      bool isVoidAllowed: false,
      bool coerceExpression: true,
      Template<Message Function(DartType, DartType, bool)>? errorTemplate,
      Template<Message Function(DartType, DartType, bool)>?
          nullabilityErrorTemplate,
      Template<Message Function(DartType, bool)>? nullabilityNullErrorTemplate,
      Template<Message Function(DartType, DartType, bool)>?
          nullabilityNullTypeErrorTemplate,
      Template<Message Function(DartType, DartType, DartType, DartType, bool)>?
          nullabilityPartErrorTemplate,
      Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
    return ensureAssignableResult(expectedType,
            new ExpressionInferenceResult(expressionType, expression),
            fileOffset: fileOffset,
            declaredContextType: declaredContextType,
            runtimeCheckedType: runtimeCheckedType,
            isVoidAllowed: isVoidAllowed,
            coerceExpression: coerceExpression,
            errorTemplate: errorTemplate,
            nullabilityErrorTemplate: nullabilityErrorTemplate,
            nullabilityNullErrorTemplate: nullabilityNullErrorTemplate,
            nullabilityNullTypeErrorTemplate: nullabilityNullTypeErrorTemplate,
            nullabilityPartErrorTemplate: nullabilityPartErrorTemplate,
            whyNotPromoted: whyNotPromoted)
        .expression;
  }

  /// Same as [ensureAssignable], but accepts an [ExpressionInferenceResult]
  /// rather than an expression and a type separately.  If no change is made,
  /// [inferenceResult] is returned unchanged.
  ExpressionInferenceResult ensureAssignableResult(
      DartType contextType, ExpressionInferenceResult inferenceResult,
      {int? fileOffset,
      DartType? declaredContextType,
      DartType? runtimeCheckedType,
      bool isVoidAllowed: false,
      bool coerceExpression: true,
      Template<Message Function(DartType, DartType, bool)>? errorTemplate,
      Template<Message Function(DartType, DartType, bool)>?
          nullabilityErrorTemplate,
      Template<Message Function(DartType, bool)>? nullabilityNullErrorTemplate,
      Template<Message Function(DartType, DartType, bool)>?
          nullabilityNullTypeErrorTemplate,
      Template<Message Function(DartType, DartType, DartType, DartType, bool)>?
          nullabilityPartErrorTemplate,
      Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
    // ignore: unnecessary_null_comparison
    assert(contextType != null);

    // [errorTemplate], [nullabilityErrorTemplate], and
    // [nullabilityPartErrorTemplate] should be provided together.
    assert((errorTemplate == null) == (nullabilityErrorTemplate == null) &&
        (nullabilityErrorTemplate == null) ==
            (nullabilityPartErrorTemplate == null));
    // [nullabilityNullErrorTemplate] and [nullabilityNullTypeErrorTemplate]
    // should be provided together.
    assert((nullabilityNullErrorTemplate == null) ==
        (nullabilityNullTypeErrorTemplate == null));
    errorTemplate ??= templateInvalidAssignmentError;
    if (nullabilityErrorTemplate == null) {
      // Use [templateInvalidAssignmentErrorNullabilityNull] only if no
      // specific [nullabilityErrorTemplate] template was passed.
      nullabilityNullErrorTemplate ??=
          templateInvalidAssignmentErrorNullabilityNull;
    }
    nullabilityNullTypeErrorTemplate ??= nullabilityErrorTemplate ??
        templateInvalidAssignmentErrorNullabilityNullType;
    nullabilityErrorTemplate ??= templateInvalidAssignmentErrorNullability;
    nullabilityPartErrorTemplate ??=
        templateInvalidAssignmentErrorPartNullability;

    // We don't need to insert assignability checks when doing top level type
    // inference since top level type inference only cares about the type that
    // is inferred (the kernel code is discarded).
    if (isTopLevel) return inferenceResult;

    fileOffset ??= inferenceResult.expression.fileOffset;
    contextType = computeGreatestClosure(contextType);

    DartType initialContextType = runtimeCheckedType ?? contextType;

    Template<Message Function(DartType, DartType, bool)>?
        preciseTypeErrorTemplate =
        _getPreciseTypeErrorTemplate(inferenceResult.expression);
    AssignabilityResult assignabilityResult = _computeAssignabilityKind(
        contextType, inferenceResult.inferredType,
        isNonNullableByDefault: isNonNullableByDefault,
        isVoidAllowed: isVoidAllowed,
        isExpressionTypePrecise: preciseTypeErrorTemplate != null,
        coerceExpression: coerceExpression);

    if (assignabilityResult.needsTearOff) {
      TypedTearoff typedTearoff = _tearOffCall(inferenceResult.expression,
          inferenceResult.inferredType as InterfaceType, fileOffset);
      inferenceResult = new ExpressionInferenceResult(
          typedTearoff.tearoffType, typedTearoff.tearoff);
    }
    if (assignabilityResult.implicitInstantiation != null) {
      inferenceResult = _applyImplicitInstantiation(
          assignabilityResult.implicitInstantiation,
          inferenceResult.inferredType,
          inferenceResult.expression);
    }

    DartType expressionType = inferenceResult.inferredType;
    Expression expression = inferenceResult.expression;
    Expression result;
    switch (assignabilityResult.kind) {
      case AssignabilityKind.assignable:
        result = expression;
        break;
      case AssignabilityKind.assignableCast:
        // Insert an implicit downcast.
        result = new AsExpression(expression, initialContextType)
          ..isTypeError = true
          ..isForNonNullableByDefault = isNonNullableByDefault
          ..isForDynamic = expressionType is DynamicType
          ..fileOffset = fileOffset;
        break;
      case AssignabilityKind.unassignable:
        // Error: not assignable.  Perform error recovery.
        result = _wrapUnassignableExpression(
            expression,
            expressionType,
            contextType,
            errorTemplate.withArguments(expressionType,
                declaredContextType ?? contextType, isNonNullableByDefault));
        break;
      case AssignabilityKind.unassignableVoid:
        // Error: not assignable.  Perform error recovery.
        result = helper.wrapInProblem(
            expression, messageVoidExpression, expression.fileOffset, noLength);
        break;
      case AssignabilityKind.unassignablePrecise:
        // The type of the expression is known precisely, so an implicit
        // downcast is guaranteed to fail.  Insert a compile-time error.
        result = helper.wrapInProblem(
            expression,
            preciseTypeErrorTemplate!.withArguments(
                expressionType, contextType, isNonNullableByDefault),
            expression.fileOffset,
            noLength);
        break;
      case AssignabilityKind.unassignableCantTearoff:
        result = _wrapTearoffErrorExpression(
            expression, contextType, templateNullableTearoffError);
        break;
      case AssignabilityKind.unassignableNullability:
        if (expressionType == assignabilityResult.subtype &&
            contextType == assignabilityResult.supertype) {
          if (expression is NullLiteral &&
              nullabilityNullErrorTemplate != null) {
            result = _wrapUnassignableExpression(
                expression,
                expressionType,
                contextType,
                nullabilityNullErrorTemplate.withArguments(
                    declaredContextType ?? contextType,
                    isNonNullableByDefault));
          } else if (expressionType is NullType) {
            result = _wrapUnassignableExpression(
                expression,
                expressionType,
                contextType,
                nullabilityNullTypeErrorTemplate.withArguments(
                    expressionType,
                    declaredContextType ?? contextType,
                    isNonNullableByDefault));
          } else {
            whyNotPromoted ??= flowAnalysis.whyNotPromoted(expression);
            result = _wrapUnassignableExpression(
                expression,
                expressionType,
                contextType,
                nullabilityErrorTemplate.withArguments(expressionType,
                    declaredContextType ?? contextType, isNonNullableByDefault),
                context: getWhyNotPromotedContext(
                    whyNotPromoted.call(),
                    expression,
                    (type) => typeSchemaEnvironment.isSubtypeOf(type,
                        contextType, SubtypeCheckMode.withNullabilities)));
          }
        } else {
          result = _wrapUnassignableExpression(
              expression,
              expressionType,
              contextType,
              nullabilityPartErrorTemplate.withArguments(
                  expressionType,
                  declaredContextType ?? contextType,
                  assignabilityResult.subtype!,
                  assignabilityResult.supertype!,
                  isNonNullableByDefault));
        }
        break;
      default:
        return unhandled("${assignabilityResult}", "ensureAssignable",
            fileOffset, helper.uri);
    }

    if (!identical(result, expression)) {
      flowAnalysis.forwardExpression(result, expression);
      return new ExpressionInferenceResult(expressionType, result);
    } else {
      return inferenceResult;
    }
  }

  Expression _wrapTearoffErrorExpression(Expression expression,
      DartType contextType, Template<Message Function(String)> template) {
    // ignore: unnecessary_null_comparison
    assert(template != null);
    Expression errorNode = new AsExpression(
        expression,
        // TODO(ahe): The outline phase doesn't correctly remove invalid
        // uses of type variables, for example, on static members. Once
        // that has been fixed, we should always be able to use
        // [contextType] directly here.
        hasAnyTypeVariables(contextType)
            ? const NeverType.nonNullable()
            : contextType)
      ..isTypeError = true
      ..fileOffset = expression.fileOffset;
    if (contextType is! InvalidType) {
      errorNode = helper.wrapInProblem(
          errorNode,
          template.withArguments(callName.text),
          errorNode.fileOffset,
          noLength);
    }
    return errorNode;
  }

  Expression _wrapUnassignableExpression(Expression expression,
      DartType expressionType, DartType contextType, Message message,
      {List<LocatedMessage>? context}) {
    Expression errorNode = new AsExpression(
        expression,
        // TODO(ahe): The outline phase doesn't correctly remove invalid
        // uses of type variables, for example, on static members. Once
        // that has been fixed, we should always be able to use
        // [contextType] directly here.
        hasAnyTypeVariables(contextType)
            ? const NeverType.nonNullable()
            : contextType)
      ..isTypeError = true
      ..isForNonNullableByDefault = isNonNullableByDefault
      ..fileOffset = expression.fileOffset;
    if (contextType is! InvalidType && expressionType is! InvalidType) {
      errorNode = helper.wrapInProblem(
          errorNode, message, errorNode.fileOffset, noLength,
          context: context);
    }
    return errorNode;
  }

  TypedTearoff _tearOffCall(
      Expression expression, InterfaceType expressionType, int fileOffset) {
    Class classNode = expressionType.classNode;
    Member callMember = classHierarchy.getInterfaceMember(classNode, callName)!;
    assert(callMember is Procedure && callMember.kind == ProcedureKind.Method);

    // Replace expression with:
    // `let t = expression in t == null ? null : t.call`
    VariableDeclaration t =
        new VariableDeclaration.forValue(expression, type: expressionType)
          ..fileOffset = fileOffset;

    // TODO(johnniwinther): Avoid null-check for non-nullable expressions.
    Expression nullCheck =
        new EqualsNull(new VariableGet(t)..fileOffset = fileOffset)
          ..fileOffset = fileOffset;

    DartType tearoffType =
        getGetterTypeForMemberTarget(callMember, expressionType)
            .withDeclaredNullability(expressionType.nullability);
    Expression tearOff = new InstanceTearOff(
        InstanceAccessKind.Instance, new VariableGet(t), callName,
        interfaceTarget: callMember as Procedure, resultType: tearoffType)
      ..fileOffset = fileOffset;
    ConditionalExpression conditional = new ConditionalExpression(nullCheck,
        new NullLiteral()..fileOffset = fileOffset, tearOff, tearoffType);
    return new TypedTearoff(
        tearoffType, new Let(t, conditional)..fileOffset = fileOffset);
  }

  /// Computes the assignability kind of [expressionType] to [contextType].
  ///
  /// The computation is side-effect free.
  AssignabilityResult _computeAssignabilityKind(
      DartType contextType, DartType expressionType,
      {required bool isNonNullableByDefault,
      required bool isVoidAllowed,
      required bool isExpressionTypePrecise,
      required bool coerceExpression}) {
    // ignore: unnecessary_null_comparison
    assert(isNonNullableByDefault != null);
    // ignore: unnecessary_null_comparison
    assert(isVoidAllowed != null);
    // ignore: unnecessary_null_comparison
    assert(isExpressionTypePrecise != null);

    // If an interface type is being assigned to a function type, see if we
    // should tear off `.call`.
    // TODO(paulberry): use resolveTypeParameter.  See findInterfaceMember.
    bool needsTearoff = false;
    if (coerceExpression && expressionType is InterfaceType) {
      Class classNode = expressionType.classNode;
      Member? callMember =
          classHierarchy.getInterfaceMember(classNode, callName);
      if (callMember is Procedure && callMember.kind == ProcedureKind.Method) {
        if (_shouldTearOffCall(contextType, expressionType)) {
          needsTearoff = true;
          if (isNonNullableByDefault && expressionType.isPotentiallyNullable) {
            return const AssignabilityResult(
                AssignabilityKind.unassignableCantTearoff,
                needsTearOff: false);
          }
          expressionType =
              getGetterTypeForMemberTarget(callMember, expressionType)
                  .withDeclaredNullability(expressionType.nullability);
        }
      }
    }
    ImplicitInstantiation? implicitInstantiation;
    if (coerceExpression && libraryFeatures.constructorTearoffs.isEnabled) {
      implicitInstantiation =
          computeImplicitInstantiation(expressionType, contextType);
      if (implicitInstantiation != null) {
        expressionType = implicitInstantiation.instantiatedType;
      }
    }

    if (expressionType is VoidType && !isVoidAllowed) {
      assert(implicitInstantiation == null);
      assert(!needsTearoff);
      return const AssignabilityResult(AssignabilityKind.unassignableVoid,
          needsTearOff: false);
    }

    IsSubtypeOf isDirectSubtypeResult = typeSchemaEnvironment
        .performNullabilityAwareSubtypeCheck(expressionType, contextType);
    bool isDirectlyAssignable = isNonNullableByDefault
        ? isDirectSubtypeResult.isSubtypeWhenUsingNullabilities()
        : isDirectSubtypeResult.isSubtypeWhenIgnoringNullabilities();
    if (isDirectlyAssignable) {
      return new AssignabilityResult(AssignabilityKind.assignable,
          needsTearOff: needsTearoff,
          implicitInstantiation: implicitInstantiation);
    }

    bool isIndirectlyAssignable = isNonNullableByDefault
        ? expressionType is DynamicType
        : typeSchemaEnvironment
            .performNullabilityAwareSubtypeCheck(contextType, expressionType)
            .isSubtypeWhenIgnoringNullabilities();
    if (!isIndirectlyAssignable) {
      if (isNonNullableByDefault &&
          isDirectSubtypeResult.isSubtypeWhenIgnoringNullabilities()) {
        return new AssignabilityResult.withTypes(
            AssignabilityKind.unassignableNullability,
            isDirectSubtypeResult.subtype,
            isDirectSubtypeResult.supertype,
            needsTearOff: needsTearoff,
            implicitInstantiation: implicitInstantiation);
      } else {
        return new AssignabilityResult(AssignabilityKind.unassignable,
            needsTearOff: needsTearoff,
            implicitInstantiation: implicitInstantiation);
      }
    }
    if (isExpressionTypePrecise) {
      // The type of the expression is known precisely, so an implicit
      // downcast is guaranteed to fail.  Insert a compile-time error.
      assert(implicitInstantiation == null);
      assert(!needsTearoff);
      return const AssignabilityResult(AssignabilityKind.unassignablePrecise,
          needsTearOff: false);
    }

    if (coerceExpression) {
      // Insert an implicit downcast.
      return new AssignabilityResult(AssignabilityKind.assignableCast,
          needsTearOff: needsTearoff,
          implicitInstantiation: implicitInstantiation);
    }

    return new AssignabilityResult(AssignabilityKind.unassignable,
        needsTearOff: needsTearoff,
        implicitInstantiation: implicitInstantiation);
  }

  bool isNull(DartType type) {
    return type is NullType;
  }

  /// Computes the type arguments for an access to an extension instance member
  /// on [extension] with the static [receiverType]. If [explicitTypeArguments]
  /// are provided, these are returned, otherwise type arguments are inferred
  /// using [receiverType].
  List<DartType> computeExtensionTypeArgument(Extension extension,
      List<DartType>? explicitTypeArguments, DartType receiverType) {
    if (explicitTypeArguments != null) {
      assert(explicitTypeArguments.length == extension.typeParameters.length);
      return explicitTypeArguments;
    } else if (extension.typeParameters.isEmpty) {
      assert(explicitTypeArguments == null);
      return const <DartType>[];
    } else {
      return inferExtensionTypeArguments(extension, receiverType);
    }
  }

  /// Infers the type arguments for an access to an extension instance member
  /// on [extension] with the static [receiverType].
  List<DartType> inferExtensionTypeArguments(
      Extension extension, DartType receiverType) {
    List<TypeParameter> typeParameters = extension.typeParameters;
    DartType onType = extension.onType;
    List<DartType> inferredTypes =
        new List<DartType>.filled(typeParameters.length, const UnknownType());
    TypeConstraintGatherer gatherer =
        typeSchemaEnvironment.setupGenericTypeInference(
            null, typeParameters, null, libraryBuilder.library);
    gatherer.constrainArguments([onType], [receiverType]);
    inferredTypes = typeSchemaEnvironment.upwardsInfer(
        gatherer, typeParameters, inferredTypes, libraryBuilder.library);
    return inferredTypes;
  }

  ObjectAccessTarget _findShownExtensionTypeMember(
      ExtensionType receiverType, Name name, int fileOffset,
      {required ObjectAccessTarget defaultTarget,
      required CallSiteAccessKind callSiteAccessKind,
      required bool isPotentiallyNullable}) {
    Extension extension = receiverType.extension;
    ExtensionTypeShowHideClause? showHideClause = extension.showHideClause;
    if (showHideClause == null) return defaultTarget;

    kernel.Reference? reference = showHideClause.findShownReference(
        name, callSiteAccessKind, classHierarchy);
    if (reference != null) {
      return new ObjectAccessTarget.interfaceMember(reference.asMember,
          isPotentiallyNullable: isPotentiallyNullable);
    } else {
      return defaultTarget;
    }
  }

  /// Returns extension member declared immediately for [receiverType].
  ///
  /// If none is found, [defaultTarget] is returned.
  ObjectAccessTarget _findDirectExtensionTypeMember(
      ExtensionType receiverType, Name name, int fileOffset,
      {required ObjectAccessTarget defaultTarget, required bool isSetter}) {
    Member? targetMember;
    Member? targetTearoff;
    ProcedureKind? targetKind;
    for (ExtensionMemberDescriptor descriptor
        in receiverType.extension.members) {
      if (descriptor.name == name) {
        switch (descriptor.kind) {
          case ExtensionMemberKind.Method:
            if (!isSetter) {
              targetMember = descriptor.member.asMember;
              targetTearoff ??= targetMember;
              targetKind = ProcedureKind.Method;
            }
            break;
          case ExtensionMemberKind.TearOff:
            if (!isSetter) {
              targetTearoff = descriptor.member.asMember;
            }
            break;
          case ExtensionMemberKind.Getter:
            if (!isSetter) {
              targetMember = descriptor.member.asMember;
              targetTearoff = null;
              targetKind = ProcedureKind.Getter;
            }
            break;
          case ExtensionMemberKind.Setter:
            if (isSetter) {
              targetMember = descriptor.member.asMember;
              targetTearoff = null;
              targetKind = ProcedureKind.Setter;
            }
            break;
          case ExtensionMemberKind.Operator:
            if (!isSetter) {
              targetMember = descriptor.member.asMember;
              targetTearoff = null;
              targetKind = ProcedureKind.Operator;
            }
            break;
          default:
            unhandled("${descriptor.kind}", "_findDirectExtensionMember",
                fileOffset, libraryBuilder.fileUri);
        }
      }
    }
    if (targetMember != null) {
      assert(targetKind != null);
      return new ObjectAccessTarget.extensionMember(
          targetMember, targetTearoff, targetKind!, receiverType.typeArguments);
    } else {
      return defaultTarget;
    }
  }

  /// Returns the extension member access by the given [name] for a receiver
  /// with the static [receiverType].
  ///
  /// If none is found, [defaultTarget] is returned.
  ///
  /// If multiple are found, none more specific, an
  /// [AmbiguousExtensionAccessTarget] is returned. This access kind results in
  /// a compile-time error, but is used to provide a better message than just
  /// reporting that the receiver does not have a member by the given name.
  ///
  /// If [isPotentiallyNullableAccess] is `true`, the returned extension member
  /// is flagged as a nullable extension member access. This access kind results
  /// in a compile-time error, but is used to provide a better message than just
  /// reporting that the receiver does not have a member by the given name.
  ObjectAccessTarget? _findExtensionMember(
      DartType receiverType, Class classNode, Name name, int fileOffset,
      {bool setter: false,
      ObjectAccessTarget? defaultTarget,
      bool isPotentiallyNullableAccess: false}) {
    Name otherName = name;
    bool otherIsSetter;
    if (name == indexGetName) {
      // [] must be checked against []=.
      otherName = indexSetName;
      otherIsSetter = false;
    } else if (name == indexSetName) {
      // []= must be checked against [].
      otherName = indexGetName;
      otherIsSetter = false;
    } else {
      otherName = name;
      otherIsSetter = !setter;
    }

    Member? otherMember =
        _getInterfaceMember(classNode, otherName, otherIsSetter, fileOffset);
    if (otherMember != null) {
      // If we're looking for `foo` and `foo=` can be found or vice-versa then
      // extension methods should not be found.
      return defaultTarget;
    }

    ExtensionAccessCandidate? bestSoFar;
    List<ExtensionAccessCandidate> noneMoreSpecific = [];
    libraryBuilder.forEachExtensionInScope((ExtensionBuilder extensionBuilder) {
      MemberBuilder? thisBuilder = extensionBuilder
          .lookupLocalMemberByName(name, setter: setter) as MemberBuilder?;
      MemberBuilder? otherBuilder = extensionBuilder.lookupLocalMemberByName(
          otherName,
          setter: otherIsSetter) as MemberBuilder?;
      if ((thisBuilder != null && !thisBuilder.isStatic) ||
          (otherBuilder != null && !otherBuilder.isStatic)) {
        DartType onType;
        DartType onTypeInstantiateToBounds;
        List<DartType> inferredTypeArguments;
        if (extensionBuilder.extension.typeParameters.isEmpty) {
          onTypeInstantiateToBounds =
              onType = extensionBuilder.extension.onType;
          inferredTypeArguments = const <DartType>[];
        } else {
          List<TypeParameter> typeParameters =
              extensionBuilder.extension.typeParameters;
          inferredTypeArguments = inferExtensionTypeArguments(
              extensionBuilder.extension, receiverType);
          Substitution inferredSubstitution =
              Substitution.fromPairs(typeParameters, inferredTypeArguments);

          for (int index = 0; index < typeParameters.length; index++) {
            TypeParameter typeParameter = typeParameters[index];
            DartType typeArgument = inferredTypeArguments[index];
            DartType bound =
                inferredSubstitution.substituteType(typeParameter.bound);
            if (!typeSchemaEnvironment.isSubtypeOf(
                typeArgument, bound, SubtypeCheckMode.withNullabilities)) {
              return;
            }
          }
          onType = inferredSubstitution
              .substituteType(extensionBuilder.extension.onType);
          List<DartType> instantiateToBoundTypeArguments = calculateBounds(
              typeParameters, coreTypes.objectClass, libraryBuilder.library);
          Substitution instantiateToBoundsSubstitution = Substitution.fromPairs(
              typeParameters, instantiateToBoundTypeArguments);
          onTypeInstantiateToBounds = instantiateToBoundsSubstitution
              .substituteType(extensionBuilder.extension.onType);
        }

        if (typeSchemaEnvironment.isSubtypeOf(
            receiverType, onType, SubtypeCheckMode.withNullabilities)) {
          ObjectAccessTarget target = const ObjectAccessTarget.missing();
          if (thisBuilder != null && !thisBuilder.isStatic) {
            if (thisBuilder.isField) {
              if (thisBuilder.isExternal) {
                target = new ObjectAccessTarget.extensionMember(
                    setter ? thisBuilder.writeTarget! : thisBuilder.readTarget!,
                    thisBuilder.readTarget,
                    setter ? ProcedureKind.Setter : ProcedureKind.Getter,
                    inferredTypeArguments,
                    isPotentiallyNullable: isPotentiallyNullableAccess);
              }
            } else {
              target = new ObjectAccessTarget.extensionMember(
                  setter ? thisBuilder.writeTarget! : thisBuilder.invokeTarget!,
                  thisBuilder.readTarget,
                  thisBuilder.kind!,
                  inferredTypeArguments,
                  isPotentiallyNullable: isPotentiallyNullableAccess);
            }
          }
          ExtensionAccessCandidate candidate = new ExtensionAccessCandidate(
              (thisBuilder ?? otherBuilder)!,
              onType,
              onTypeInstantiateToBounds,
              target,
              isPlatform:
                  extensionBuilder.libraryBuilder.importUri.isScheme('dart'));
          if (noneMoreSpecific.isNotEmpty) {
            bool isMostSpecific = true;
            for (ExtensionAccessCandidate other in noneMoreSpecific) {
              bool? isMoreSpecific =
                  candidate.isMoreSpecificThan(typeSchemaEnvironment, other);
              if (isMoreSpecific != true) {
                isMostSpecific = false;
                break;
              }
            }
            if (isMostSpecific) {
              bestSoFar = candidate;
              noneMoreSpecific.clear();
            } else {
              noneMoreSpecific.add(candidate);
            }
          } else if (bestSoFar == null) {
            bestSoFar = candidate;
          } else {
            bool? isMoreSpecific =
                candidate.isMoreSpecificThan(typeSchemaEnvironment, bestSoFar!);
            if (isMoreSpecific == true) {
              bestSoFar = candidate;
            } else if (isMoreSpecific == null) {
              noneMoreSpecific.add(bestSoFar!);
              noneMoreSpecific.add(candidate);
              bestSoFar = null;
            }
          }
        }
      }
    });
    if (bestSoFar != null) {
      return bestSoFar!.target;
    } else {
      if (noneMoreSpecific.isNotEmpty) {
        return new AmbiguousExtensionAccessTarget(noneMoreSpecific);
      }
    }
    return defaultTarget;
  }

  /// Finds a member of [receiverType] called [name], and if it is found,
  /// reports it through instrumentation using [fileOffset].
  ///
  /// For the case where [receiverType] is a [FunctionType], and the name
  /// is `call`, the string 'call' is returned as a sentinel object.
  ///
  /// For the case where [receiverType] is `dynamic`, and the name is declared
  /// in Object, the member from Object is returned though the call may not end
  /// up targeting it if the arguments do not match (the basic principle is that
  /// the Object member is used for inferring types only if noSuchMethod cannot
  /// be targeted due to, e.g., an incorrect argument count).
  ObjectAccessTarget findInterfaceMember(
      DartType receiverType, Name name, int fileOffset,
      {required CallSiteAccessKind callSiteAccessKind,
      bool instrumented: true,
      bool includeExtensionMethods: false}) {
    // ignore: unnecessary_null_comparison
    assert(receiverType != null && isKnown(receiverType));

    bool isSetter = callSiteAccessKind == CallSiteAccessKind.setterInvocation;

    DartType receiverBound = resolveTypeParameter(receiverType);

    bool isReceiverTypePotentiallyNullable = isNonNullableByDefault &&
        receiverType.isPotentiallyNullable &&
        // Calls to `==` are always on a non-null receiver.
        name != equalsName;

    Class classNode = receiverBound is InterfaceType
        ? receiverBound.classNode
        : coreTypes.objectClass;

    if (isReceiverTypePotentiallyNullable) {
      Member? member = _getInterfaceMember(
          coreTypes.objectClass, name, isSetter, fileOffset);
      if (member != null) {
        // Null implements all Object members so this is not considered a
        // potentially nullable access.
        return new ObjectAccessTarget.objectMember(member);
      }
      if (includeExtensionMethods && receiverBound is! DynamicType) {
        ObjectAccessTarget? target = _findExtensionMember(
            isNonNullableByDefault ? receiverType : receiverBound,
            coreTypes.objectClass,
            name,
            fileOffset,
            setter: isSetter);
        if (target != null) {
          return target;
        }
      }
    }

    if (receiverBound is FunctionType && name == callName) {
      return isReceiverTypePotentiallyNullable
          ? const ObjectAccessTarget.nullableCallFunction()
          : const ObjectAccessTarget.callFunction();
    } else if (receiverBound is NeverType) {
      switch (receiverBound.nullability) {
        case Nullability.nonNullable:
          return const ObjectAccessTarget.never();
        case Nullability.nullable:
        case Nullability.legacy:
          // Never? and Never* are equivalent to Null.
          return findInterfaceMember(const NullType(), name, fileOffset,
              callSiteAccessKind: callSiteAccessKind);
        case Nullability.undetermined:
          return internalProblem(
              templateInternalProblemUnsupportedNullability.withArguments(
                  "${receiverBound.nullability}",
                  receiverBound,
                  isNonNullableByDefault),
              fileOffset,
              libraryBuilder.fileUri);
      }
    }

    ObjectAccessTarget? target;
    Member? interfaceMember =
        _getInterfaceMember(classNode, name, isSetter, fileOffset);
    if (interfaceMember != null) {
      target = new ObjectAccessTarget.interfaceMember(interfaceMember,
          isPotentiallyNullable: isReceiverTypePotentiallyNullable);
    } else if (receiverBound is DynamicType) {
      target = const ObjectAccessTarget.dynamic();
    } else if (receiverBound is InvalidType) {
      target = const ObjectAccessTarget.invalid();
    } else if (receiverBound is InterfaceType &&
        receiverBound.classNode == coreTypes.functionClass &&
        name == callName) {
      target = isReceiverTypePotentiallyNullable
          ? const ObjectAccessTarget.nullableCallFunction()
          : const ObjectAccessTarget.callFunction();
    } else if (libraryFeatures.extensionTypes.isEnabled &&
        receiverBound is ExtensionType) {
      target = _findDirectExtensionTypeMember(receiverBound, name, fileOffset,
          isSetter: isSetter,
          defaultTarget: const ObjectAccessTarget.missing());
      if (target.kind == ObjectAccessTargetKind.missing) {
        target = _findShownExtensionTypeMember(receiverBound, name, fileOffset,
            callSiteAccessKind: callSiteAccessKind,
            isPotentiallyNullable: isReceiverTypePotentiallyNullable,
            defaultTarget: const ObjectAccessTarget.missing());
      }
    } else {
      target = const ObjectAccessTarget.missing();
    }
    if (instrumented &&
        receiverBound != const DynamicType() &&
        (target.isInstanceMember || target.isObjectMember)) {
      instrumentation?.record(uriForInstrumentation, fileOffset, 'target',
          new InstrumentationValueForMember(target.member!));
    }

    if (target.isMissing && includeExtensionMethods) {
      if (isReceiverTypePotentiallyNullable) {
        // When the receiver type is potentially nullable we would have found
        // the extension member above, if available. Therefore we know that we
        // are in an erroneous case and instead look up the extension member on
        // the non-nullable receiver bound but flag the found target as a
        // nullable extension member access. This is done to provide the better
        // error message that the extension member exists but that the access is
        // invalid.
        target = _findExtensionMember(
            isNonNullableByDefault
                ? receiverType.toNonNull()
                : receiverBound.toNonNull(),
            classNode,
            name,
            fileOffset,
            setter: isSetter,
            defaultTarget: target,
            isPotentiallyNullableAccess: true)!;
      } else {
        target = _findExtensionMember(
            isNonNullableByDefault ? receiverType : receiverBound,
            classNode,
            name,
            fileOffset,
            setter: isSetter,
            defaultTarget: target)!;
      }
    }
    return target;
  }

  /// If target is missing on a non-dynamic receiver, an error is reported
  /// using [errorTemplate] and an invalid expression is returned.
  Expression? reportMissingInterfaceMember(
      ObjectAccessTarget target,
      DartType receiverType,
      Name name,
      int fileOffset,
      Template<Message Function(String, DartType, bool)> errorTemplate) {
    // ignore: unnecessary_null_comparison
    assert(receiverType != null && isKnown(receiverType));
    // ignore: unnecessary_null_comparison
    if (!isTopLevel && target.isMissing && errorTemplate != null) {
      int length = name.text.length;
      if (identical(name.text, callName.text) ||
          identical(name.text, unaryMinusName.text)) {
        length = 1;
      }
      return helper.buildProblem(
          errorTemplate.withArguments(name.text,
              resolveTypeParameter(receiverType), isNonNullableByDefault),
          fileOffset,
          length);
    }
    return null;
  }

  /// Returns [type] as passed from [superClass] to the current class.
  ///
  /// If a legacy class occurs between the current class and [superClass] then
  /// [type] needs to be legacy erased. For instance
  ///
  ///    // Opt in:
  ///    class Super {
  ///      int extendedMethod(int i, {required int j}) => i;
  ///    }
  ///    class Mixin {
  ///      int mixedInMethod(int i, {required int j}) => i;
  ///    }
  ///    // Opt out:
  ///    class Legacy extends Super with Mixin {}
  ///    // Opt in:
  ///    class Class extends Legacy {
  ///      test() {
  ///        // Ok to call `Legacy.extendedMethod` since its type is
  ///        // `int* Function(int*, {int* j})`.
  ///        super.extendedMethod(null);
  ///        // Ok to call `Legacy.mixedInMethod` since its type is
  ///        // `int* Function(int*, {int* j})`.
  ///        super.mixedInMethod(null);
  ///      }
  ///    }
  ///
  DartType computeTypeFromSuperClass(Class superClass, DartType type) {
    if (needsLegacyErasure(thisType!.classNode, superClass)) {
      type = legacyErasure(type);
    }
    return type;
  }

  /// Returns the type of [target] when accessed as a getter on [receiverType].
  ///
  /// For instance
  ///
  ///    class Class<T> {
  ///      T method() {}
  ///      T getter => null;
  ///    }
  ///
  ///    Class<int> c = ...
  ///    c.method; // The getter type is `int Function()`.
  ///    c.getter; // The getter type is `int`.
  ///
  DartType getGetterType(ObjectAccessTarget target, DartType receiverType) {
    switch (target.kind) {
      case ObjectAccessTargetKind.callFunction:
      case ObjectAccessTargetKind.nullableCallFunction:
        return receiverType;
      case ObjectAccessTargetKind.invalid:
        return const InvalidType();
      case ObjectAccessTargetKind.dynamic:
      case ObjectAccessTargetKind.missing:
      case ObjectAccessTargetKind.ambiguous:
        return const DynamicType();
      case ObjectAccessTargetKind.never:
        return const NeverType.nonNullable();
      case ObjectAccessTargetKind.instanceMember:
      case ObjectAccessTargetKind.objectMember:
      case ObjectAccessTargetKind.nullableInstanceMember:
        return getGetterTypeForMemberTarget(target.member!, receiverType);
      case ObjectAccessTargetKind.extensionMember:
      case ObjectAccessTargetKind.nullableExtensionMember:
        switch (target.extensionMethodKind) {
          case ProcedureKind.Method:
          case ProcedureKind.Operator:
            FunctionType functionType = target.member!.function!
                .computeFunctionType(libraryBuilder.nonNullable);
            List<TypeParameter> extensionTypeParameters = functionType
                .typeParameters
                .take(target.inferredExtensionTypeArguments.length)
                .toList();
            Substitution substitution = Substitution.fromPairs(
                extensionTypeParameters, target.inferredExtensionTypeArguments);
            DartType resultType = substitution.substituteType(new FunctionType(
                functionType.positionalParameters.skip(1).toList(),
                functionType.returnType,
                libraryBuilder.nonNullable,
                namedParameters: functionType.namedParameters,
                typeParameters: functionType.typeParameters
                    .skip(target.inferredExtensionTypeArguments.length)
                    .toList(),
                requiredParameterCount:
                    functionType.requiredParameterCount - 1));
            if (!isNonNullableByDefault) {
              resultType = legacyErasure(resultType);
            }
            return resultType;
          case ProcedureKind.Getter:
            FunctionType functionType = target.member!.function!
                .computeFunctionType(libraryBuilder.nonNullable);
            List<TypeParameter> extensionTypeParameters = functionType
                .typeParameters
                .take(target.inferredExtensionTypeArguments.length)
                .toList();
            Substitution substitution = Substitution.fromPairs(
                extensionTypeParameters, target.inferredExtensionTypeArguments);
            DartType resultType =
                substitution.substituteType(functionType.returnType);
            if (!isNonNullableByDefault) {
              resultType = legacyErasure(resultType);
            }
            return resultType;
          case ProcedureKind.Setter:
          case ProcedureKind.Factory:
            break;
        }
    }
    throw unhandled('$target', 'getGetterType', -1, null);
  }

  /// Returns the getter type of [interfaceMember] on a receiver of type
  /// [receiverType].
  ///
  /// For instance
  ///
  ///    class Class<T> {
  ///      T method() {}
  ///      T getter => null;
  ///    }
  ///
  ///    Class<int> c = ...
  ///    c.method; // The getter type is `int Function()`.
  ///    c.getter; // The getter type is `int`.
  ///
  DartType getGetterTypeForMemberTarget(
      Member interfaceMember, DartType receiverType) {
    Class memberClass = interfaceMember.enclosingClass!;
    assert(interfaceMember is Field || interfaceMember is Procedure,
        "Unexpected interface member $interfaceMember.");
    DartType calleeType = interfaceMember.getterType;
    if (memberClass.typeParameters.isNotEmpty) {
      receiverType = resolveTypeParameter(receiverType);
      if (receiverType is InterfaceType) {
        List<DartType> castedTypeArguments = classHierarchy
            .getTypeArgumentsAsInstanceOf(receiverType, memberClass)!;
        calleeType = Substitution.fromPairs(
                memberClass.typeParameters, castedTypeArguments)
            .substituteType(calleeType);
      }
    }
    if (!isNonNullableByDefault) {
      calleeType = legacyErasure(calleeType);
    }
    return calleeType;
  }

  /// Returns the type of [target] when accessed as an invocation on
  /// [receiverType].
  ///
  /// If the target is known not to be invokable [unknownFunction] is returned.
  ///
  /// For instance
  ///
  ///    class Class<T> {
  ///      T method() {}
  ///      T Function() getter1 => null;
  ///      T getter2 => null;
  ///    }
  ///
  ///    Class<int> c = ...
  ///    c.method; // The getter type is `int Function()`.
  ///    c.getter1; // The getter type is `int Function()`.
  ///    c.getter2; // The getter type is [unknownFunction].
  ///
  FunctionType getFunctionType(
      ObjectAccessTarget target, DartType receiverType) {
    switch (target.kind) {
      case ObjectAccessTargetKind.callFunction:
      case ObjectAccessTargetKind.nullableCallFunction:
        return _getFunctionType(receiverType);
      case ObjectAccessTargetKind.dynamic:
      case ObjectAccessTargetKind.never:
      case ObjectAccessTargetKind.invalid:
      case ObjectAccessTargetKind.missing:
      case ObjectAccessTargetKind.ambiguous:
        return unknownFunction;
      case ObjectAccessTargetKind.instanceMember:
      case ObjectAccessTargetKind.objectMember:
      case ObjectAccessTargetKind.nullableInstanceMember:
        return _getFunctionType(
            getGetterTypeForMemberTarget(target.member!, receiverType));
      case ObjectAccessTargetKind.extensionMember:
      case ObjectAccessTargetKind.nullableExtensionMember:
        switch (target.extensionMethodKind) {
          case ProcedureKind.Method:
          case ProcedureKind.Operator:
            FunctionType functionType = target.member!.function!
                .computeFunctionType(libraryBuilder.nonNullable);
            if (!isNonNullableByDefault) {
              functionType = legacyErasure(functionType) as FunctionType;
            }
            return functionType;
          case ProcedureKind.Getter:
            // TODO(johnniwinther): Handle implicit .call on extension getter.
            return _getFunctionType(target.member!.function!.returnType);
          case ProcedureKind.Setter:
          case ProcedureKind.Factory:
            break;
        }
    }
    throw unhandled('$target', 'getFunctionType', -1, null);
  }

  /// Returns the type of the receiver argument in an access to an extension
  /// member on [extension] with the given extension [typeArguments].
  DartType getExtensionReceiverType(
      Extension extension, List<DartType> typeArguments) {
    DartType receiverType = extension.onType;
    if (extension.typeParameters.isNotEmpty) {
      Substitution substitution =
          Substitution.fromPairs(extension.typeParameters, typeArguments);
      return substitution.substituteType(receiverType);
    }
    return receiverType;
  }

  /// Returns the return type of the invocation of [target] on [receiverType].
  // TODO(johnniwinther): Cleanup [getFunctionType], [getReturnType],
  // [getIndexKeyType] and [getIndexSetValueType]. We shouldn't need that many.
  DartType getReturnType(ObjectAccessTarget target, DartType receiverType) {
    switch (target.kind) {
      case ObjectAccessTargetKind.instanceMember:
      case ObjectAccessTargetKind.objectMember:
      case ObjectAccessTargetKind.nullableInstanceMember:
        FunctionType functionType = _getFunctionType(
            getGetterTypeForMemberTarget(target.member!, receiverType));
        return functionType.returnType;
      case ObjectAccessTargetKind.extensionMember:
      case ObjectAccessTargetKind.nullableExtensionMember:
        switch (target.extensionMethodKind) {
          case ProcedureKind.Operator:
            FunctionType functionType = target.member!.function!
                .computeFunctionType(libraryBuilder.nonNullable);
            DartType returnType = functionType.returnType;
            if (functionType.typeParameters.isNotEmpty) {
              Substitution substitution = Substitution.fromPairs(
                  functionType.typeParameters,
                  target.inferredExtensionTypeArguments);
              returnType = substitution.substituteType(returnType);
            }
            if (!isNonNullableByDefault) {
              returnType = legacyErasure(returnType);
            }
            return returnType;
          default:
            throw unhandled('$target', 'getFunctionType', -1, null);
        }
      case ObjectAccessTargetKind.never:
        return const NeverType.nonNullable();
      case ObjectAccessTargetKind.invalid:
        return const InvalidType();
      case ObjectAccessTargetKind.callFunction:
      case ObjectAccessTargetKind.nullableCallFunction:
      case ObjectAccessTargetKind.dynamic:
      case ObjectAccessTargetKind.missing:
      case ObjectAccessTargetKind.ambiguous:
        break;
    }
    return const DynamicType();
  }

  DartType getPositionalParameterTypeForTarget(
      ObjectAccessTarget target, DartType receiverType, int index) {
    switch (target.kind) {
      case ObjectAccessTargetKind.instanceMember:
      case ObjectAccessTargetKind.objectMember:
      case ObjectAccessTargetKind.nullableInstanceMember:
        FunctionType functionType = _getFunctionType(
            getGetterTypeForMemberTarget(target.member!, receiverType));
        if (functionType.positionalParameters.length > index) {
          return functionType.positionalParameters[index];
        }
        break;
      case ObjectAccessTargetKind.extensionMember:
      case ObjectAccessTargetKind.nullableExtensionMember:
        FunctionType functionType = target.member!.function!
            .computeFunctionType(libraryBuilder.nonNullable);
        if (functionType.positionalParameters.length > index + 1) {
          DartType keyType = functionType.positionalParameters[index + 1];
          if (functionType.typeParameters.isNotEmpty) {
            Substitution substitution = Substitution.fromPairs(
                functionType.typeParameters,
                target.inferredExtensionTypeArguments);
            keyType = substitution.substituteType(keyType);
          }
          if (!isNonNullableByDefault) {
            keyType = legacyErasure(keyType);
          }
          return keyType;
        }
        break;
      case ObjectAccessTargetKind.invalid:
        return const InvalidType();
      case ObjectAccessTargetKind.callFunction:
      case ObjectAccessTargetKind.nullableCallFunction:
      case ObjectAccessTargetKind.dynamic:
      case ObjectAccessTargetKind.never:
      case ObjectAccessTargetKind.missing:
      case ObjectAccessTargetKind.ambiguous:
        break;
    }
    return const DynamicType();
  }

  /// Returns the type of the 'key' parameter in an [] or []= implementation.
  ///
  /// For instance
  ///
  ///    class Class<K, V> {
  ///      V operator [](K key) => null;
  ///      void operator []=(K key, V value) {}
  ///    }
  ///
  ///    extension Extension<K, V> on Class<K, V> {
  ///      V operator [](K key) => null;
  ///      void operator []=(K key, V value) {}
  ///    }
  ///
  ///    new Class<int, String>()[0];             // The key type is `int`.
  ///    new Class<int, String>()[0] = 'foo';     // The key type is `int`.
  ///    Extension<int, String>(null)[0];         // The key type is `int`.
  ///    Extension<int, String>(null)[0] = 'foo'; // The key type is `int`.
  ///
  DartType getIndexKeyType(ObjectAccessTarget target, DartType receiverType) {
    switch (target.kind) {
      case ObjectAccessTargetKind.instanceMember:
      case ObjectAccessTargetKind.objectMember:
      case ObjectAccessTargetKind.nullableInstanceMember:
        FunctionType functionType = _getFunctionType(
            getGetterTypeForMemberTarget(target.member!, receiverType));
        if (functionType.positionalParameters.length >= 1) {
          return functionType.positionalParameters[0];
        }
        break;
      case ObjectAccessTargetKind.extensionMember:
      case ObjectAccessTargetKind.nullableExtensionMember:
        switch (target.extensionMethodKind) {
          case ProcedureKind.Operator:
            FunctionType functionType = target.member!.function!
                .computeFunctionType(libraryBuilder.nonNullable);
            if (functionType.positionalParameters.length >= 2) {
              DartType keyType = functionType.positionalParameters[1];
              if (functionType.typeParameters.isNotEmpty) {
                Substitution substitution = Substitution.fromPairs(
                    functionType.typeParameters,
                    target.inferredExtensionTypeArguments);
                keyType = substitution.substituteType(keyType);
              }
              if (!isNonNullableByDefault) {
                keyType = legacyErasure(keyType);
              }
              return keyType;
            }
            break;
          default:
            throw unhandled('$target', 'getFunctionType', -1, null);
        }
        break;
      case ObjectAccessTargetKind.invalid:
        return const InvalidType();
      case ObjectAccessTargetKind.callFunction:
      case ObjectAccessTargetKind.nullableCallFunction:
      case ObjectAccessTargetKind.dynamic:
      case ObjectAccessTargetKind.never:
      case ObjectAccessTargetKind.missing:
      case ObjectAccessTargetKind.ambiguous:
        break;
    }
    return const DynamicType();
  }

  /// Returns the type of the 'value' parameter in an []= implementation.
  ///
  /// For instance
  ///
  ///    class Class<K, V> {
  ///      void operator []=(K key, V value) {}
  ///    }
  ///
  ///    extension Extension<K, V> on Class<K, V> {
  ///      void operator []=(K key, V value) {}
  ///    }
  ///
  ///    new Class<int, String>()[0] = 'foo';     // The value type is `String`.
  ///    Extension<int, String>(null)[0] = 'foo'; // The value type is `String`.
  ///
  DartType getIndexSetValueType(
      ObjectAccessTarget target, DartType? receiverType) {
    switch (target.kind) {
      case ObjectAccessTargetKind.instanceMember:
      case ObjectAccessTargetKind.objectMember:
      case ObjectAccessTargetKind.nullableInstanceMember:
        FunctionType functionType = _getFunctionType(
            getGetterTypeForMemberTarget(target.member!, receiverType!));
        if (functionType.positionalParameters.length >= 2) {
          return functionType.positionalParameters[1];
        }
        break;
      case ObjectAccessTargetKind.extensionMember:
      case ObjectAccessTargetKind.nullableExtensionMember:
        switch (target.extensionMethodKind) {
          case ProcedureKind.Operator:
            FunctionType functionType = target.member!.function!
                .computeFunctionType(libraryBuilder.nonNullable);
            if (functionType.positionalParameters.length >= 3) {
              DartType indexType = functionType.positionalParameters[2];
              if (functionType.typeParameters.isNotEmpty) {
                Substitution substitution = Substitution.fromPairs(
                    functionType.typeParameters,
                    target.inferredExtensionTypeArguments);
                indexType = substitution.substituteType(indexType);
              }
              if (!isNonNullableByDefault) {
                indexType = legacyErasure(indexType);
              }
              return indexType;
            }
            break;
          default:
            throw unhandled('$target', 'getFunctionType', -1, null);
        }
        break;
      case ObjectAccessTargetKind.invalid:
        return const InvalidType();
      case ObjectAccessTargetKind.callFunction:
      case ObjectAccessTargetKind.nullableCallFunction:
      case ObjectAccessTargetKind.dynamic:
      case ObjectAccessTargetKind.never:
      case ObjectAccessTargetKind.missing:
      case ObjectAccessTargetKind.ambiguous:
        break;
    }
    return const DynamicType();
  }

  FunctionType _getFunctionType(DartType calleeType) {
    calleeType = resolveTypeParameter(calleeType);
    if (calleeType is FunctionType) {
      if (!isNonNullableByDefault) {
        calleeType = legacyErasure(calleeType);
      }
      return calleeType as FunctionType;
    }
    return unknownFunction;
  }

  FunctionType getFunctionTypeForImplicitCall(DartType calleeType) {
    calleeType = resolveTypeParameter(calleeType);
    if (calleeType is FunctionType) {
      if (!isNonNullableByDefault) {
        calleeType = legacyErasure(calleeType);
      }
      return calleeType as FunctionType;
    } else if (calleeType is InterfaceType) {
      Member? member =
          _getInterfaceMember(calleeType.classNode, callName, false, -1);
      if (member != null) {
        DartType callType = getGetterTypeForMemberTarget(member, calleeType);
        if (callType is FunctionType) {
          if (!isNonNullableByDefault) {
            callType = legacyErasure(callType);
          }
          return callType as FunctionType;
        }
      }
    }
    return unknownFunction;
  }

  DartType? getDerivedTypeArgumentOf(DartType type, Class class_) {
    if (type is InterfaceType) {
      List<DartType>? typeArgumentsAsInstanceOfClass =
          classHierarchy.getTypeArgumentsAsInstanceOf(type, class_);
      if (typeArgumentsAsInstanceOfClass != null) {
        return typeArgumentsAsInstanceOfClass[0];
      }
    }
    return null;
  }

  /// If the [member] is a forwarding stub, return the target it forwards to.
  /// Otherwise return the given [member].
  Member getRealTarget(Member member) {
    if (member is Procedure && member.isForwardingStub) {
      return member.abstractForwardingStubTarget!;
    }
    return member;
  }

  DartType getSetterType(ObjectAccessTarget target, DartType receiverType) {
    switch (target.kind) {
      case ObjectAccessTargetKind.dynamic:
      case ObjectAccessTargetKind.never:
      case ObjectAccessTargetKind.missing:
      case ObjectAccessTargetKind.ambiguous:
        return const DynamicType();
      case ObjectAccessTargetKind.invalid:
        return const InvalidType();
      case ObjectAccessTargetKind.instanceMember:
      case ObjectAccessTargetKind.objectMember:
      case ObjectAccessTargetKind.nullableInstanceMember:
        Member interfaceMember = target.member!;
        Class memberClass = interfaceMember.enclosingClass!;
        DartType setterType;
        if (interfaceMember is Procedure) {
          assert(interfaceMember.kind == ProcedureKind.Setter);
          List<VariableDeclaration> setterParameters =
              interfaceMember.function.positionalParameters;
          setterType = setterParameters.length > 0
              ? setterParameters[0].type
              : const DynamicType();
        } else if (interfaceMember is Field) {
          setterType = interfaceMember.type;
        } else {
          throw unhandled(interfaceMember.runtimeType.toString(),
              'getSetterType', -1, null);
        }
        if (memberClass.typeParameters.isNotEmpty) {
          receiverType = resolveTypeParameter(receiverType);
          if (receiverType is InterfaceType) {
            setterType = Substitution.fromPairs(
                    memberClass.typeParameters,
                    classHierarchy.getTypeArgumentsAsInstanceOf(
                        receiverType, memberClass)!)
                .substituteType(setterType);
          }
        }
        if (!isNonNullableByDefault) {
          setterType = legacyErasure(setterType);
        }
        return setterType;
      case ObjectAccessTargetKind.extensionMember:
      case ObjectAccessTargetKind.nullableExtensionMember:
        switch (target.extensionMethodKind) {
          case ProcedureKind.Setter:
            FunctionType functionType = target.member!.function!
                .computeFunctionType(libraryBuilder.nonNullable);
            List<TypeParameter> extensionTypeParameters = functionType
                .typeParameters
                .take(target.inferredExtensionTypeArguments.length)
                .toList();
            Substitution substitution = Substitution.fromPairs(
                extensionTypeParameters, target.inferredExtensionTypeArguments);
            DartType setterType = substitution
                .substituteType(functionType.positionalParameters[1]);
            if (!isNonNullableByDefault) {
              setterType = legacyErasure(setterType);
            }
            return setterType;
          case ProcedureKind.Method:
          case ProcedureKind.Getter:
          case ProcedureKind.Factory:
          case ProcedureKind.Operator:
            break;
        }
        // TODO(johnniwinther): Compute the right setter type.
        return const DynamicType();
      case ObjectAccessTargetKind.callFunction:
      case ObjectAccessTargetKind.nullableCallFunction:
        break;
    }
    throw unhandled(target.runtimeType.toString(), 'getSetterType', -1, null);
  }

  DartType getTypeArgumentOf(DartType type, Class class_) {
    if (type is InterfaceType && identical(type.classNode, class_)) {
      return type.typeArguments[0];
    } else {
      return const UnknownType();
    }
  }

  /// Returns the type used as the inferred type of a variable declaration,
  /// based on the static type of the initializer expression, given by
  /// [initializerType].
  DartType inferDeclarationType(DartType initializerType,
      {bool forSyntheticVariable: false}) {
    if (initializerType is NullType) {
      // If the initializer type is Null or bottom, the inferred type is
      // dynamic.
      // TODO(paulberry): this rule is inherited from analyzer behavior but is
      // not spec'ed anywhere.
      return const DynamicType();
    }
    if (forSyntheticVariable) {
      return normalizeNullabilityInLibrary(
          initializerType, libraryBuilder.library);
    } else {
      return demoteTypeInLibrary(initializerType, libraryBuilder.library);
    }
  }

  NullAwareGuard createNullAwareGuard(VariableDeclaration variable) {
    return new NullAwareGuard(variable, variable.fileOffset, this);
  }

  ExpressionInferenceResult wrapExpressionInferenceResultInProblem(
      ExpressionInferenceResult result,
      Message message,
      int fileOffset,
      int length,
      {List<LocatedMessage>? context}) {
    return createNullAwareExpressionInferenceResult(
        result.inferredType,
        helper.wrapInProblem(
            result.nullAwareAction, message, fileOffset, length,
            context: context),
        result.nullAwareGuards);
  }

  ExpressionInferenceResult createNullAwareExpressionInferenceResult(
      DartType inferredType,
      Expression expression,
      Link<NullAwareGuard>? nullAwareGuards) {
    if (nullAwareGuards != null && nullAwareGuards.isNotEmpty) {
      return new NullAwareExpressionInferenceResult(
          computeNullable(inferredType),
          inferredType,
          nullAwareGuards,
          expression);
    } else {
      return new ExpressionInferenceResult(inferredType, expression);
    }
  }

  InvocationInferenceResult inferInvocation(
      InferenceVisitor visitor,
      DartType typeContext,
      int offset,
      FunctionType calleeType,
      ArgumentsImpl arguments,
      {List<VariableDeclaration>? hoistedExpressions,
      bool isSpecialCasedBinaryOperator: false,
      bool isSpecialCasedTernaryOperator: false,
      DartType? receiverType,
      bool skipTypeArgumentInference: false,
      bool isConst: false,
      bool isImplicitExtensionMember: false,
      bool isImplicitCall: false,
      Member? staticTarget,
      bool isExtensionMemberInvocation = false}) {
    int extensionTypeParameterCount = getExtensionTypeParameterCount(arguments);
    if (extensionTypeParameterCount != 0) {
      return _inferGenericExtensionMethodInvocation(
          visitor,
          extensionTypeParameterCount,
          typeContext,
          offset,
          calleeType,
          arguments,
          hoistedExpressions,
          isSpecialCasedBinaryOperator: isSpecialCasedBinaryOperator,
          isSpecialCasedTernaryOperator: isSpecialCasedTernaryOperator,
          receiverType: receiverType,
          skipTypeArgumentInference: skipTypeArgumentInference,
          isConst: isConst,
          isImplicitExtensionMember: isImplicitExtensionMember);
    }
    return _inferInvocation(
        visitor, typeContext, offset, calleeType, arguments, hoistedExpressions,
        isSpecialCasedBinaryOperator: isSpecialCasedBinaryOperator,
        isSpecialCasedTernaryOperator: isSpecialCasedTernaryOperator,
        receiverType: receiverType,
        skipTypeArgumentInference: skipTypeArgumentInference,
        isConst: isConst,
        isImplicitExtensionMember: isImplicitExtensionMember,
        isImplicitCall: isImplicitCall,
        staticTarget: staticTarget,
        isExtensionMemberInvocation: isExtensionMemberInvocation);
  }

  InvocationInferenceResult _inferGenericExtensionMethodInvocation(
      InferenceVisitor visitor,
      int extensionTypeParameterCount,
      DartType typeContext,
      int offset,
      FunctionType calleeType,
      Arguments arguments,
      List<VariableDeclaration>? hoistedExpressions,
      {bool isSpecialCasedBinaryOperator: false,
      bool isSpecialCasedTernaryOperator: false,
      DartType? receiverType,
      bool skipTypeArgumentInference: false,
      bool isConst: false,
      bool isImplicitExtensionMember: false,
      bool isImplicitCall: false,
      Member? staticTarget}) {
    FunctionType extensionFunctionType = new FunctionType(
        [calleeType.positionalParameters.first],
        const DynamicType(),
        libraryBuilder.nonNullable,
        requiredParameterCount: 1,
        typeParameters: calleeType.typeParameters
            .take(extensionTypeParameterCount)
            .toList());
    ArgumentsImpl extensionArguments = engine.forest.createArguments(
        arguments.fileOffset, [arguments.positional.first],
        types: getExplicitExtensionTypeArguments(arguments));
    _inferInvocation(visitor, const UnknownType(), offset,
        extensionFunctionType, extensionArguments, hoistedExpressions,
        skipTypeArgumentInference: skipTypeArgumentInference,
        receiverType: receiverType,
        isImplicitExtensionMember: isImplicitExtensionMember,
        isImplicitCall: isImplicitCall,
        staticTarget: staticTarget,
        isExtensionMemberInvocation: true);
    Substitution extensionSubstitution = Substitution.fromPairs(
        extensionFunctionType.typeParameters, extensionArguments.types);

    List<TypeParameter> targetTypeParameters = const <TypeParameter>[];
    if (calleeType.typeParameters.length > extensionTypeParameterCount) {
      targetTypeParameters =
          calleeType.typeParameters.skip(extensionTypeParameterCount).toList();
    }
    FunctionType targetFunctionType = new FunctionType(
        calleeType.positionalParameters.skip(1).toList(),
        calleeType.returnType,
        libraryBuilder.nonNullable,
        requiredParameterCount: calleeType.requiredParameterCount - 1,
        namedParameters: calleeType.namedParameters,
        typeParameters: targetTypeParameters);
    targetFunctionType = extensionSubstitution
        .substituteType(targetFunctionType) as FunctionType;
    ArgumentsImpl targetArguments = engine.forest.createArguments(
        arguments.fileOffset, arguments.positional.skip(1).toList(),
        named: arguments.named, types: getExplicitTypeArguments(arguments));
    InvocationInferenceResult result = _inferInvocation(visitor, typeContext,
        offset, targetFunctionType, targetArguments, hoistedExpressions,
        isSpecialCasedBinaryOperator: isSpecialCasedBinaryOperator,
        isSpecialCasedTernaryOperator: isSpecialCasedTernaryOperator,
        skipTypeArgumentInference: skipTypeArgumentInference,
        isConst: isConst,
        isImplicitCall: isImplicitCall,
        staticTarget: staticTarget);
    arguments.positional.clear();
    arguments.positional.addAll(extensionArguments.positional);
    arguments.positional.addAll(targetArguments.positional);
    setParents(arguments.positional, arguments);
    // The `targetArguments.named` is the same list as `arguments.named` so
    // we just need to ensure that parent relations are realigned.
    setParents(arguments.named, arguments);
    arguments.types.clear();
    arguments.types.addAll(extensionArguments.types);
    arguments.types.addAll(targetArguments.types);
    return result;
  }

  /// Performs the type inference steps that are shared by all kinds of
  /// invocations (constructors, instance methods, and static methods).
  InvocationInferenceResult _inferInvocation(
      InferenceVisitor visitor,
      DartType typeContext,
      int offset,
      FunctionType calleeType,
      ArgumentsImpl arguments,
      List<VariableDeclaration>? hoistedExpressions,
      {bool isSpecialCasedBinaryOperator: false,
      bool isSpecialCasedTernaryOperator: false,
      DartType? receiverType,
      bool skipTypeArgumentInference: false,
      bool isConst: false,
      bool isImplicitExtensionMember: false,
      required bool isImplicitCall,
      Member? staticTarget,
      bool isExtensionMemberInvocation: false}) {
    // [receiverType] must be provided for special-cased operators.
    assert(!isSpecialCasedBinaryOperator && !isSpecialCasedTernaryOperator ||
        receiverType != null);

    List<TypeParameter> calleeTypeParameters = calleeType.typeParameters;
    if (calleeTypeParameters.isNotEmpty) {
      // It's possible that one of the callee type parameters might match a type
      // that already exists as part of inference (e.g. the type of an
      // argument).  This might happen, for instance, in the case where a
      // function or method makes a recursive call to itself.  To avoid the
      // callee type parameters accidentally matching a type that already
      // exists, and creating invalid inference results, we need to create fresh
      // type parameters for the callee (see dartbug.com/31759).
      // TODO(paulberry): is it possible to find a narrower set of circumstances
      // in which me must do this, to avoid a performance regression?
      FreshTypeParameters fresh = getFreshTypeParameters(calleeTypeParameters);
      calleeType = fresh.applyToFunctionType(calleeType);
      calleeTypeParameters = fresh.freshTypeParameters;
    }

    List<DartType>? explicitTypeArguments = getExplicitTypeArguments(arguments);

    bool inferenceNeeded = !skipTypeArgumentInference &&
        explicitTypeArguments == null &&
        calleeTypeParameters.isNotEmpty;
    bool typeChecksNeeded = !isTopLevel;
    bool useFormalAndActualTypes = inferenceNeeded ||
        typeChecksNeeded ||
        isSpecialCasedBinaryOperator ||
        isSpecialCasedTernaryOperator;

    List<DartType>? inferredTypes;
    Substitution? substitution;
    List<DartType>? formalTypes;
    List<DartType>? actualTypes;
    if (useFormalAndActualTypes) {
      formalTypes = [];
      actualTypes = [];
    }

    List<VariableDeclaration>? localHoistedExpressions;
    if (libraryFeatures.namedArgumentsAnywhere.isEnabled &&
        arguments.argumentsOriginalOrder != null &&
        hoistedExpressions == null &&
        !isTopLevel &&
        !isConst) {
      hoistedExpressions = localHoistedExpressions = <VariableDeclaration>[];
    }

    TypeConstraintGatherer? gatherer;
    if (inferenceNeeded) {
      // ignore: unnecessary_null_comparison
      if (isConst && typeContext != null) {
        typeContext = new TypeVariableEliminator(
                bottomType,
                isNonNullableByDefault
                    ? coreTypes.objectNullableRawType
                    : coreTypes.objectLegacyRawType)
            .substituteType(typeContext);
      }
      gatherer = typeSchemaEnvironment.setupGenericTypeInference(
          isNonNullableByDefault
              ? calleeType.returnType
              : legacyErasure(calleeType.returnType),
          calleeTypeParameters,
          typeContext,
          libraryBuilder.library);
      inferredTypes = typeSchemaEnvironment.partialInfer(
          gatherer, calleeTypeParameters, null, libraryBuilder.library);
      substitution =
          Substitution.fromPairs(calleeTypeParameters, inferredTypes);
    } else if (explicitTypeArguments != null &&
        calleeTypeParameters.length == explicitTypeArguments.length) {
      substitution =
          Substitution.fromPairs(calleeTypeParameters, explicitTypeArguments);
    } else if (calleeTypeParameters.length != 0) {
      substitution = Substitution.fromPairs(
          calleeTypeParameters,
          new List<DartType>.filled(
              calleeTypeParameters.length, const DynamicType()));
    }
    bool isIdentical =
        staticTarget == typeSchemaEnvironment.coreTypes.identicalProcedure;
    // TODO(paulberry): if we are doing top level inference and type arguments
    // were omitted, report an error.
    List<Object?> argumentsEvaluationOrder;
    if (libraryFeatures.namedArgumentsAnywhere.isEnabled &&
        arguments.argumentsOriginalOrder != null) {
      if (staticTarget?.isExtensionMember ?? false) {
        // Add the receiver.
        argumentsEvaluationOrder = <Object?>[
          arguments.positional[0],
          ...arguments.argumentsOriginalOrder!
        ];
      } else {
        argumentsEvaluationOrder = arguments.argumentsOriginalOrder!;
      }
    } else {
      argumentsEvaluationOrder = <Object?>[
        ...arguments.positional,
        ...arguments.named
      ];
    }
    arguments.argumentsOriginalOrder = null;

    // The following loop determines how many argument expressions should be
    // hoisted to preserve the evaluation order. The computation is based on the
    // following observation: the largest suffix of the argument vector, such
    // that every positional argument in that suffix comes before any named
    // argument, retains the evaluation order after the rest of the arguments
    // are hoisted, and therefore doesn't need to be hoisted itself. The loop
    // below finds the starting position of such suffix and stores it in the
    // [hoistingEndIndex] variable. In case all positional arguments come
    // before all named arguments, the suffix coincides with the entire argument
    // vector, and none of the arguments is hoisted. That way the legacy
    // behavior is preserved.
    int hoistingEndIndex;
    if (libraryFeatures.namedArgumentsAnywhere.isEnabled) {
      hoistingEndIndex = argumentsEvaluationOrder.length - 1;
      for (int i = argumentsEvaluationOrder.length - 2;
          i >= 0 && hoistingEndIndex == i + 1;
          i--) {
        int previousWeight =
            argumentsEvaluationOrder[i + 1] is NamedExpression ? 1 : 0;
        int currentWeight =
            argumentsEvaluationOrder[i] is NamedExpression ? 1 : 0;
        if (currentWeight <= previousWeight) {
          --hoistingEndIndex;
        }
      }
    } else {
      hoistingEndIndex = 0;
    }

    ExpressionInferenceResult inferArgument(
        DartType formalType, Expression argumentExpression,
        {required bool isNamed}) {
      DartType inferredFormalType = substitution != null
          ? substitution.substituteType(formalType)
          : formalType;
      if (!isNamed) {
        if (isSpecialCasedBinaryOperator) {
          inferredFormalType =
              typeSchemaEnvironment.getContextTypeOfSpecialCasedBinaryOperator(
                  typeContext, receiverType!, inferredFormalType,
                  isNonNullableByDefault: isNonNullableByDefault);
        } else if (isSpecialCasedTernaryOperator) {
          inferredFormalType =
              typeSchemaEnvironment.getContextTypeOfSpecialCasedTernaryOperator(
                  typeContext, receiverType!, inferredFormalType,
                  isNonNullableByDefault: isNonNullableByDefault);
        }
      }
      return visitor.inferExpression(
          argumentExpression,
          isNonNullableByDefault
              ? inferredFormalType
              : legacyErasure(inferredFormalType),
          inferenceNeeded ||
              isSpecialCasedBinaryOperator ||
              isSpecialCasedTernaryOperator ||
              typeChecksNeeded);
    }

    List<EqualityInfo<VariableDeclaration, DartType>?>? identicalInfo =
        isIdentical && arguments.positional.length == 2 ? [] : null;
    int positionalIndex = 0;
    int namedIndex = 0;
    List<_DeferredParamInfo>? deferredFunctionLiterals;
    for (int evaluationOrderIndex = 0;
        evaluationOrderIndex < argumentsEvaluationOrder.length;
        evaluationOrderIndex++) {
      Object? argument = argumentsEvaluationOrder[evaluationOrderIndex];
      assert(
          argument is Expression || argument is NamedExpression,
          "Expected the argument to be either an Expression "
          "or a NamedExpression, got '${argument.runtimeType}'.");
      int index;
      DartType formalType;
      Expression argumentExpression;
      bool isExpression = argument is Expression;
      if (isExpression) {
        index = positionalIndex++;
        formalType = getPositionalParameterType(calleeType, index);
        argumentExpression = arguments.positional[index];
      } else {
        index = namedIndex++;
        NamedExpression namedArgument = arguments.named[index];
        formalType = getNamedParameterType(calleeType, namedArgument.name);
        argumentExpression = namedArgument.value;
      }
      if (isExpression && isImplicitExtensionMember && index == 0) {
        assert(
            receiverType != null,
            "No receiver type provided for implicit extension member "
            "invocation.");
        continue;
      }
      Expression unparenthesizedExpression = argumentExpression;
      while (unparenthesizedExpression is ParenthesizedExpression) {
        unparenthesizedExpression = unparenthesizedExpression.expression;
      }
      if (isInferenceUpdate1Enabled &&
          unparenthesizedExpression is FunctionExpression) {
        (deferredFunctionLiterals ??= []).add(new _DeferredParamInfo(
            formalType: formalType,
            argumentExpression: argumentExpression,
            unparenthesizedExpression: unparenthesizedExpression,
            isNamed: !isExpression,
            evaluationOrderIndex: isImplicitExtensionMember
                ? evaluationOrderIndex - 1
                : evaluationOrderIndex,
            index: index));
        // We don't have `identical` info yet, so fill it in with `null` for
        // now.  Later, when we visit the function literal, we'll replace it.
        identicalInfo?.add(null);
        if (useFormalAndActualTypes) {
          formalTypes!.add(formalType);
          // We don't have an inferred type yet, so fill it in with UnknownType
          // for now.  Later, when we infer a type, we'll replace it.
          actualTypes!.add(const UnknownType());
        }
      } else {
        ExpressionInferenceResult result = inferArgument(
            formalType, argumentExpression,
            isNamed: !isExpression);
        DartType inferredType = _computeInferredType(result);
        if (localHoistedExpressions != null &&
            evaluationOrderIndex >= hoistingEndIndex) {
          hoistedExpressions = null;
        }
        Expression expression =
            _hoist(result.expression, inferredType, hoistedExpressions);
        identicalInfo
            ?.add(flowAnalysis.equalityOperand_end(expression, inferredType));
        if (isExpression) {
          arguments.positional[index] = expression..parent = arguments;
        } else {
          NamedExpression namedArgument = arguments.named[index];
          namedArgument.value = expression..parent = namedArgument;
        }
        gatherer?.tryConstrainLower(formalType, inferredType);
        if (useFormalAndActualTypes) {
          formalTypes!.add(formalType);
          actualTypes!.add(inferredType);
        }
      }
    }
    if (deferredFunctionLiterals != null) {
      bool isFirstStage = true;
      for (List<_DeferredParamInfo> stage in new _FunctionLiteralDependencies(
              deferredFunctionLiterals,
              calleeType.typeParameters.toSet(),
              inferenceNeeded
                  ? _computeUndeferredParamInfo(
                      formalTypes!, deferredFunctionLiterals)
                  : const [])
          .planReconciliationStages()) {
        if (gatherer != null && !isFirstStage) {
          inferredTypes = typeSchemaEnvironment.partialInfer(gatherer,
              calleeTypeParameters, inferredTypes, libraryBuilder.library);
          substitution =
              Substitution.fromPairs(calleeTypeParameters, inferredTypes);
        }
        for (_DeferredParamInfo deferredArgument in stage) {
          ExpressionInferenceResult result = inferArgument(
              deferredArgument.formalType, deferredArgument.argumentExpression,
              isNamed: deferredArgument.isNamed);
          DartType inferredType = _computeInferredType(result);
          Expression expression = result.expression;
          identicalInfo?[deferredArgument.evaluationOrderIndex] =
              flowAnalysis.equalityOperand_end(expression, inferredType);
          if (deferredArgument.isNamed) {
            NamedExpression namedArgument =
                arguments.named[deferredArgument.index];
            namedArgument.value = expression..parent = namedArgument;
          } else {
            arguments.positional[deferredArgument.index] = expression
              ..parent = arguments;
          }
          gatherer?.tryConstrainLower(
              deferredArgument.formalType, inferredType);
          if (useFormalAndActualTypes) {
            actualTypes![deferredArgument.evaluationOrderIndex] = inferredType;
          }
        }
        isFirstStage = false;
      }
    }
    if (identicalInfo != null) {
      flowAnalysis.equalityOperation_end(
          arguments.parent as Expression, identicalInfo[0], identicalInfo[1]);
    }
    assert(
        positionalIndex == arguments.positional.length,
        "Expected 'positionalIndex' to be ${arguments.positional.length}, "
        "got ${positionalIndex}.");
    assert(
        namedIndex == arguments.named.length,
        "Expected 'namedIndex' to be ${arguments.named.length}, "
        "got ${namedIndex}.");

    if (isSpecialCasedBinaryOperator || isSpecialCasedTernaryOperator) {
      if (typeChecksNeeded && !identical(calleeType, unknownFunction)) {
        LocatedMessage? argMessage = helper.checkArgumentsForType(
            calleeType, arguments, offset,
            isExtensionMemberInvocation: isExtensionMemberInvocation);
        if (argMessage != null) {
          return new WrapInProblemInferenceResult(
              const InvalidType(),
              const InvalidType(),
              argMessage.messageObject,
              argMessage.charOffset,
              argMessage.length,
              helper,
              isInapplicable: true,
              hoistedArguments: localHoistedExpressions);
        }
      }
      if (isSpecialCasedBinaryOperator) {
        calleeType = replaceReturnType(
            calleeType,
            typeSchemaEnvironment.getTypeOfSpecialCasedBinaryOperator(
                receiverType!, actualTypes![0],
                isNonNullableByDefault: isNonNullableByDefault));
      } else if (isSpecialCasedTernaryOperator) {
        calleeType = replaceReturnType(
            calleeType,
            typeSchemaEnvironment.getTypeOfSpecialCasedTernaryOperator(
                receiverType!,
                actualTypes![0],
                actualTypes[1],
                libraryBuilder.library));
      }
    }

    // Check for and remove duplicated named arguments.
    if (!isTopLevel) {
      List<NamedExpression> named = arguments.named;
      Map<String, NamedExpression> seenNames = <String, NamedExpression>{};
      bool hasProblem = false;
      int namedTypeIndex = arguments.positional.length;
      List<NamedExpression> uniqueNamed = <NamedExpression>[];
      for (NamedExpression expression in named) {
        String name = expression.name;
        if (seenNames.containsKey(name)) {
          hasProblem = true;
          NamedExpression prevNamedExpression = seenNames[name]!;
          prevNamedExpression.value = helper.wrapInProblem(
              _createDuplicateExpression(prevNamedExpression.fileOffset,
                  prevNamedExpression.value, expression.value),
              templateDuplicatedNamedArgument.withArguments(name),
              expression.fileOffset,
              name.length)
            ..parent = prevNamedExpression;
          if (useFormalAndActualTypes) {
            formalTypes!.removeAt(namedTypeIndex);
            actualTypes!.removeAt(namedTypeIndex);
          }
        } else {
          seenNames[name] = expression;
          uniqueNamed.add(expression);
          namedTypeIndex++;
        }
      }
      if (hasProblem) {
        arguments.named = uniqueNamed;
      }
    }

    if (inferenceNeeded) {
      inferredTypes = typeSchemaEnvironment.upwardsInfer(gatherer!,
          calleeTypeParameters, inferredTypes!, libraryBuilder.library);
      assert(inferredTypes.every((type) => isKnown(type)),
          "Unknown type(s) in inferred types: $inferredTypes.");
      assert(inferredTypes.every((type) => !hasPromotedTypeVariable(type)),
          "Promoted type variable(s) in inferred types: $inferredTypes.");
      substitution =
          Substitution.fromPairs(calleeTypeParameters, inferredTypes);
      instrumentation?.record(uriForInstrumentation, offset, 'typeArgs',
          new InstrumentationValueForTypeArgs(inferredTypes));
      arguments.types.clear();
      arguments.types.addAll(inferredTypes);
      if (dataForTesting != null) {
        assert(arguments.fileOffset != TreeNode.noOffset);
        dataForTesting!.typeInferenceResult.inferredTypeArguments[arguments] =
            inferredTypes;
      }
    }
    List<DartType> positionalArgumentTypes = [];
    List<NamedType> namedArgumentTypes = [];
    if (typeChecksNeeded && !identical(calleeType, unknownFunction)) {
      LocatedMessage? argMessage = helper.checkArgumentsForType(
          calleeType, arguments, offset,
          isExtensionMemberInvocation: isExtensionMemberInvocation);
      if (argMessage != null) {
        return new WrapInProblemInferenceResult(
            const InvalidType(),
            const InvalidType(),
            argMessage.messageObject,
            argMessage.charOffset,
            argMessage.length,
            helper,
            isInapplicable: true,
            hoistedArguments: localHoistedExpressions);
      } else {
        // Argument counts and names match. Compare types.
        int positionalShift = isImplicitExtensionMember ? 1 : 0;
        int numPositionalArgs = arguments.positional.length - positionalShift;
        for (int i = 0; i < formalTypes!.length; i++) {
          DartType formalType = formalTypes[i];
          DartType expectedType = substitution != null
              ? substitution.substituteType(formalType)
              : formalType;
          DartType actualType = actualTypes![i];
          Expression expression;
          NamedExpression? namedExpression;
          bool coerceExpression;
          if (i < numPositionalArgs) {
            expression = arguments.positional[positionalShift + i];
            positionalArgumentTypes.add(actualType);
            coerceExpression = !arguments.positionalAreSuperParameters;
          } else {
            namedExpression = arguments.named[i - numPositionalArgs];
            expression = namedExpression.value;
            namedArgumentTypes
                .add(new NamedType(namedExpression.name, actualType));
            coerceExpression = !(arguments.namedSuperParameterNames
                    ?.contains(namedExpression.name) ??
                false);
          }
          expression = ensureAssignable(expectedType, actualType, expression,
              isVoidAllowed: expectedType is VoidType,
              coerceExpression: coerceExpression,
              // TODO(johnniwinther): Specialize message for operator
              // invocations.
              errorTemplate: templateArgumentTypeNotAssignable,
              nullabilityErrorTemplate:
                  templateArgumentTypeNotAssignableNullability,
              nullabilityPartErrorTemplate:
                  templateArgumentTypeNotAssignablePartNullability,
              nullabilityNullErrorTemplate:
                  templateArgumentTypeNotAssignableNullabilityNull,
              nullabilityNullTypeErrorTemplate:
                  templateArgumentTypeNotAssignableNullabilityNullType);
          if (namedExpression == null) {
            arguments.positional[positionalShift + i] = expression
              ..parent = arguments;
          } else {
            namedExpression.value = expression..parent = namedExpression;
          }
        }
      }
    }
    DartType inferredType;
    if (substitution != null) {
      calleeType = substitution.substituteType(calleeType.withoutTypeParameters)
          as FunctionType;
    }
    inferredType = calleeType.returnType;
    assert(
        !containsFreeFunctionTypeVariables(inferredType),
        "Inferred return type $inferredType contains free variables."
        "Inferred function type: $calleeType.");

    if (!isNonNullableByDefault) {
      inferredType = legacyErasure(inferredType);
      calleeType = legacyErasure(calleeType) as FunctionType;
    }

    return new SuccessfulInferenceResult(inferredType, calleeType,
        hoistedArguments: localHoistedExpressions,
        inferredReceiverType: receiverType);
  }

  FunctionType inferLocalFunction(
      InferenceVisitor visitor,
      FunctionNode function,
      DartType? typeContext,
      int fileOffset,
      DartType? returnContext) {
    bool hasImplicitReturnType = false;
    if (returnContext == null) {
      hasImplicitReturnType = true;
      returnContext =
          isNonNullableByDefault ? const UnknownType() : const DynamicType();
    }
    if (!isTopLevel) {
      List<VariableDeclaration> positionalParameters =
          function.positionalParameters;
      for (int i = 0; i < positionalParameters.length; i++) {
        VariableDeclaration parameter = positionalParameters[i];
        flowAnalysis.declare(parameter, true);
        inferMetadataKeepingHelper(visitor, parameter, parameter.annotations);
        if (parameter.initializer != null) {
          ExpressionInferenceResult initializerResult = visitor.inferExpression(
              parameter.initializer!, parameter.type, !isTopLevel);
          parameter.initializer = initializerResult.expression
            ..parent = parameter;
        }
      }
      for (VariableDeclaration parameter in function.namedParameters) {
        flowAnalysis.declare(parameter, true);
        inferMetadataKeepingHelper(visitor, parameter, parameter.annotations);
        ExpressionInferenceResult initializerResult = visitor.inferExpression(
            parameter.initializer!, parameter.type, !isTopLevel);
        parameter.initializer = initializerResult.expression
          ..parent = parameter;
      }
    }

    // Let `<T0, ..., Tn>` be the set of type parameters of the closure (with
    // `n`=0 if there are no type parameters).
    List<TypeParameter> typeParameters = function.typeParameters;

    // Let `(P0 x0, ..., Pm xm)` be the set of formal parameters of the closure
    // (including required, positional optional, and named optional parameters).
    // If any type `Pi` is missing, denote it as `_`.
    List<VariableDeclaration> formals = function.positionalParameters.toList()
      ..addAll(function.namedParameters);

    // Let `B` denote the closure body.  If `B` is an expression function body
    // (`=> e`), treat it as equivalent to a block function body containing a
    // single `return` statement (`{ return e; }`).

    // Attempt to match `K` as a function type compatible with the closure (that
    // is, one having n type parameters and a compatible set of formal
    // parameters).  If there is a successful match, let `<S0, ..., Sn>` be the
    // set of matched type parameters and `(Q0, ..., Qm)` be the set of matched
    // formal parameter types, and let `N` be the return type.
    Substitution substitution;
    List<DartType?> formalTypesFromContext =
        new List<DartType?>.filled(formals.length, null);
    if (typeContext is FunctionType &&
        typeContext.typeParameters.length == typeParameters.length) {
      for (int i = 0; i < formals.length; i++) {
        if (i < function.positionalParameters.length) {
          formalTypesFromContext[i] =
              getPositionalParameterType(typeContext, i);
        } else {
          formalTypesFromContext[i] =
              getNamedParameterType(typeContext, formals[i].name!);
        }
      }
      returnContext = typeContext.returnType;

      // Let `[T/S]` denote the type substitution where each `Si` is replaced
      // with the corresponding `Ti`.
      Map<TypeParameter, DartType> substitutionMap =
          <TypeParameter, DartType>{};
      for (int i = 0; i < typeContext.typeParameters.length; i++) {
        substitutionMap[typeContext.typeParameters[i]] =
            i < typeParameters.length
                ? new TypeParameterType.forAlphaRenaming(
                    typeContext.typeParameters[i], typeParameters[i])
                : const DynamicType();
      }
      substitution = Substitution.fromMap(substitutionMap);
    } else {
      // If the match is not successful because  `K` is `_`, let all `Si`, all
      // `Qi`, and `N` all be `_`.

      // If the match is not successful for any other reason, this will result
      // in a type error, so the implementation is free to choose the best
      // error recovery path.
      substitution = Substitution.empty;
    }

    // Define `Ri` as follows: if `Pi` is not `_`, let `Ri` be `Pi`.
    // Otherwise, if `Qi` is not `_`, let `Ri` be the greatest closure of
    // `Qi[T/S]` with respect to `?`.  Otherwise, let `Ri` be `dynamic`.
    for (int i = 0; i < formals.length; i++) {
      VariableDeclarationImpl formal = formals[i] as VariableDeclarationImpl;
      if (formal.isImplicitlyTyped) {
        DartType inferredType;
        if (formalTypesFromContext[i] != null) {
          inferredType = computeGreatestClosure2(
              substitution.substituteType(formalTypesFromContext[i]!));
          if (typeSchemaEnvironment.isSubtypeOf(
              inferredType,
              const NullType(),
              isNonNullableByDefault
                  ? SubtypeCheckMode.withNullabilities
                  : SubtypeCheckMode.ignoringNullabilities)) {
            inferredType = coreTypes.objectRawType(libraryBuilder.nullable);
          }
        } else {
          inferredType = const DynamicType();
        }
        instrumentation?.record(uriForInstrumentation, formal.fileOffset,
            'type', new InstrumentationValueForType(inferredType));
        formal.type = demoteTypeInLibrary(inferredType, libraryBuilder.library);
        if (dataForTesting != null) {
          dataForTesting!.typeInferenceResult.inferredVariableTypes[formal] =
              formal.type;
        }
      }

      if (isNonNullableByDefault) {
        // If a parameter is a positional or named optional parameter and its
        // type is potentially non-nullable, it should have an initializer.
        bool isOptionalPositional = function.requiredParameterCount <= i &&
            i < function.positionalParameters.length;
        bool isOptionalNamed =
            i >= function.positionalParameters.length && !formal.isRequired;
        if ((isOptionalPositional || isOptionalNamed) &&
            formal.type.isPotentiallyNonNullable &&
            !formal.hasDeclaredInitializer) {
          libraryBuilder.addProblem(
              templateOptionalNonNullableWithoutInitializerError.withArguments(
                  formal.name!, formal.type, isNonNullableByDefault),
              formal.fileOffset,
              formal.name!.length,
              libraryBuilder.importUri);
        }
      }
    }

    if (isNonNullableByDefault) {
      for (VariableDeclaration parameter in function.namedParameters) {
        VariableDeclarationImpl formal = parameter as VariableDeclarationImpl;
        // Required named parameters shouldn't have initializers.
        if (formal.isRequired && formal.hasDeclaredInitializer) {
          libraryBuilder.addProblem(
              templateRequiredNamedParameterHasDefaultValueError
                  .withArguments(formal.name!),
              formal.fileOffset,
              formal.name!.length,
              libraryBuilder.importUri);
        }
      }
    }

    // Let `N'` be `N[T/S]`.  The [ClosureContext] constructor will adjust
    // accordingly if the closure is declared with `async`, `async*`, or
    // `sync*`.
    if (returnContext is! UnknownType) {
      returnContext = substitution.substituteType(returnContext);
    }

    // Apply type inference to `B` in return context `N’`, with any references
    // to `xi` in `B` having type `Pi`.  This produces `B’`.
    bool needToSetReturnType = hasImplicitReturnType;
    ClosureContext closureContext = new ClosureContext(
        this, function.asyncMarker, returnContext, needToSetReturnType);
    StatementInferenceResult bodyResult =
        visitor.inferStatement(function.body!, closureContext);

    // If the closure is declared with `async*` or `sync*`, let `M` be the
    // least upper bound of the types of the `yield` expressions in `B’`, or
    // `void` if `B’` contains no `yield` expressions.  Otherwise, let `M` be
    // the least upper bound of the types of the `return` expressions in `B’`,
    // or `void` if `B’` contains no `return` expressions.
    if (needToSetReturnType) {
      DartType inferredReturnType = closureContext.inferReturnType(this,
          hasImplicitReturn: flowAnalysis.isReachable);

      // Then the result of inference is `<T0, ..., Tn>(R0 x0, ..., Rn xn) B`
      // with type `<T0, ..., Tn>(R0, ..., Rn) -> M’` (with some of the `Ri` and
      // `xi` denoted as optional or named parameters, if appropriate).
      instrumentation?.record(uriForInstrumentation, fileOffset, 'returnType',
          new InstrumentationValueForType(inferredReturnType));
      function.returnType = inferredReturnType;
    }
    bodyResult = closureContext.handleImplicitReturn(
        this, function.body!, bodyResult, fileOffset);
    function.futureValueType = closureContext.futureValueType;
    assert(
        !(function.asyncMarker == AsyncMarker.Async &&
            function.futureValueType == null),
        "No future value type computed.");

    if (bodyResult.hasChanged) {
      function.body = bodyResult.statement..parent = function;
    }
    return function.computeFunctionType(libraryBuilder.nonNullable);
  }

  void inferMetadataKeepingHelper(InferenceVisitor visitor, TreeNode? parent,
      List<Expression>? annotations) {
    if (annotations != null) {
      for (int index = 0; index < annotations.length; index++) {
        ExpressionInferenceResult result = visitor.inferExpression(
            annotations[index], const UnknownType(), !isTopLevel);
        annotations[index] = result.expression..parent = parent;
      }
    }
  }

  StaticInvocation transformExtensionMethodInvocation(int fileOffset,
      ObjectAccessTarget target, Expression receiver, Arguments arguments) {
    assert(target.isExtensionMember || target.isNullableExtensionMember);
    Procedure procedure = target.member as Procedure;
    return engine.forest.createStaticInvocation(
        fileOffset,
        procedure,
        engine.forest.createArgumentsForExtensionMethod(
            arguments.fileOffset,
            target.inferredExtensionTypeArguments.length,
            procedure.function.typeParameters.length -
                target.inferredExtensionTypeArguments.length,
            receiver,
            extensionTypeArguments: target.inferredExtensionTypeArguments,
            positionalArguments: arguments.positional,
            namedArguments: arguments.named,
            typeArguments: arguments.types));
  }

  ExpressionInferenceResult _inferDynamicInvocation(
      InferenceVisitor visitor,
      int fileOffset,
      Link<NullAwareGuard> nullAwareGuards,
      Expression receiver,
      Name name,
      ArgumentsImpl arguments,
      DartType typeContext,
      List<VariableDeclaration>? hoistedExpressions,
      {required bool isImplicitCall}) {
    // ignore: unnecessary_null_comparison
    assert(isImplicitCall != null);
    InvocationInferenceResult result = inferInvocation(
        visitor, typeContext, fileOffset, unknownFunction, arguments,
        hoistedExpressions: hoistedExpressions,
        receiverType: const DynamicType(),
        isImplicitCall: isImplicitCall);
    assert(name != equalsName);
    Expression expression = new DynamicInvocation(
        DynamicAccessKind.Dynamic, receiver, name, arguments)
      ..fileOffset = fileOffset;
    return createNullAwareExpressionInferenceResult(
        result.inferredType, result.applyResult(expression), nullAwareGuards);
  }

  ExpressionInferenceResult _inferNeverInvocation(
      InferenceVisitor visitor,
      int fileOffset,
      Link<NullAwareGuard> nullAwareGuards,
      Expression receiver,
      NeverType receiverType,
      Name name,
      ArgumentsImpl arguments,
      DartType typeContext,
      List<VariableDeclaration>? hoistedExpressions,
      {required bool isImplicitCall}) {
    // ignore: unnecessary_null_comparison
    assert(isImplicitCall != null);
    InvocationInferenceResult result = inferInvocation(
        visitor, typeContext, fileOffset, unknownFunction, arguments,
        hoistedExpressions: hoistedExpressions,
        receiverType: receiverType,
        isImplicitCall: isImplicitCall);
    assert(name != equalsName);
    Expression expression = new DynamicInvocation(
        DynamicAccessKind.Never, receiver, name, arguments)
      ..fileOffset = fileOffset;
    return createNullAwareExpressionInferenceResult(
        const NeverType.nonNullable(),
        result.applyResult(expression),
        nullAwareGuards);
  }

  ExpressionInferenceResult _inferMissingInvocation(
      InferenceVisitor visitor,
      int fileOffset,
      Link<NullAwareGuard> nullAwareGuards,
      Expression receiver,
      DartType receiverType,
      ObjectAccessTarget target,
      Name name,
      ArgumentsImpl arguments,
      DartType typeContext,
      List<VariableDeclaration>? hoistedExpressions,
      {required bool isExpressionInvocation,
      required bool isImplicitCall,
      Name? implicitInvocationPropertyName}) {
    assert(target.isMissing || target.isAmbiguous);
    // ignore: unnecessary_null_comparison
    assert(isExpressionInvocation != null);
    // ignore: unnecessary_null_comparison
    assert(isImplicitCall != null);
    Expression error = createMissingMethodInvocation(
        fileOffset, receiver, receiverType, name, arguments,
        isExpressionInvocation: isExpressionInvocation,
        implicitInvocationPropertyName: implicitInvocationPropertyName,
        extensionAccessCandidates:
            target.isAmbiguous ? target.candidates : null);
    InvocationInferenceResult inferenceResult = inferInvocation(
        visitor, typeContext, fileOffset, unknownFunction, arguments,
        hoistedExpressions: hoistedExpressions,
        receiverType: receiverType,
        isImplicitCall: isExpressionInvocation || isImplicitCall);
    Expression replacementError = inferenceResult.applyResult(error);
    assert(name != equalsName);
    // TODO(johnniwinther): Use InvalidType instead.
    return createNullAwareExpressionInferenceResult(
        const DynamicType(), replacementError, nullAwareGuards);
  }

  ExpressionInferenceResult _inferExtensionInvocation(
      InferenceVisitor visitor,
      int fileOffset,
      Link<NullAwareGuard> nullAwareGuards,
      Expression receiver,
      DartType receiverType,
      ObjectAccessTarget target,
      Name name,
      ArgumentsImpl arguments,
      DartType typeContext,
      List<VariableDeclaration>? hoistedExpressions,
      {required bool isImplicitCall}) {
    // ignore: unnecessary_null_comparison
    assert(isImplicitCall != null);
    assert(target.isExtensionMember || target.isNullableExtensionMember);
    DartType calleeType = getGetterType(target, receiverType);
    FunctionType functionType = getFunctionType(target, receiverType);

    if (target.extensionMethodKind == ProcedureKind.Getter) {
      StaticInvocation staticInvocation = transformExtensionMethodInvocation(
          fileOffset, target, receiver, new Arguments.empty());
      ExpressionInferenceResult result = inferMethodInvocation(
          visitor,
          fileOffset,
          nullAwareGuards,
          staticInvocation,
          calleeType,
          callName,
          arguments,
          typeContext,
          hoistedExpressions: hoistedExpressions,
          isExpressionInvocation: false,
          isImplicitCall: true,
          implicitInvocationPropertyName: name);

      if (!isTopLevel && target.isNullable) {
        // Handles cases like:
        //   C? c;
        //   c();
        // where there is an extension on C defined as:
        //   extension on C {
        //     void Function() get call => () {};
        //   }
        List<LocatedMessage>? context = getWhyNotPromotedContext(
            flowAnalysis.whyNotPromoted(receiver)(),
            staticInvocation,
            (type) => !type.isPotentiallyNullable);
        result = wrapExpressionInferenceResultInProblem(
            result,
            templateNullableExpressionCallError.withArguments(
                receiverType, isNonNullableByDefault),
            fileOffset,
            noLength,
            context: context);
      }

      return result;
    } else {
      StaticInvocation staticInvocation = transformExtensionMethodInvocation(
          fileOffset, target, receiver, arguments);
      InvocationInferenceResult result = inferInvocation(visitor, typeContext,
          fileOffset, functionType, staticInvocation.arguments as ArgumentsImpl,
          hoistedExpressions: hoistedExpressions,
          receiverType: receiverType,
          isImplicitExtensionMember: true,
          isImplicitCall: isImplicitCall,
          isExtensionMemberInvocation: true);
      if (!isTopLevel) {
        libraryBuilder.checkBoundsInStaticInvocation(staticInvocation,
            typeSchemaEnvironment, helper.uri, getTypeArgumentsInfo(arguments));
      }

      Expression replacement = result.applyResult(staticInvocation);
      if (!isTopLevel && target.isNullable) {
        List<LocatedMessage>? context = getWhyNotPromotedContext(
            flowAnalysis.whyNotPromoted(receiver)(),
            staticInvocation,
            (type) => !type.isPotentiallyNullable);
        if (isImplicitCall) {
          // Handles cases like:
          //   int? i;
          //   i();
          // where there is an extension:
          //   extension on int {
          //     void call() {}
          //   }
          replacement = helper.wrapInProblem(
              replacement,
              templateNullableExpressionCallError.withArguments(
                  receiverType, isNonNullableByDefault),
              fileOffset,
              noLength,
              context: context);
        } else {
          // Handles cases like:
          //   int? i;
          //   i.methodOnNonNullInt();
          // where `methodOnNonNullInt` is declared in an extension:
          //   extension on int {
          //     void methodOnNonNullInt() {}
          //   }
          replacement = helper.wrapInProblem(
              replacement,
              templateNullableMethodCallError.withArguments(
                  name.text, receiverType, isNonNullableByDefault),
              fileOffset,
              name.text.length,
              context: context);
        }
      }
      return createNullAwareExpressionInferenceResult(
          result.inferredType, replacement, nullAwareGuards);
    }
  }

  ExpressionInferenceResult _inferFunctionInvocation(
      InferenceVisitor visitor,
      int fileOffset,
      Link<NullAwareGuard> nullAwareGuards,
      Expression receiver,
      DartType receiverType,
      ObjectAccessTarget target,
      ArgumentsImpl arguments,
      DartType typeContext,
      List<VariableDeclaration>? hoistedExpressions,
      {required bool isImplicitCall}) {
    // ignore: unnecessary_null_comparison
    assert(isImplicitCall != null);
    assert(target.isCallFunction || target.isNullableCallFunction);
    FunctionType declaredFunctionType = getFunctionType(target, receiverType);
    InvocationInferenceResult result = inferInvocation(
        visitor, typeContext, fileOffset, declaredFunctionType, arguments,
        hoistedExpressions: hoistedExpressions,
        receiverType: receiverType,
        isImplicitCall: isImplicitCall);
    Expression? expression;
    String? localName;

    DartType inferredFunctionType = result.functionType;
    if (result.isInapplicable) {
      // This was a function invocation whose arguments didn't match
      // the parameters.
      expression = new FunctionInvocation(
          FunctionAccessKind.Inapplicable, receiver, arguments,
          functionType: null)
        ..fileOffset = fileOffset;
    } else if (receiver is VariableGet) {
      VariableDeclaration variable = receiver.variable;
      TreeNode? parent = variable.parent;
      if (parent is FunctionDeclaration) {
        assert(!identical(inferredFunctionType, unknownFunction),
            "Unknown function type for local function invocation.");
        localName = variable.name!;
        expression = new LocalFunctionInvocation(variable, arguments,
            functionType: inferredFunctionType as FunctionType)
          ..fileOffset = receiver.fileOffset;
      }
    }
    expression ??= new FunctionInvocation(
        target.isNullableCallFunction
            ? FunctionAccessKind.Nullable
            : (identical(inferredFunctionType, unknownFunction)
                ? FunctionAccessKind.Function
                : FunctionAccessKind.FunctionType),
        receiver,
        arguments,
        functionType: identical(inferredFunctionType, unknownFunction)
            ? null
            : inferredFunctionType as FunctionType)
      ..fileOffset = fileOffset;

    _checkBoundsInFunctionInvocation(
        declaredFunctionType, localName, arguments, fileOffset);

    Expression replacement = result.applyResult(expression);
    if (!isTopLevel && target.isNullableCallFunction) {
      List<LocatedMessage>? context = getWhyNotPromotedContext(
          flowAnalysis.whyNotPromoted(receiver)(),
          expression,
          (type) => !type.isPotentiallyNullable);
      if (isImplicitCall) {
        // Handles cases like:
        //   void Function()? f;
        //   f();
        replacement = helper.wrapInProblem(
            replacement,
            templateNullableExpressionCallError.withArguments(
                receiverType, isNonNullableByDefault),
            fileOffset,
            noLength,
            context: context);
      } else {
        // Handles cases like:
        //   void Function()? f;
        //   f.call();
        replacement = helper.wrapInProblem(
            replacement,
            templateNullableMethodCallError.withArguments(
                callName.text, receiverType, isNonNullableByDefault),
            fileOffset,
            callName.text.length,
            context: context);
      }
    }
    // TODO(johnniwinther): Check that type arguments against the bounds.
    return createNullAwareExpressionInferenceResult(
        result.inferredType, replacement, nullAwareGuards);
  }

  FunctionType _computeFunctionTypeForArguments(
      Arguments arguments, DartType type) {
    return new FunctionType(
        new List<DartType>.filled(arguments.positional.length, type),
        type,
        libraryBuilder.nonNullable,
        namedParameters: new List<NamedType>.generate(arguments.named.length,
            (int index) => new NamedType(arguments.named[index].name, type)));
  }

  ExpressionInferenceResult _inferInstanceMethodInvocation(
      InferenceVisitor visitor,
      int fileOffset,
      Link<NullAwareGuard> nullAwareGuards,
      Expression receiver,
      DartType receiverType,
      ObjectAccessTarget target,
      Arguments arguments,
      DartType typeContext,
      List<VariableDeclaration>? hoistedExpressions,
      {required bool isImplicitCall,
      required bool isSpecialCasedBinaryOperator,
      required bool isSpecialCasedTernaryOperator}) {
    // ignore: unnecessary_null_comparison
    assert(isImplicitCall != null);
    // ignore: unnecessary_null_comparison
    assert(isSpecialCasedBinaryOperator != null);
    // ignore: unnecessary_null_comparison
    assert(isSpecialCasedTernaryOperator != null);
    assert(target.isInstanceMember ||
        target.isObjectMember ||
        target.isNullableInstanceMember);
    Procedure? method = target.member as Procedure;
    assert(method.kind == ProcedureKind.Method,
        "Unexpected instance method $method");
    Name methodName = method.name;

    if (receiverType == const DynamicType()) {
      FunctionNode signature = method.function;
      if (arguments.positional.length < signature.requiredParameterCount ||
          arguments.positional.length > signature.positionalParameters.length) {
        target = const ObjectAccessTarget.dynamic();
        method = null;
      }
      for (NamedExpression argument in arguments.named) {
        if (!signature.namedParameters
            .any((declaration) => declaration.name == argument.name)) {
          target = const ObjectAccessTarget.dynamic();
          method = null;
        }
      }
      if (instrumentation != null && method != null) {
        instrumentation!.record(uriForInstrumentation, fileOffset, 'target',
            new InstrumentationValueForMember(method));
      }
    }

    DartType calleeType = getGetterType(target, receiverType);
    FunctionType declaredFunctionType = getFunctionType(target, receiverType);

    bool contravariantCheck = false;
    if (receiver is! ThisExpression &&
        method != null &&
        returnedTypeParametersOccurNonCovariantly(
            method.enclosingClass!, method.function.returnType)) {
      contravariantCheck = true;
    }
    InvocationInferenceResult result = inferInvocation(visitor, typeContext,
        fileOffset, declaredFunctionType, arguments as ArgumentsImpl,
        hoistedExpressions: hoistedExpressions,
        receiverType: receiverType,
        isImplicitCall: isImplicitCall,
        isSpecialCasedBinaryOperator: isSpecialCasedBinaryOperator,
        isSpecialCasedTernaryOperator: isSpecialCasedTernaryOperator);

    Expression expression;
    DartType inferredFunctionType = result.functionType;
    if (target.isDynamic) {
      // This was an Object member invocation whose arguments didn't match
      // the parameters.
      expression = new DynamicInvocation(
          DynamicAccessKind.Dynamic, receiver, methodName, arguments)
        ..fileOffset = fileOffset;
    } else if (result.isInapplicable) {
      // This was a method invocation whose arguments didn't match
      // the parameters.
      expression = new InstanceInvocation(
          InstanceAccessKind.Inapplicable, receiver, methodName, arguments,
          functionType:
              _computeFunctionTypeForArguments(arguments, const InvalidType()),
          interfaceTarget: method!)
        ..fileOffset = fileOffset;
    } else {
      assert(
          inferredFunctionType is FunctionType &&
              !identical(unknownFunction, inferredFunctionType),
          "No function type found for $receiver.$methodName ($target) on "
          "$receiverType");
      InstanceAccessKind kind;
      switch (target.kind) {
        case ObjectAccessTargetKind.instanceMember:
          kind = InstanceAccessKind.Instance;
          break;
        case ObjectAccessTargetKind.nullableInstanceMember:
          kind = InstanceAccessKind.Nullable;
          break;
        case ObjectAccessTargetKind.objectMember:
          kind = InstanceAccessKind.Object;
          break;
        default:
          throw new UnsupportedError('Unexpected target kind $target');
      }
      expression = new InstanceInvocation(kind, receiver, methodName, arguments,
          functionType: inferredFunctionType as FunctionType,
          interfaceTarget: method!)
        ..fileOffset = fileOffset;
    }
    Expression replacement;
    if (contravariantCheck) {
      // TODO(johnniwinther): Merge with the replacement computation below.
      replacement = new AsExpression(expression, result.inferredType)
        ..isTypeError = true
        ..isCovarianceCheck = true
        ..isForNonNullableByDefault = isNonNullableByDefault
        ..fileOffset = fileOffset;
      if (instrumentation != null) {
        int offset =
            arguments.fileOffset == -1 ? fileOffset : arguments.fileOffset;
        instrumentation!.record(uriForInstrumentation, offset, 'checkReturn',
            new InstrumentationValueForType(result.inferredType));
      }
    } else {
      replacement = expression;
    }

    _checkBoundsInMethodInvocation(
        target, receiverType, calleeType, methodName, arguments, fileOffset);

    replacement = result.applyResult(replacement);
    if (!isTopLevel && target.isNullable) {
      List<LocatedMessage>? context = getWhyNotPromotedContext(
          flowAnalysis.whyNotPromoted(receiver)(),
          expression,
          (type) => !type.isPotentiallyNullable);
      if (isImplicitCall) {
        // Handles cases like:
        //   C? c;
        //   c();
        // Where C is defined as:
        //   class C {
        //     void call();
        //   }
        replacement = helper.wrapInProblem(
            replacement,
            templateNullableExpressionCallError.withArguments(
                receiverType, isNonNullableByDefault),
            fileOffset,
            noLength,
            context: context);
      } else {
        // Handles cases like:
        //   int? i;
        //   i.abs();
        replacement = helper.wrapInProblem(
            replacement,
            templateNullableMethodCallError.withArguments(
                methodName.text, receiverType, isNonNullableByDefault),
            fileOffset,
            methodName.text.length,
            context: context);
      }
    }

    return createNullAwareExpressionInferenceResult(
        result.inferredType, replacement, nullAwareGuards);
  }

  ExpressionInferenceResult _inferInstanceGetterInvocation(
      InferenceVisitor visitor,
      int fileOffset,
      Link<NullAwareGuard> nullAwareGuards,
      Expression receiver,
      DartType receiverType,
      ObjectAccessTarget target,
      ArgumentsImpl arguments,
      DartType typeContext,
      List<VariableDeclaration>? hoistedExpressions,
      {required bool isExpressionInvocation}) {
    // ignore: unnecessary_null_comparison
    assert(isExpressionInvocation != null);
    assert(target.isInstanceMember ||
        target.isObjectMember ||
        target.isNullableInstanceMember);
    Procedure? getter = target.member as Procedure;
    assert(getter.kind == ProcedureKind.Getter);

    // TODO(johnniwinther): This is inconsistent with the handling below. Remove
    // this or add handling similar to [_inferMethodInvocation].
    if (receiverType == const DynamicType()) {
      FunctionNode signature = getter.function;
      if (arguments.positional.length < signature.requiredParameterCount ||
          arguments.positional.length > signature.positionalParameters.length) {
        target = const ObjectAccessTarget.dynamic();
        getter = null;
      }
      for (NamedExpression argument in arguments.named) {
        if (!signature.namedParameters
            .any((declaration) => declaration.name == argument.name)) {
          target = const ObjectAccessTarget.dynamic();
          getter = null;
        }
      }
      if (instrumentation != null && getter != null) {
        instrumentation!.record(uriForInstrumentation, fileOffset, 'target',
            new InstrumentationValueForMember(getter));
      }
    }

    DartType calleeType = getGetterType(target, receiverType);
    FunctionType functionType = getFunctionTypeForImplicitCall(calleeType);

    List<VariableDeclaration>? locallyHoistedExpressions;
    if (hoistedExpressions == null && !isTopLevel) {
      // We don't hoist in top-level inference.
      hoistedExpressions = locallyHoistedExpressions = <VariableDeclaration>[];
    }
    if (arguments.positional.isNotEmpty || arguments.named.isNotEmpty) {
      receiver = _hoist(receiver, receiverType, hoistedExpressions);
    }

    Name originalName = getter!.name;
    Expression originalReceiver = receiver;
    Member originalTarget = getter;
    InstanceAccessKind kind;
    switch (target.kind) {
      case ObjectAccessTargetKind.instanceMember:
        kind = InstanceAccessKind.Instance;
        break;
      case ObjectAccessTargetKind.nullableInstanceMember:
        kind = InstanceAccessKind.Nullable;
        break;
      case ObjectAccessTargetKind.objectMember:
        kind = InstanceAccessKind.Object;
        break;
      default:
        throw new UnsupportedError('Unexpected target kind $target');
    }
    InstanceGet originalPropertyGet = new InstanceGet(
        kind, originalReceiver, originalName,
        resultType: calleeType, interfaceTarget: originalTarget)
      ..fileOffset = fileOffset;
    Expression propertyGet = originalPropertyGet;
    if (calleeType is! DynamicType &&
        receiver is! ThisExpression &&
        returnedTypeParametersOccurNonCovariantly(
            getter.enclosingClass!, getter.function.returnType)) {
      propertyGet = new AsExpression(propertyGet, functionType)
        ..isTypeError = true
        ..isCovarianceCheck = true
        ..isForNonNullableByDefault = isNonNullableByDefault
        ..fileOffset = fileOffset;
      if (instrumentation != null) {
        int offset =
            arguments.fileOffset == -1 ? fileOffset : arguments.fileOffset;
        instrumentation!.record(uriForInstrumentation, offset,
            'checkGetterReturn', new InstrumentationValueForType(functionType));
      }
    }

    if (isExpressionInvocation) {
      if (isTopLevel) {
        // Create an expression invocation for reporting the error during
        // full inference.
        return new ExpressionInferenceResult(
            const InvalidType(),
            new ExpressionInvocation(receiver, arguments)
              ..fileOffset = fileOffset);
      } else {
        Expression error = helper.buildProblem(
            templateImplicitCallOfNonMethod.withArguments(
                receiverType, isNonNullableByDefault),
            fileOffset,
            noLength);
        return new ExpressionInferenceResult(const InvalidType(), error);
      }
    }

    ExpressionInferenceResult invocationResult = inferMethodInvocation(
        visitor,
        arguments.fileOffset,
        const Link<NullAwareGuard>(),
        propertyGet,
        calleeType,
        callName,
        arguments,
        typeContext,
        hoistedExpressions: hoistedExpressions,
        isExpressionInvocation: false,
        isImplicitCall: true,
        implicitInvocationPropertyName: getter.name);

    if (!isTopLevel && target.isNullable) {
      // Handles cases like:
      //   C? c;
      //   c.foo();
      // Where C is defined as:
      //   class C {
      //     void Function() get foo => () {};
      //   }
      List<LocatedMessage>? context = getWhyNotPromotedContext(
          flowAnalysis.whyNotPromoted(receiver)(),
          invocationResult.expression,
          (type) => !type.isPotentiallyNullable);
      invocationResult = wrapExpressionInferenceResultInProblem(
          invocationResult,
          templateNullableExpressionCallError.withArguments(
              receiverType, isNonNullableByDefault),
          fileOffset,
          noLength,
          context: context);
    }

    if (!libraryBuilder
        .loader.target.backendTarget.supportsExplicitGetterCalls) {
      // TODO(johnniwinther): Remove this when dart2js/ddc supports explicit
      //  getter calls.
      Expression nullAwareAction = invocationResult.nullAwareAction;
      if (nullAwareAction is InstanceInvocation &&
          nullAwareAction.receiver == originalPropertyGet) {
        invocationResult = new ExpressionInferenceResult(
            invocationResult.inferredType,
            new InstanceGetterInvocation(originalPropertyGet.kind,
                originalReceiver, originalName, nullAwareAction.arguments,
                interfaceTarget: originalTarget,
                functionType: nullAwareAction.functionType)
              ..fileOffset = nullAwareAction.fileOffset);
      } else if (nullAwareAction is DynamicInvocation &&
          nullAwareAction.receiver == originalPropertyGet) {
        invocationResult = new ExpressionInferenceResult(
            invocationResult.inferredType,
            new InstanceGetterInvocation(originalPropertyGet.kind,
                originalReceiver, originalName, nullAwareAction.arguments,
                interfaceTarget: originalTarget, functionType: null)
              ..fileOffset = nullAwareAction.fileOffset);
      } else if (nullAwareAction is FunctionInvocation &&
          nullAwareAction.receiver == originalPropertyGet) {
        invocationResult = new ExpressionInferenceResult(
            invocationResult.inferredType,
            new InstanceGetterInvocation(originalPropertyGet.kind,
                originalReceiver, originalName, nullAwareAction.arguments,
                interfaceTarget: originalTarget,
                functionType: nullAwareAction.functionType)
              ..fileOffset = nullAwareAction.fileOffset);
      }
    }
    invocationResult =
        _insertHoistedExpression(invocationResult, locallyHoistedExpressions);
    return createNullAwareExpressionInferenceResult(
        invocationResult.inferredType,
        invocationResult.expression,
        nullAwareGuards);
  }

  Expression _hoist(Expression expression, DartType type,
      List<VariableDeclaration>? hoistedExpressions) {
    if (hoistedExpressions != null &&
        expression is! ThisExpression &&
        expression is! FunctionExpression) {
      VariableDeclaration variable = createVariable(expression, type);
      hoistedExpressions.add(variable);
      return createVariableGet(variable);
    }
    return expression;
  }

  ExpressionInferenceResult _insertHoistedExpression(
      ExpressionInferenceResult result,
      List<VariableDeclaration>? hoistedExpressions) {
    if (hoistedExpressions != null && hoistedExpressions.isNotEmpty) {
      Expression expression = result.nullAwareAction;
      for (int index = hoistedExpressions.length - 1; index >= 0; index--) {
        expression = createLet(hoistedExpressions[index], expression);
      }
      return createNullAwareExpressionInferenceResult(
          result.inferredType, expression, result.nullAwareGuards);
    }
    return result;
  }

  ExpressionInferenceResult _inferInstanceFieldInvocation(
      InferenceVisitor visitor,
      int fileOffset,
      Link<NullAwareGuard> nullAwareGuards,
      Expression receiver,
      DartType receiverType,
      ObjectAccessTarget target,
      ArgumentsImpl arguments,
      DartType typeContext,
      List<VariableDeclaration>? hoistedExpressions,
      {required bool isExpressionInvocation}) {
    // ignore: unnecessary_null_comparison
    assert(isExpressionInvocation != null);
    assert(target.isInstanceMember ||
        target.isObjectMember ||
        target.isNullableInstanceMember);
    Field field = target.member as Field;

    DartType calleeType = getGetterType(target, receiverType);
    FunctionType functionType = getFunctionTypeForImplicitCall(calleeType);

    List<VariableDeclaration>? locallyHoistedExpressions;
    if (hoistedExpressions == null && !isTopLevel) {
      // We don't hoist in top-level inference.
      hoistedExpressions = locallyHoistedExpressions = <VariableDeclaration>[];
    }
    if (arguments.positional.isNotEmpty || arguments.named.isNotEmpty) {
      receiver = _hoist(receiver, receiverType, hoistedExpressions);
    }

    Map<DartType, NonPromotionReason> Function()? whyNotPromoted;
    if (!isTopLevel && target.isNullable) {
      // We won't report the error until later (after we have an
      // invocationResult), but we need to gather "why not promoted" info now,
      // before we tell flow analysis about the property get.
      whyNotPromoted = flowAnalysis.whyNotPromoted(receiver);
    }

    Name originalName = field.name;
    Expression originalReceiver = receiver;
    Member originalTarget = field;
    InstanceAccessKind kind;
    switch (target.kind) {
      case ObjectAccessTargetKind.instanceMember:
        kind = InstanceAccessKind.Instance;
        break;
      case ObjectAccessTargetKind.nullableInstanceMember:
        kind = InstanceAccessKind.Nullable;
        break;
      case ObjectAccessTargetKind.objectMember:
        kind = InstanceAccessKind.Object;
        break;
      default:
        throw new UnsupportedError('Unexpected target kind $target');
    }
    InstanceGet originalPropertyGet = new InstanceGet(
        kind, originalReceiver, originalName,
        resultType: calleeType, interfaceTarget: originalTarget)
      ..fileOffset = fileOffset;
    flowAnalysis.propertyGet(originalPropertyGet, originalReceiver,
        originalName.text, originalTarget, calleeType);
    Expression propertyGet = originalPropertyGet;
    if (receiver is! ThisExpression &&
        calleeType is! DynamicType &&
        returnedTypeParametersOccurNonCovariantly(
            field.enclosingClass!, field.type)) {
      propertyGet = new AsExpression(propertyGet, functionType)
        ..isTypeError = true
        ..isCovarianceCheck = true
        ..isForNonNullableByDefault = isNonNullableByDefault
        ..fileOffset = fileOffset;
      if (instrumentation != null) {
        int offset =
            arguments.fileOffset == -1 ? fileOffset : arguments.fileOffset;
        instrumentation!.record(uriForInstrumentation, offset,
            'checkGetterReturn', new InstrumentationValueForType(functionType));
      }
    }

    if (isExpressionInvocation) {
      if (isTopLevel) {
        // Create an expression invocation for reporting the error during
        // full inference.
        return new ExpressionInferenceResult(
            const InvalidType(),
            new ExpressionInvocation(receiver, arguments)
              ..fileOffset = fileOffset);
      } else {
        Expression error = helper.buildProblem(
            templateImplicitCallOfNonMethod.withArguments(
                receiverType, isNonNullableByDefault),
            fileOffset,
            noLength);
        return new ExpressionInferenceResult(const InvalidType(), error);
      }
    }

    ExpressionInferenceResult invocationResult = inferMethodInvocation(
        visitor,
        arguments.fileOffset,
        const Link<NullAwareGuard>(),
        propertyGet,
        calleeType,
        callName,
        arguments,
        typeContext,
        isExpressionInvocation: false,
        isImplicitCall: true,
        hoistedExpressions: hoistedExpressions,
        implicitInvocationPropertyName: field.name);

    if (!isTopLevel && target.isNullable) {
      // Handles cases like:
      //   C? c;
      //   c.foo();
      // Where C is defined as:
      //   class C {
      //     void Function() foo;
      //     C(this.foo);
      //   }
      // TODO(paulberry): would it be better to report NullableMethodCallError
      // in this scenario?
      List<LocatedMessage>? context = getWhyNotPromotedContext(
          whyNotPromoted!(),
          invocationResult.expression,
          (type) => !type.isPotentiallyNullable);
      invocationResult = wrapExpressionInferenceResultInProblem(
          invocationResult,
          templateNullableExpressionCallError.withArguments(
              receiverType, isNonNullableByDefault),
          fileOffset,
          noLength,
          context: context);
    }

    if (!libraryBuilder
        .loader.target.backendTarget.supportsExplicitGetterCalls) {
      // TODO(johnniwinther): Remove this when dart2js/ddc supports explicit
      //  getter calls.
      Expression nullAwareAction = invocationResult.nullAwareAction;
      if (nullAwareAction is InstanceInvocation &&
          nullAwareAction.receiver == originalPropertyGet) {
        invocationResult = new ExpressionInferenceResult(
            invocationResult.inferredType,
            new InstanceGetterInvocation(originalPropertyGet.kind,
                originalReceiver, originalName, nullAwareAction.arguments,
                interfaceTarget: originalTarget,
                functionType: nullAwareAction.functionType)
              ..fileOffset = nullAwareAction.fileOffset);
      } else if (nullAwareAction is DynamicInvocation &&
          nullAwareAction.receiver == originalPropertyGet) {
        invocationResult = new ExpressionInferenceResult(
            invocationResult.inferredType,
            new InstanceGetterInvocation(originalPropertyGet.kind,
                originalReceiver, originalName, nullAwareAction.arguments,
                interfaceTarget: originalTarget, functionType: null)
              ..fileOffset = nullAwareAction.fileOffset);
      } else if (nullAwareAction is FunctionInvocation &&
          nullAwareAction.receiver == originalPropertyGet) {
        invocationResult = new ExpressionInferenceResult(
            invocationResult.inferredType,
            new InstanceGetterInvocation(originalPropertyGet.kind,
                originalReceiver, originalName, nullAwareAction.arguments,
                interfaceTarget: originalTarget,
                functionType: nullAwareAction.functionType)
              ..fileOffset = nullAwareAction.fileOffset);
      }
    }
    invocationResult =
        _insertHoistedExpression(invocationResult, locallyHoistedExpressions);
    return createNullAwareExpressionInferenceResult(
        invocationResult.inferredType,
        invocationResult.expression,
        nullAwareGuards);
  }

  /// Performs the core type inference algorithm for method invocations.
  ExpressionInferenceResult inferMethodInvocation(
      InferenceVisitor visitor,
      int fileOffset,
      Link<NullAwareGuard> nullAwareGuards,
      Expression receiver,
      DartType receiverType,
      Name name,
      ArgumentsImpl arguments,
      DartType typeContext,
      {required bool isExpressionInvocation,
      required bool isImplicitCall,
      Name? implicitInvocationPropertyName,
      List<VariableDeclaration>? hoistedExpressions}) {
    // ignore: unnecessary_null_comparison
    assert(isExpressionInvocation != null);
    // ignore: unnecessary_null_comparison
    assert(isImplicitCall != null);

    ObjectAccessTarget target = findInterfaceMember(
        receiverType, name, fileOffset,
        instrumented: true,
        includeExtensionMethods: true,
        callSiteAccessKind: CallSiteAccessKind.methodInvocation);

    switch (target.kind) {
      case ObjectAccessTargetKind.instanceMember:
      case ObjectAccessTargetKind.objectMember:
      case ObjectAccessTargetKind.nullableInstanceMember:
        Member member = target.member!;
        if (member is Procedure) {
          if (member.kind == ProcedureKind.Getter) {
            return _inferInstanceGetterInvocation(
                visitor,
                fileOffset,
                nullAwareGuards,
                receiver,
                receiverType,
                target,
                arguments,
                typeContext,
                hoistedExpressions,
                isExpressionInvocation: isExpressionInvocation);
          } else {
            bool isSpecialCasedBinaryOperator =
                isSpecialCasedBinaryOperatorForReceiverType(
                    target, receiverType);
            return _inferInstanceMethodInvocation(
                visitor,
                fileOffset,
                nullAwareGuards,
                receiver,
                receiverType,
                target,
                arguments,
                typeContext,
                hoistedExpressions,
                isImplicitCall: isImplicitCall,
                isSpecialCasedBinaryOperator: isSpecialCasedBinaryOperator,
                isSpecialCasedTernaryOperator:
                    isSpecialCasedTernaryOperator(target));
          }
        } else {
          return _inferInstanceFieldInvocation(
              visitor,
              fileOffset,
              nullAwareGuards,
              receiver,
              receiverType,
              target,
              arguments,
              typeContext,
              hoistedExpressions,
              isExpressionInvocation: isExpressionInvocation);
        }
      case ObjectAccessTargetKind.callFunction:
      case ObjectAccessTargetKind.nullableCallFunction:
        return _inferFunctionInvocation(
            visitor,
            fileOffset,
            nullAwareGuards,
            receiver,
            receiverType,
            target,
            arguments,
            typeContext,
            hoistedExpressions,
            isImplicitCall: isImplicitCall);
      case ObjectAccessTargetKind.extensionMember:
      case ObjectAccessTargetKind.nullableExtensionMember:
        return _inferExtensionInvocation(
            visitor,
            fileOffset,
            nullAwareGuards,
            receiver,
            receiverType,
            target,
            name,
            arguments,
            typeContext,
            hoistedExpressions,
            isImplicitCall: isImplicitCall);
      case ObjectAccessTargetKind.ambiguous:
      case ObjectAccessTargetKind.missing:
        return _inferMissingInvocation(
            visitor,
            fileOffset,
            nullAwareGuards,
            receiver,
            receiverType,
            target,
            name,
            arguments,
            typeContext,
            hoistedExpressions,
            isExpressionInvocation: isExpressionInvocation,
            isImplicitCall: isImplicitCall,
            implicitInvocationPropertyName: implicitInvocationPropertyName);
      case ObjectAccessTargetKind.dynamic:
      case ObjectAccessTargetKind.invalid:
        return _inferDynamicInvocation(visitor, fileOffset, nullAwareGuards,
            receiver, name, arguments, typeContext, hoistedExpressions,
            isImplicitCall: isExpressionInvocation || isImplicitCall);
      case ObjectAccessTargetKind.never:
        return _inferNeverInvocation(
            visitor,
            fileOffset,
            nullAwareGuards,
            receiver,
            receiverType as NeverType,
            name,
            arguments,
            typeContext,
            hoistedExpressions,
            isImplicitCall: isImplicitCall);
    }
  }

  void _checkBoundsInMethodInvocation(
      ObjectAccessTarget target,
      DartType receiverType,
      DartType calleeType,
      Name methodName,
      Arguments arguments,
      int fileOffset) {
    // If [arguments] were inferred, check them.
    if (!isTopLevel) {
      // We only perform checks in full inference.

      // [actualReceiverType], [interfaceTarget], and [actualMethodName] below
      // are for a workaround for the cases like the following:
      //
      //     class C1 { var f = new C2(); }
      //     class C2 { int call<X extends num>(X x) => 42; }
      //     main() { C1 c = new C1(); c.f("foobar"); }
      DartType actualReceiverType;
      Member? interfaceTarget;
      Name actualMethodName;
      if (calleeType is InterfaceType) {
        actualReceiverType = calleeType;
        interfaceTarget = null;
        actualMethodName = callName;
      } else {
        actualReceiverType = receiverType;
        interfaceTarget = (target.isInstanceMember || target.isObjectMember)
            ? target.member
            : null;
        actualMethodName = methodName;
      }
      libraryBuilder.checkBoundsInMethodInvocation(
          actualReceiverType,
          typeSchemaEnvironment,
          classHierarchy,
          actualMethodName,
          interfaceTarget,
          arguments,
          helper.uri,
          fileOffset);
    }
  }

  void checkBoundsInInstantiation(
      FunctionType functionType, List<DartType> arguments, int fileOffset,
      {required bool inferred}) {
    // ignore: unnecessary_null_comparison
    assert(inferred != null);
    // If [arguments] were inferred, check them.
    if (!isTopLevel) {
      // We only perform checks in full inference.
      libraryBuilder.checkBoundsInInstantiation(typeSchemaEnvironment,
          classHierarchy, functionType, arguments, helper.uri, fileOffset,
          inferred: inferred);
    }
  }

  void _checkBoundsInFunctionInvocation(FunctionType functionType,
      String? localName, Arguments arguments, int fileOffset) {
    // If [arguments] were inferred, check them.
    if (!isTopLevel) {
      // We only perform checks in full inference.
      libraryBuilder.checkBoundsInFunctionInvocation(
          typeSchemaEnvironment,
          classHierarchy,
          functionType,
          localName,
          arguments,
          helper.uri,
          fileOffset);
    }
  }

  bool isSpecialCasedBinaryOperatorForReceiverType(
      ObjectAccessTarget target, DartType receiverType) {
    return (target.isInstanceMember ||
            target.isObjectMember ||
            target.isNullableInstanceMember) &&
        target.member is Procedure &&
        typeSchemaEnvironment.isSpecialCasesBinaryForReceiverType(
            target.member as Procedure, receiverType,
            isNonNullableByDefault: isNonNullableByDefault);
  }

  bool isSpecialCasedTernaryOperator(ObjectAccessTarget target) {
    return (target.isInstanceMember ||
            target.isObjectMember ||
            target.isNullableInstanceMember) &&
        target.member is Procedure &&
        typeSchemaEnvironment.isSpecialCasedTernaryOperator(
            target.member as Procedure,
            isNonNullableByDefault: isNonNullableByDefault);
  }

  /// Performs the core type inference algorithm for super method invocations.
  ExpressionInferenceResult inferSuperMethodInvocation(
      InferenceVisitor visitor,
      Expression expression,
      Name methodName,
      ArgumentsImpl arguments,
      DartType typeContext,
      Procedure? procedure) {
    int fileOffset = expression.fileOffset;
    ObjectAccessTarget target = procedure != null
        ? new ObjectAccessTarget.interfaceMember(procedure,
            isPotentiallyNullable: false)
        : const ObjectAccessTarget.missing();
    DartType receiverType = thisType!;
    bool isSpecialCasedBinaryOperator =
        isSpecialCasedBinaryOperatorForReceiverType(target, receiverType);
    DartType calleeType = getGetterType(target, receiverType);
    FunctionType functionType = getFunctionType(target, receiverType);
    if (procedure != null) {
      calleeType =
          computeTypeFromSuperClass(procedure.enclosingClass!, calleeType);
      functionType =
          computeTypeFromSuperClass(procedure.enclosingClass!, functionType)
              as FunctionType;
    }
    if (isNonNullableByDefault &&
        methodName == equalsName &&
        functionType.positionalParameters.length == 1) {
      // operator == always allows nullable arguments.
      functionType = new FunctionType([
        functionType.positionalParameters.single
            .withDeclaredNullability(libraryBuilder.nullable)
      ], functionType.returnType, functionType.declaredNullability);
    }
    InvocationInferenceResult result = inferInvocation(
        visitor, typeContext, fileOffset, functionType, arguments,
        isSpecialCasedBinaryOperator: isSpecialCasedBinaryOperator,
        receiverType: receiverType,
        isImplicitExtensionMember: false);
    DartType inferredType = result.inferredType;
    if (methodName.text == '==') {
      inferredType = coreTypes.boolRawType(libraryBuilder.nonNullable);
    }
    _checkBoundsInMethodInvocation(
        target, receiverType, calleeType, methodName, arguments, fileOffset);

    return new ExpressionInferenceResult(
        inferredType, result.applyResult(expression));
  }

  /// Performs the core type inference algorithm for super property get.
  ExpressionInferenceResult inferSuperPropertyGet(
      Expression expression, Name name, DartType typeContext, Member? member) {
    ObjectAccessTarget readTarget = member != null
        ? new ObjectAccessTarget.interfaceMember(member,
            isPotentiallyNullable: false)
        : const ObjectAccessTarget.missing();
    DartType receiverType = thisType!;
    DartType inferredType = getGetterType(readTarget, receiverType);
    if (member != null) {
      inferredType =
          computeTypeFromSuperClass(member.enclosingClass!, inferredType);
    }
    if (member is Procedure && member.kind == ProcedureKind.Method) {
      return instantiateTearOff(inferredType, typeContext, expression);
    }
    flowAnalysis.thisOrSuperPropertyGet(
        expression, name.text, member, inferredType);
    return new ExpressionInferenceResult(inferredType, expression);
  }

  /// Computes the implicit instantiation from an expression of [tearOffType]
  /// to the [context] type. Return `null` if an implicit instantiation is not
  /// necessary or possible.
  ImplicitInstantiation? computeImplicitInstantiation(
      DartType tearoffType, DartType context) {
    if (tearoffType is FunctionType &&
        context is FunctionType &&
        context.typeParameters.isEmpty) {
      FunctionType functionType = tearoffType;
      List<TypeParameter> typeParameters = functionType.typeParameters;
      if (typeParameters.isNotEmpty) {
        List<DartType> inferredTypes = new List<DartType>.filled(
            typeParameters.length, const UnknownType());
        FunctionType instantiatedType = functionType.withoutTypeParameters;
        TypeConstraintGatherer gatherer =
            typeSchemaEnvironment.setupGenericTypeInference(instantiatedType,
                typeParameters, context, libraryBuilder.library);
        inferredTypes = typeSchemaEnvironment.upwardsInfer(
            gatherer, typeParameters, inferredTypes, libraryBuilder.library);
        Substitution substitution =
            Substitution.fromPairs(typeParameters, inferredTypes);
        tearoffType = substitution.substituteType(instantiatedType);
        return new ImplicitInstantiation(
            inferredTypes, functionType, tearoffType);
      }
    }
    return null;
  }

  ExpressionInferenceResult _applyImplicitInstantiation(
      ImplicitInstantiation? implicitInstantiation,
      DartType tearOffType,
      Expression expression) {
    if (implicitInstantiation != null) {
      FunctionType uninstantiatedType = implicitInstantiation.functionType;

      List<DartType> typeArguments = implicitInstantiation.typeArguments;
      if (!isTopLevel) {
        checkBoundsInInstantiation(
            uninstantiatedType, typeArguments, expression.fileOffset,
            inferred: true);
      }

      if (expression is TypedefTearOff) {
        Substitution substitution =
            Substitution.fromPairs(expression.typeParameters, typeArguments);
        typeArguments =
            expression.typeArguments.map(substitution.substituteType).toList();
        expression = expression.expression;
      } else {
        LoweredTypedefTearOff? loweredTypedefTearOff =
            LoweredTypedefTearOff.fromExpression(expression);
        if (loweredTypedefTearOff != null) {
          Substitution substitution = Substitution.fromPairs(
              loweredTypedefTearOff.typedefTearOff.function.typeParameters,
              typeArguments);
          typeArguments = loweredTypedefTearOff.typeArguments
              .map(substitution.substituteType)
              .toList();
          expression = loweredTypedefTearOff.targetTearOff;
        }
      }
      tearOffType = implicitInstantiation.instantiatedType;
      if (uninstantiatedType.isPotentiallyNullable) {
        // Replace expression with:
        // `let t = expression in t == null ? null : t<...>`
        VariableDeclaration t = new VariableDeclaration.forValue(expression,
            type: uninstantiatedType)
          ..fileOffset = expression.fileOffset;

        Expression nullCheck = new EqualsNull(
            new VariableGet(t)..fileOffset = expression.fileOffset)
          ..fileOffset = expression.fileOffset;

        ConditionalExpression conditional = new ConditionalExpression(
            nullCheck,
            new NullLiteral()..fileOffset = expression.fileOffset,
            new Instantiation(
                new VariableGet(t, uninstantiatedType.toNonNull()),
                typeArguments)
              ..fileOffset = expression.fileOffset,
            tearOffType);
        expression = new Let(t, conditional)
          ..fileOffset = expression.fileOffset;
      } else {
        expression = new Instantiation(expression, typeArguments)
          ..fileOffset = expression.fileOffset;
      }
    }
    return new ExpressionInferenceResult(tearOffType, expression);
  }

  /// Performs the type inference steps necessary to instantiate a tear-off
  /// (if necessary).
  ExpressionInferenceResult instantiateTearOff(
      DartType tearoffType, DartType context, Expression expression) {
    ImplicitInstantiation? implicitInstantiation =
        computeImplicitInstantiation(tearoffType, context);
    return _applyImplicitInstantiation(
        implicitInstantiation, tearoffType, expression);
  }

  /// True if the returned [type] has non-covariant occurrences of any of
  /// [class_]'s type parameters.
  ///
  /// A non-covariant occurrence of a type parameter is either a contravariant
  /// or an invariant position.
  ///
  /// A contravariant position is to the left of an odd number of arrows. For
  /// example, T occurs contravariantly in T -> T0, T0 -> (T -> T1),
  /// (T0 -> T) -> T1 but not in (T -> T0) -> T1.
  ///
  /// An invariant position is without a bound of a type parameter. For example,
  /// T occurs invariantly in `S Function<S extends T>()` and
  /// `void Function<S extends C<T>>(S)`.
  static bool returnedTypeParametersOccurNonCovariantly(
      Class class_, DartType type) {
    if (class_.typeParameters.isEmpty) return false;
    IncludesTypeParametersNonCovariantly checker =
        new IncludesTypeParametersNonCovariantly(class_.typeParameters,
            // We are checking the returned type (field/getter type or return
            // type of a method) and this is a covariant position.
            initialVariance: Variance.covariant);
    return type.accept(checker);
  }

  /// Determines the dispatch category of a [MethodInvocation] and returns a
  /// boolean indicating whether an "as" check will need to be added due to
  /// contravariance.
  MethodContravarianceCheckKind preCheckInvocationContravariance(
      DartType receiverType, ObjectAccessTarget target,
      {required bool isThisReceiver}) {
    // ignore: unnecessary_null_comparison
    assert(isThisReceiver != null);
    if (target.isInstanceMember || target.isObjectMember) {
      Member interfaceMember = target.member!;
      if (interfaceMember is Field ||
          interfaceMember is Procedure &&
              interfaceMember.kind == ProcedureKind.Getter) {
        DartType getType = getGetterType(target, receiverType);
        if (getType is DynamicType) {
          return MethodContravarianceCheckKind.none;
        }
        if (!isThisReceiver) {
          if ((interfaceMember is Field &&
                  returnedTypeParametersOccurNonCovariantly(
                      interfaceMember.enclosingClass!, interfaceMember.type)) ||
              (interfaceMember is Procedure &&
                  returnedTypeParametersOccurNonCovariantly(
                      interfaceMember.enclosingClass!,
                      interfaceMember.function.returnType))) {
            return MethodContravarianceCheckKind.checkGetterReturn;
          }
        }
      } else if (!isThisReceiver &&
          interfaceMember is Procedure &&
          returnedTypeParametersOccurNonCovariantly(
              interfaceMember.enclosingClass!,
              interfaceMember.function.returnType)) {
        return MethodContravarianceCheckKind.checkMethodReturn;
      }
    }
    return MethodContravarianceCheckKind.none;
  }

  /// If the given [type] is a [TypeParameterType], resolve it to its bound.
  DartType resolveTypeParameter(DartType type) {
    DartType? resolveOneStep(DartType type) {
      if (type is TypeParameterType) {
        return type.bound;
      } else {
        return null;
      }
    }

    DartType? resolved = resolveOneStep(type);
    if (resolved == null) return type;

    // Detect circularities using the tortoise-and-hare algorithm.
    DartType? tortoise = resolved;
    DartType? hare = resolveOneStep(tortoise);
    if (hare == null) return tortoise;
    while (true) {
      if (identical(tortoise, hare)) {
        // We found a circularity.  Give up and return `dynamic`.
        return const DynamicType();
      }

      // Hare takes two steps
      DartType? step1 = resolveOneStep(hare!);
      if (step1 == null) return hare;
      DartType? step2 = resolveOneStep(step1);
      if (step2 == null) return step1;
      hare = step2;

      // Tortoise takes one step
      tortoise = resolveOneStep(tortoise!);
    }
  }

  DartType wrapFutureOrType(DartType type) {
    if (type is FutureOrType) {
      return type;
    }
    // TODO(paulberry): If [type] is a subtype of `Future`, should we just
    // return it unmodified?
    // ignore: unnecessary_null_comparison
    if (type == null) {
      return coreTypes.futureRawType(libraryBuilder.nullable);
    }
    return new FutureOrType(type, libraryBuilder.nonNullable);
  }

  DartType wrapFutureType(DartType type, Nullability nullability) {
    return new InterfaceType(
        coreTypes.futureClass, nullability, <DartType>[type]);
  }

  DartType wrapType(DartType type, Class class_, Nullability nullability) {
    return new InterfaceType(class_, nullability, <DartType>[type]);
  }

  /// Computes the `futureValueTypeSchema` for the type schema [type].
  ///
  /// This is the same as the [futureValueType] except that this handles
  /// the unknown type.
  DartType computeFutureValueTypeSchema(DartType type) {
    return type.accept1(new FutureValueTypeVisitor(unhandledTypeHandler:
        (DartType node, CoreTypes coreTypes,
            DartType Function(DartType node, CoreTypes coreTypes) recursor) {
      if (node is UnknownType) {
        // futureValueTypeSchema(_) = _.
        return node;
      }
      throw new UnsupportedError("Unsupported type '${node.runtimeType}'.");
    }), coreTypes);
  }

  Member? _getInterfaceMember(
      Class class_, Name name, bool setter, int charOffset) {
    ClassMember? classMember = engine.membersBuilder
        .getInterfaceClassMember(class_, name, setter: setter);
    if (classMember != null) {
      if (classMember.isStatic) {
        classMember = null;
      } else if (classMember.isDuplicate) {
        if (!isTopLevel) {
          libraryBuilder.addProblem(
              templateDuplicatedDeclarationUse.withArguments(name.text),
              charOffset,
              name.text.length,
              helper.uri);
        }
        classMember = null;
      }
    }
    Member? member = classMember?.getMember(engine.membersBuilder);
    if (member == null && libraryBuilder.isPatch) {
      // TODO(johnniwinther): Injected members are currently not included
      // in the class hierarchy builder.
      member ??=
          classHierarchy.getInterfaceMember(class_, name, setter: setter);
    }
    return TypeInferenceEngine.resolveInferenceNode(member);
  }

  /// Determines if the given [expression]'s type is precisely known at compile
  /// time.
  ///
  /// If it is, an error message template is returned, which can be used by the
  /// caller to report an invalid cast.  Otherwise, `null` is returned.
  Template<Message Function(DartType, DartType, bool)>?
      _getPreciseTypeErrorTemplate(Expression expression) {
    if (expression is ListLiteral) {
      return templateInvalidCastLiteralList;
    }
    if (expression is MapLiteral) {
      return templateInvalidCastLiteralMap;
    }
    if (expression is SetLiteral) {
      return templateInvalidCastLiteralSet;
    }
    if (expression is FunctionExpression) {
      return templateInvalidCastFunctionExpr;
    }
    if (expression is ConstructorInvocation) {
      return templateInvalidCastNewExpr;
    }
    if (expression is StaticGet) {
      Member target = expression.target;
      if (target is Procedure && target.kind == ProcedureKind.Method) {
        if (target.enclosingClass != null) {
          return templateInvalidCastStaticMethod;
        } else {
          return templateInvalidCastTopLevelFunction;
        }
      }
      return null;
    }
    if (expression is StaticTearOff) {
      Member target = expression.target;
      if (target.enclosingClass != null) {
        return templateInvalidCastStaticMethod;
      } else {
        return templateInvalidCastTopLevelFunction;
      }
    }
    if (expression is VariableGet) {
      VariableDeclaration variable = expression.variable;
      if (variable is VariableDeclarationImpl && variable.isLocalFunction) {
        return templateInvalidCastLocalFunction;
      }
    }
    return null;
  }

  bool _shouldTearOffCall(DartType contextType, DartType expressionType) {
    if (contextType is FutureOrType) {
      contextType = contextType.typeArgument;
    }
    if (contextType is FunctionType) return true;
    if (contextType is InterfaceType &&
        contextType.classNode == typeSchemaEnvironment.functionClass) {
      if (!typeSchemaEnvironment.isSubtypeOf(expressionType, contextType,
          SubtypeCheckMode.ignoringNullabilities)) {
        return true;
      }
    }
    return false;
  }

  Expression createMissingSuperIndexGet(int fileOffset, Expression index) {
    if (isTopLevel) {
      return engine.forest.createSuperMethodInvocation(fileOffset, indexGetName,
          null, engine.forest.createArguments(fileOffset, <Expression>[index]));
    } else {
      return helper.buildProblem(
          templateSuperclassHasNoMethod.withArguments(indexGetName.text),
          fileOffset,
          noLength);
    }
  }

  Expression createMissingSuperIndexSet(
      int fileOffset, Expression index, Expression value) {
    if (isTopLevel) {
      return engine.forest.createSuperMethodInvocation(
          fileOffset,
          indexSetName,
          null,
          engine.forest
              .createArguments(fileOffset, <Expression>[index, value]));
    } else {
      return helper.buildProblem(
          templateSuperclassHasNoMethod.withArguments(indexSetName.text),
          fileOffset,
          noLength);
    }
  }

  /// Creates an expression the represents the invalid invocation of [name] on
  /// [receiver] with [arguments].
  ///
  /// This is used to ensure that subexpressions of invalid invocations are part
  /// of the AST using `helper.wrapInProblem`.
  Expression _createInvalidInvocation(
      int fileOffset, Expression receiver, Name name, Arguments arguments) {
    return new DynamicInvocation(
        DynamicAccessKind.Unresolved, receiver, name, arguments)
      ..fileOffset = fileOffset;
  }

  /// Creates an expression the represents the invalid get of [name] on
  /// [receiver].
  ///
  /// This is used to ensure that subexpressions of invalid gets are part
  /// of the AST using `helper.wrapInProblem`.
  Expression _createInvalidGet(int fileOffset, Expression receiver, Name name) {
    return new DynamicGet(DynamicAccessKind.Unresolved, receiver, name)
      ..fileOffset = fileOffset;
  }

  /// Creates an expression the represents the invalid set of [name] on
  /// [receiver] with [value].
  ///
  /// This is used to ensure that subexpressions of invalid gets are part
  /// of the AST using `helper.wrapInProblem`.
  Expression _createInvalidSet(
      int fileOffset, Expression receiver, Name name, Expression value) {
    return new DynamicSet(DynamicAccessKind.Unresolved, receiver, name, value)
      ..fileOffset = fileOffset;
  }

  /// Creates an expression the represents a duplicate expression occurring
  /// for instance as the [first] and [second] occurrence of named arguments
  /// with the same name.
  ///
  /// This is used to ensure that subexpressions of duplicate expressions are
  /// part of the AST using `helper.wrapInProblem`.
  Expression _createDuplicateExpression(
      int fileOffset, Expression first, Expression second) {
    return new BlockExpression(
        new Block([new ExpressionStatement(first)..fileOffset = fileOffset])
          ..fileOffset = fileOffset,
        second)
      ..fileOffset = fileOffset;
  }

  Expression _reportMissingOrAmbiguousMember(
      int fileOffset,
      int length,
      DartType receiverType,
      Name name,
      Expression wrappedExpression,
      List<ExtensionAccessCandidate>? extensionAccessCandidates,
      Template<Message Function(String, DartType, bool)> missingTemplate,
      Template<Message Function(String, DartType, bool)> ambiguousTemplate) {
    List<LocatedMessage>? context;
    Template<Message Function(String, DartType, bool)> template =
        missingTemplate;
    if (extensionAccessCandidates != null) {
      context = extensionAccessCandidates
          .map((ExtensionAccessCandidate c) =>
              messageAmbiguousExtensionCause.withLocation(
                  c.memberBuilder.fileUri!,
                  c.memberBuilder.charOffset,
                  name == unaryMinusName ? 1 : c.memberBuilder.name.length))
          .toList();
      template = ambiguousTemplate;
    }
    return helper.wrapInProblem(
        wrappedExpression,
        template.withArguments(name.text, resolveTypeParameter(receiverType),
            isNonNullableByDefault),
        fileOffset,
        length,
        context: context);
  }

  Expression createMissingMethodInvocation(int fileOffset, Expression receiver,
      DartType receiverType, Name name, Arguments arguments,
      {required bool isExpressionInvocation,
      Name? implicitInvocationPropertyName,
      List<ExtensionAccessCandidate>? extensionAccessCandidates}) {
    // ignore: unnecessary_null_comparison
    assert(isExpressionInvocation != null);
    if (isTopLevel) {
      return engine.forest
          .createMethodInvocation(fileOffset, receiver, name, arguments);
    } else if (implicitInvocationPropertyName != null) {
      assert(extensionAccessCandidates == null);
      return helper.wrapInProblem(
          _createInvalidInvocation(fileOffset, receiver, name, arguments),
          templateInvokeNonFunction
              .withArguments(implicitInvocationPropertyName.text),
          fileOffset,
          implicitInvocationPropertyName.text.length);
    } else {
      return _reportMissingOrAmbiguousMember(
          fileOffset,
          isExpressionInvocation ? noLength : name.text.length,
          receiverType,
          name,
          _createInvalidInvocation(fileOffset, receiver, name, arguments),
          extensionAccessCandidates,
          receiverType is ExtensionType
              ? templateUndefinedExtensionMethod
              : templateUndefinedMethod,
          templateAmbiguousExtensionMethod);
    }
  }

  Expression createMissingPropertyGet(int fileOffset, Expression receiver,
      DartType receiverType, Name propertyName,
      {List<ExtensionAccessCandidate>? extensionAccessCandidates}) {
    if (isTopLevel) {
      return engine.forest
          .createPropertyGet(fileOffset, receiver, propertyName);
    } else {
      Template<Message Function(String, DartType, bool)> templateMissing;
      if (receiverType is ExtensionType) {
        templateMissing = templateUndefinedExtensionGetter;
      } else {
        templateMissing = templateUndefinedGetter;
      }
      return _reportMissingOrAmbiguousMember(
          fileOffset,
          propertyName.text.length,
          receiverType,
          propertyName,
          _createInvalidGet(fileOffset, receiver, propertyName),
          extensionAccessCandidates,
          templateMissing,
          templateAmbiguousExtensionProperty);
    }
  }

  Expression createMissingPropertySet(int fileOffset, Expression receiver,
      DartType receiverType, Name propertyName, Expression value,
      {required bool forEffect,
      List<ExtensionAccessCandidate>? extensionAccessCandidates}) {
    // ignore: unnecessary_null_comparison
    assert(forEffect != null);
    if (isTopLevel) {
      return engine.forest.createPropertySet(
          fileOffset, receiver, propertyName, value,
          forEffect: forEffect);
    } else {
      Template<Message Function(String, DartType, bool)> templateMissing;
      if (receiverType is ExtensionType) {
        templateMissing = templateUndefinedExtensionSetter;
      } else {
        templateMissing = templateUndefinedSetter;
      }
      return _reportMissingOrAmbiguousMember(
          fileOffset,
          propertyName.text.length,
          receiverType,
          propertyName,
          _createInvalidSet(fileOffset, receiver, propertyName, value),
          extensionAccessCandidates,
          templateMissing,
          templateAmbiguousExtensionProperty);
    }
  }

  Expression createMissingIndexGet(int fileOffset, Expression receiver,
      DartType receiverType, Expression index,
      {List<ExtensionAccessCandidate>? extensionAccessCandidates}) {
    if (isTopLevel) {
      return engine.forest.createIndexGet(fileOffset, receiver, index);
    } else {
      Template<Message Function(String, DartType, bool)> templateMissing;
      if (receiverType is ExtensionType) {
        templateMissing = templateUndefinedExtensionOperator;
      } else {
        templateMissing = templateUndefinedOperator;
      }
      return _reportMissingOrAmbiguousMember(
          fileOffset,
          noLength,
          receiverType,
          indexGetName,
          _createInvalidInvocation(fileOffset, receiver, indexGetName,
              new Arguments([index])..fileOffset = fileOffset),
          extensionAccessCandidates,
          templateMissing,
          templateAmbiguousExtensionOperator);
    }
  }

  Expression createMissingIndexSet(int fileOffset, Expression receiver,
      DartType receiverType, Expression index, Expression value,
      {required bool forEffect,
      List<ExtensionAccessCandidate>? extensionAccessCandidates}) {
    // ignore: unnecessary_null_comparison
    assert(forEffect != null);
    if (isTopLevel) {
      return engine.forest.createIndexSet(fileOffset, receiver, index, value,
          forEffect: forEffect);
    } else {
      Template<Message Function(String, DartType, bool)> templateMissing;
      if (receiverType is ExtensionType) {
        templateMissing = templateUndefinedExtensionOperator;
      } else {
        templateMissing = templateUndefinedOperator;
      }
      return _reportMissingOrAmbiguousMember(
          fileOffset,
          noLength,
          receiverType,
          indexSetName,
          _createInvalidInvocation(fileOffset, receiver, indexSetName,
              new Arguments([index, value])..fileOffset = fileOffset),
          extensionAccessCandidates,
          templateMissing,
          templateAmbiguousExtensionOperator);
    }
  }

  Expression createMissingBinary(int fileOffset, Expression left,
      DartType leftType, Name binaryName, Expression right,
      {List<ExtensionAccessCandidate>? extensionAccessCandidates}) {
    assert(binaryName != equalsName);
    if (isTopLevel) {
      return engine.forest.createMethodInvocation(fileOffset, left, binaryName,
          engine.forest.createArguments(fileOffset, <Expression>[right]));
    } else {
      Template<Message Function(String, DartType, bool)> templateMissing;
      if (leftType is ExtensionType) {
        templateMissing = templateUndefinedExtensionOperator;
      } else {
        templateMissing = templateUndefinedOperator;
      }
      return _reportMissingOrAmbiguousMember(
          fileOffset,
          binaryName.text.length,
          leftType,
          binaryName,
          _createInvalidInvocation(fileOffset, left, binaryName,
              new Arguments([right])..fileOffset = fileOffset),
          extensionAccessCandidates,
          templateMissing,
          templateAmbiguousExtensionOperator);
    }
  }

  Expression createMissingUnary(int fileOffset, Expression expression,
      DartType expressionType, Name unaryName,
      {List<ExtensionAccessCandidate>? extensionAccessCandidates}) {
    if (isTopLevel) {
      return new UnaryExpression(unaryName, expression)
        ..fileOffset = fileOffset;
    } else {
      Template<Message Function(String, DartType, bool)> templateMissing;
      if (expressionType is ExtensionType) {
        templateMissing = templateUndefinedExtensionOperator;
      } else {
        templateMissing = templateUndefinedOperator;
      }
      return _reportMissingOrAmbiguousMember(
          fileOffset,
          unaryName == unaryMinusName ? 1 : unaryName.text.length,
          expressionType,
          unaryName,
          _createInvalidInvocation(fileOffset, expression, unaryName,
              new Arguments([])..fileOffset = fileOffset),
          extensionAccessCandidates,
          templateMissing,
          templateAmbiguousExtensionOperator);
    }
  }

  /// Creates a `e == null` test for the expression [left] using the
  /// [fileOffset] as file offset for the created nodes.
  Expression createEqualsNull(int fileOffset, Expression left) {
    return new EqualsNull(left)..fileOffset = fileOffset;
  }

  /// Reports an error if [typeArgument] is a generic function type.
  ///
  /// This is use for reporting generic function types used as a type argument,
  /// which was disallowed before the 'generic-metadata' feature was enabled.
  void checkGenericFunctionTypeArgument(DartType typeArgument, int fileOffset) {
    assert(!libraryBuilder.libraryFeatures.genericMetadata.isEnabled);
    if (isGenericFunctionTypeOrAlias(typeArgument)) {
      libraryBuilder.addProblem(
          templateGenericFunctionTypeInferredAsActualTypeArgument.withArguments(
              typeArgument, isNonNullableByDefault),
          fileOffset,
          noLength,
          helper.uri);
    }
  }

  DartType _computeInferredType(ExpressionInferenceResult result) =>
      identical(result.inferredType, noInferredType) || isNonNullableByDefault
          ? result.inferredType
          : legacyErasure(result.inferredType);
}

class TypeInferrerImplBenchmarked implements TypeInferrer {
  final TypeInferrerImpl impl;
  final Benchmarker benchmarker;

  TypeInferrerImplBenchmarked(
      TypeInferenceEngine engine,
      Uri uriForInstrumentation,
      bool topLevel,
      InterfaceType? thisType,
      SourceLibraryBuilder library,
      AssignedVariables<TreeNode, VariableDeclaration> assignedVariables,
      InferenceDataForTesting? dataForTesting,
      this.benchmarker)
      : impl = new TypeInferrerImpl(engine, uriForInstrumentation, topLevel,
            thisType, library, assignedVariables, dataForTesting);

  @override
  bool get isTopLevel => impl.isTopLevel;

  @override
  AssignedVariables<TreeNode, VariableDeclaration> get assignedVariables =>
      impl.assignedVariables;

  @override
  FlowAnalysis<TreeNode, Statement, Expression, VariableDeclaration, DartType>
      get flowAnalysis => impl.flowAnalysis;

  @override
  SourceLibraryBuilder get libraryBuilder => impl.libraryBuilder;

  @override
  TypeSchemaEnvironment get typeSchemaEnvironment => impl.typeSchemaEnvironment;

  @override
  Uri get uriForInstrumentation => impl.uriForInstrumentation;

  @override
  DartType inferImplicitFieldType(
      InferenceHelper helper, Expression initializer) {
    benchmarker.beginSubdivide(BenchmarkSubdivides.inferImplicitFieldType);
    DartType result = impl.inferImplicitFieldType(helper, initializer);
    benchmarker.endSubdivide();
    return result;
  }

  @override
  ExpressionInferenceResult inferFieldInitializer(
      InferenceHelper helper, DartType declaredType, Expression initializer) {
    benchmarker.beginSubdivide(BenchmarkSubdivides.inferFieldInitializer);
    ExpressionInferenceResult result =
        impl.inferFieldInitializer(helper, declaredType, initializer);
    benchmarker.endSubdivide();
    return result;
  }

  @override
  InferredFunctionBody inferFunctionBody(InferenceHelper helper, int fileOffset,
      DartType returnType, AsyncMarker asyncMarker, Statement body) {
    benchmarker.beginSubdivide(BenchmarkSubdivides.inferFunctionBody);
    InferredFunctionBody result = impl.inferFunctionBody(
        helper, fileOffset, returnType, asyncMarker, body);
    benchmarker.endSubdivide();
    return result;
  }

  @override
  InitializerInferenceResult inferInitializer(
      InferenceHelper helper, Initializer initializer) {
    benchmarker.beginSubdivide(BenchmarkSubdivides.inferInitializer);
    InitializerInferenceResult result =
        impl.inferInitializer(helper, initializer);
    benchmarker.endSubdivide();
    return result;
  }

  @override
  void inferMetadata(
      InferenceHelper helper, TreeNode? parent, List<Expression>? annotations) {
    benchmarker.beginSubdivide(BenchmarkSubdivides.inferMetadata);
    impl.inferMetadata(helper, parent, annotations);
    benchmarker.endSubdivide();
  }

  @override
  Expression inferParameterInitializer(
      InferenceHelper helper,
      Expression initializer,
      DartType declaredType,
      bool hasDeclaredInitializer) {
    benchmarker.beginSubdivide(BenchmarkSubdivides.inferParameterInitializer);
    Expression result = impl.inferParameterInitializer(
        helper, initializer, declaredType, hasDeclaredInitializer);
    benchmarker.endSubdivide();
    return result;
  }

  @override
  List<DartType>? inferRedirectingFactoryTypeArguments(
      InferenceHelper helper,
      DartType typeContext,
      FunctionNode redirectingFactoryFunction,
      int fileOffset,
      Member target,
      FunctionType targetType) {
    benchmarker.beginSubdivide(
        BenchmarkSubdivides.inferRedirectingFactoryTypeArguments);
    List<DartType>? result = impl.inferRedirectingFactoryTypeArguments(
        helper,
        typeContext,
        redirectingFactoryFunction,
        fileOffset,
        target,
        targetType);
    benchmarker.endSubdivide();
    return result;
  }
}

abstract class MixinInferrer {
  final CoreTypes coreTypes;
  final TypeConstraintGatherer gatherer;

  MixinInferrer(this.coreTypes, this.gatherer);

  Supertype? asInstantiationOf(Supertype type, Class superclass);

  void reportProblem(Message message, Class cls);

  void generateConstraints(
      Class mixinClass, Supertype baseType, Supertype mixinSupertype) {
    if (mixinSupertype.typeArguments.isEmpty) {
      // The supertype constraint isn't generic; it doesn't constrain anything.
    } else if (mixinSupertype.classNode.isAnonymousMixin) {
      // We have either a mixin declaration `mixin M<X0, ..., Xn> on S0, S1` or
      // a VM-style super mixin `abstract class M<X0, ..., Xn> extends S0 with
      // S1` where S0 and S1 are superclass constraints that possibly have type
      // arguments.
      //
      // It has been compiled by naming the superclass to either:
      //
      // abstract class S0&S1<...> extends Object implements S0, S1 {}
      // abstract class M<X0, ..., Xn> extends S0&S1<...> ...
      //
      // for a mixin declaration, or else:
      //
      // abstract class S0&S1<...> = S0 with S1;
      // abstract class M<X0, ..., Xn> extends S0&S1<...>
      //
      // for a VM-style super mixin.  The type parameters of S0&S1 are the X0,
      // ..., Xn that occurred free in S0 and S1.  Treat S0 and S1 as separate
      // supertype constraints by recursively calling this algorithm.
      //
      // In the Dart VM the mixin application classes themselves are all
      // eliminated by translating them to normal classes.  In that case, the
      // mixin appears as the only interface in the introduced class.  We
      // support three forms for the superclass constraints:
      //
      // abstract class S0&S1<...> extends Object implements S0, S1 {}
      // abstract class S0&S1<...> = S0 with S1;
      // abstract class S0&S1<...> extends S0 implements S1 {}
      Class mixinSuperclass = mixinSupertype.classNode;
      if (mixinSuperclass.mixedInType == null &&
          mixinSuperclass.implementedTypes.length != 1 &&
          (mixinSuperclass.superclass != coreTypes.objectClass ||
              mixinSuperclass.implementedTypes.length != 2)) {
        unexpected(
            'Compiler-generated mixin applications have a mixin or else '
                'implement exactly one type',
            '$mixinSuperclass implements '
                '${mixinSuperclass.implementedTypes.length} types',
            mixinSuperclass.fileOffset,
            mixinSuperclass.fileUri);
      }
      Substitution substitution = Substitution.fromSupertype(mixinSupertype);
      Supertype s0, s1;
      if (mixinSuperclass.implementedTypes.length == 2) {
        s0 = mixinSuperclass.implementedTypes[0];
        s1 = mixinSuperclass.implementedTypes[1];
      } else if (mixinSuperclass.implementedTypes.length == 1) {
        s0 = mixinSuperclass.supertype!;
        s1 = mixinSuperclass.implementedTypes.first;
      } else {
        s0 = mixinSuperclass.supertype!;
        s1 = mixinSuperclass.mixedInType!;
      }
      s0 = substitution.substituteSupertype(s0);
      s1 = substitution.substituteSupertype(s1);
      generateConstraints(mixinClass, baseType, s0);
      generateConstraints(mixinClass, baseType, s1);
    } else {
      // Find the type U0 which is baseType as an instance of mixinSupertype's
      // class.
      Supertype? supertype =
          asInstantiationOf(baseType, mixinSupertype.classNode);
      if (supertype == null) {
        reportProblem(
            templateMixinInferenceNoMatchingClass.withArguments(
                mixinClass.name,
                baseType.classNode.name,
                mixinSupertype.asInterfaceType,
                mixinClass.enclosingLibrary.isNonNullableByDefault),
            mixinClass);
        return;
      }
      InterfaceType u0 = Substitution.fromSupertype(baseType)
          .substituteSupertype(supertype)
          .asInterfaceType;
      // We want to solve U0 = S0 where S0 is mixinSupertype, but we only have
      // a subtype constraints.  Solve for equality by solving
      // both U0 <: S0 and S0 <: U0.
      InterfaceType s0 = mixinSupertype.asInterfaceType;

      gatherer.tryConstrainLower(s0, u0);
      gatherer.tryConstrainUpper(s0, u0);
    }
  }

  void infer(Class classNode) {
    Supertype mixedInType = classNode.mixedInType!;
    assert(mixedInType.typeArguments.every((t) => t == const UnknownType()));
    // Note that we have no anonymous mixin applications, they have all
    // been named.  Note also that mixin composition has been translated
    // so that we only have mixin applications of the form `S with M`.
    Supertype baseType = classNode.supertype!;
    Class mixinClass = mixedInType.classNode;
    Supertype mixinSupertype = mixinClass.supertype!;
    // Generate constraints based on the mixin's supertype.
    generateConstraints(mixinClass, baseType, mixinSupertype);
    // Solve them to get a map from type parameters to upper and lower
    // bounds.
    Map<TypeParameter, TypeConstraint> result =
        gatherer.computeConstraints(classNode.enclosingLibrary);
    // Generate new type parameters with the solution as bounds.
    List<TypeParameter> parameters = mixinClass.typeParameters.map((p) {
      TypeConstraint? constraint = result[p];
      // Because we solved for equality, a valid solution has a parameter
      // either unconstrained or else with identical upper and lower bounds.
      if (constraint != null && constraint.upper != constraint.lower) {
        reportProblem(
            templateMixinInferenceNoMatchingClass.withArguments(
                mixinClass.name,
                baseType.classNode.name,
                mixinSupertype.asInterfaceType,
                mixinClass.enclosingLibrary.isNonNullableByDefault),
            mixinClass);
        return p;
      }
      assert(constraint == null || constraint.upper == constraint.lower);
      bool exact =
          constraint != null && constraint.upper != const UnknownType();
      return new TypeParameter(
          p.name, exact ? constraint.upper : p.bound, p.defaultType);
    }).toList();
    // Bounds might mention the mixin class's type parameters so we have to
    // substitute them before calling instantiate to bounds.
    Substitution substitution = Substitution.fromPairs(
        mixinClass.typeParameters,
        new List<DartType>.generate(
            parameters.length,
            (i) => new TypeParameterType.forAlphaRenaming(
                mixinClass.typeParameters[i], parameters[i])));
    for (TypeParameter p in parameters) {
      p.bound = substitution.substituteType(p.bound);
    }
    // Use instantiate to bounds.
    List<DartType> bounds = calculateBounds(
        parameters, coreTypes.objectClass, classNode.enclosingLibrary);
    for (int i = 0; i < mixedInType.typeArguments.length; ++i) {
      mixedInType.typeArguments[i] = bounds[i];
    }
  }
}

/// The result of a statement inference.
class StatementInferenceResult {
  const StatementInferenceResult();

  factory StatementInferenceResult.single(Statement statement) =
      SingleStatementInferenceResult;

  factory StatementInferenceResult.multiple(
          int fileOffset, List<Statement> statements) =
      MultipleStatementInferenceResult;

  bool get hasChanged => false;

  Statement get statement =>
      throw new UnsupportedError('StatementInferenceResult.statement');

  int get statementCount =>
      throw new UnsupportedError('StatementInferenceResult.statementCount');

  List<Statement> get statements =>
      throw new UnsupportedError('StatementInferenceResult.statements');
}

class SingleStatementInferenceResult implements StatementInferenceResult {
  @override
  final Statement statement;

  SingleStatementInferenceResult(this.statement);

  @override
  bool get hasChanged => true;

  @override
  int get statementCount => 1;

  @override
  List<Statement> get statements =>
      throw new UnsupportedError('SingleStatementInferenceResult.statements');
}

class MultipleStatementInferenceResult implements StatementInferenceResult {
  final int fileOffset;
  @override
  final List<Statement> statements;

  MultipleStatementInferenceResult(this.fileOffset, this.statements);

  @override
  bool get hasChanged => true;

  @override
  Statement get statement => new Block(statements)..fileOffset = fileOffset;

  @override
  int get statementCount => statements.length;
}

/// Tells the inferred type and how the code should be transformed.
///
/// It is intended for use by generalized inference methods, such as
/// [InferenceVisitorBase.inferInvocation], where the input [Expression] isn't
/// available for rewriting.  So, instead of transforming the code, the result
/// of the inference provides a way to transform the code at the point of
/// invocation.
abstract class InvocationInferenceResult {
  DartType get inferredType;

  DartType get functionType;

  /// Applies the result of the inference to the expression being inferred.
  ///
  /// A successful result leaves [expression] intact, and an error detected
  /// during inference would wrap the expression into an [InvalidExpression].
  Expression applyResult(Expression expression);

  /// Returns `true` if the arguments of the call where not applicable to the
  /// target.
  bool get isInapplicable;

  static Expression _insertHoistedExpressions(
      Expression expression, List<VariableDeclaration> hoistedExpressions) {
    if (hoistedExpressions.isNotEmpty) {
      for (int index = hoistedExpressions.length - 1; index >= 0; index--) {
        expression = createLet(hoistedExpressions[index], expression);
      }
    }
    return expression;
  }
}

class SuccessfulInferenceResult implements InvocationInferenceResult {
  @override
  final DartType inferredType;

  @override
  final FunctionType functionType;

  final List<VariableDeclaration>? hoistedArguments;

  final DartType? inferredReceiverType;

  SuccessfulInferenceResult(this.inferredType, this.functionType,
      {required this.hoistedArguments, this.inferredReceiverType});

  @override
  Expression applyResult(Expression expression) {
    List<VariableDeclaration>? hoistedArguments = this.hoistedArguments;
    if (hoistedArguments == null || hoistedArguments.isEmpty) {
      return expression;
    } else {
      assert(expression is InvocationExpression ||
          expression is InvalidExpression);
      if (expression is FactoryConstructorInvocation) {
        return InvocationInferenceResult._insertHoistedExpressions(
            expression, hoistedArguments);
      } else if (expression is TypeAliasedConstructorInvocation) {
        return InvocationInferenceResult._insertHoistedExpressions(
            expression, hoistedArguments);
      } else if (expression is TypeAliasedFactoryInvocation) {
        return InvocationInferenceResult._insertHoistedExpressions(
            expression, hoistedArguments);
      } else if (expression is ConstructorInvocation) {
        return InvocationInferenceResult._insertHoistedExpressions(
            expression, hoistedArguments);
      } else if (expression is DynamicInvocation) {
        return InvocationInferenceResult._insertHoistedExpressions(
            expression, hoistedArguments);
      } else if (expression is FunctionInvocation) {
        return InvocationInferenceResult._insertHoistedExpressions(
            expression, hoistedArguments);
      } else if (expression is InstanceGetterInvocation) {
        // The hoisting of InstanceGetterInvocation is performed elsewhere.
        return expression;
      } else if (expression is InstanceInvocation) {
        VariableDeclaration receiver = createVariable(
            expression.receiver, inferredReceiverType ?? const DynamicType());
        expression.receiver = createVariableGet(receiver)..parent = expression;
        return createLet(
            receiver,
            InvocationInferenceResult._insertHoistedExpressions(
                expression, hoistedArguments));
      } else if (expression is LocalFunctionInvocation) {
        return InvocationInferenceResult._insertHoistedExpressions(
            expression, hoistedArguments);
      } else if (expression is StaticInvocation) {
        return InvocationInferenceResult._insertHoistedExpressions(
            expression, hoistedArguments);
      } else if (expression is SuperMethodInvocation) {
        return InvocationInferenceResult._insertHoistedExpressions(
            expression, hoistedArguments);
      } else if (expression is InvalidExpression) {
        return InvocationInferenceResult._insertHoistedExpressions(
            expression, hoistedArguments);
      } else {
        throw new StateError(
            "Unhandled invocation kind '${expression.runtimeType}'.");
      }
    }
  }

  @override
  bool get isInapplicable => false;
}

class WrapInProblemInferenceResult implements InvocationInferenceResult {
  @override
  final DartType inferredType;

  @override
  final DartType functionType;

  final Message message;

  final int fileOffset;

  final int length;

  final InferenceHelper helper;

  @override
  final bool isInapplicable;

  final List<VariableDeclaration>? hoistedArguments;

  WrapInProblemInferenceResult(this.inferredType, this.functionType,
      this.message, this.fileOffset, this.length, this.helper,
      {required this.isInapplicable, required this.hoistedArguments})
      // ignore: unnecessary_null_comparison
      : assert(isInapplicable != null);

  @override
  Expression applyResult(Expression expression) {
    expression = helper.wrapInProblem(expression, message, fileOffset, length);
    List<VariableDeclaration>? hoistedArguments = this.hoistedArguments;
    if (hoistedArguments == null || hoistedArguments.isEmpty) {
      return expression;
    } else {
      return InvocationInferenceResult._insertHoistedExpressions(
          expression, hoistedArguments);
    }
  }
}

abstract class InitializerInferenceResult {
  /// Modifies list of initializers in-place to apply the inference result.
  void applyResult(List<Initializer> initializers, TreeNode? parent);

  factory InitializerInferenceResult.fromInvocationInferenceResult(
      InvocationInferenceResult invocationInferenceResult) {
    if (invocationInferenceResult is SuccessfulInferenceResult) {
      return new SuccessfulInitializerInvocationInferenceResult
          .fromSuccessfulInferenceResult(invocationInferenceResult);
    } else {
      return new WrapInProblemInitializerInferenceResult
              .fromWrapInProblemInferenceResult(
          invocationInferenceResult as WrapInProblemInferenceResult);
    }
  }
}

class SuccessfulInitializerInferenceResult
    implements InitializerInferenceResult {
  const SuccessfulInitializerInferenceResult();

  @override
  void applyResult(List<Initializer> initializers, TreeNode? parent) {}
}

class SuccessfulInitializerInvocationInferenceResult
    implements InitializerInferenceResult {
  final DartType inferredType;

  final FunctionType functionType;

  final List<VariableDeclaration>? hoistedArguments;

  final DartType? inferredReceiverType;

  SuccessfulInitializerInvocationInferenceResult(
      {required this.inferredType,
      required this.functionType,
      required this.hoistedArguments,
      required this.inferredReceiverType});

  SuccessfulInitializerInvocationInferenceResult.fromSuccessfulInferenceResult(
      SuccessfulInferenceResult successfulInferenceResult)
      : this(
            inferredType: successfulInferenceResult.inferredType,
            functionType: successfulInferenceResult.functionType,
            hoistedArguments: successfulInferenceResult.hoistedArguments,
            inferredReceiverType:
                successfulInferenceResult.inferredReceiverType);

  @override
  void applyResult(List<Initializer> initializers, TreeNode? parent) {
    List<VariableDeclaration>? hoistedArguments = this.hoistedArguments;
    if (hoistedArguments != null && hoistedArguments.isNotEmpty) {
      for (VariableDeclaration hoistedArgument in hoistedArguments) {
        initializers.add(new LocalInitializer(hoistedArgument)
          ..parent = parent
          ..fileOffset = hoistedArgument.fileOffset);
      }
    }
  }
}

class WrapInProblemInitializerInferenceResult
    implements InitializerInferenceResult {
  WrapInProblemInitializerInferenceResult.fromWrapInProblemInferenceResult(
      WrapInProblemInferenceResult wrapInProblemInferenceResult);

  @override
  void applyResult(List<Initializer> initializers, TreeNode? parent) {}
}

/// The result of inference of a property get expression.
class PropertyGetInferenceResult {
  /// The main inference result.
  final ExpressionInferenceResult expressionInferenceResult;

  /// The property that was looked up, or `null` if no property was found.
  final Member? member;

  PropertyGetInferenceResult(this.expressionInferenceResult, this.member);
}

/// The result of an expression inference.
class ExpressionInferenceResult {
  /// The inferred type of the expression.
  final DartType inferredType;

  /// The inferred expression.
  final Expression expression;

  ExpressionInferenceResult(this.inferredType, this.expression)
      // ignore: unnecessary_null_comparison
      : assert(expression != null);

  /// The guards used for null-aware access if the expression is part of a
  /// null-shorting.
  Link<NullAwareGuard> get nullAwareGuards => const Link<NullAwareGuard>();

  /// If the expression is part of a null-shorting, this is the action performed
  /// on the guarded variable, found as the first guard in [nullAwareGuards].
  /// Otherwise, this is the same as [expression].
  Expression get nullAwareAction => expression;

  DartType get nullAwareActionType => inferredType;

  ExpressionInferenceResult stopShorting() => this;

  @override
  String toString() => 'ExpressionInferenceResult($inferredType,$expression)';
}

/// A guard used for creating null-shorting null-aware actions.
class NullAwareGuard {
  /// The variable used to guard the null-aware action.
  final VariableDeclaration _nullAwareVariable;

  /// The file offset used for the null-test.
  int _nullAwareFileOffset;

  final InferenceVisitorBase _inferrer;

  NullAwareGuard(
      this._nullAwareVariable, this._nullAwareFileOffset, this._inferrer)
      // ignore: unnecessary_null_comparison
      : assert(_nullAwareVariable != null),
        // ignore: unnecessary_null_comparison
        assert(_nullAwareFileOffset != null),
        // ignore: unnecessary_null_comparison
        assert(_inferrer != null) {
    // Ensure the initializer of [_nullAwareVariable] is promoted to
    // non-nullable.
    _inferrer.flowAnalysis.nullAwareAccess_rightBegin(
        _nullAwareVariable.initializer, _nullAwareVariable.type);
    // Ensure [_nullAwareVariable] is promoted to non-nullable.
    // TODO(johnniwinther): Avoid creating a [VariableGet] to promote the
    // variable.
    VariableGet read = new VariableGet(_nullAwareVariable);
    _inferrer.flowAnalysis.variableRead(read, _nullAwareVariable);
    _inferrer.flowAnalysis
        .nullAwareAccess_rightBegin(read, _nullAwareVariable.type);
  }

  /// Creates the null-guarded application of [nullAwareAction] with the
  /// [inferredType].
  ///
  /// For an null-aware action `v.e` on the [_nullAwareVariable] `v` the created
  /// expression is
  ///
  ///     let v in v == null ? null : v.e
  ///
  Expression createExpression(
      DartType inferredType, Expression nullAwareAction) {
    // End non-nullable promotion of [_nullAwareVariable].
    _inferrer.flowAnalysis.nullAwareAccess_end();
    // End non-nullable promotion of the initializer of [_nullAwareVariable].
    _inferrer.flowAnalysis.nullAwareAccess_end();
    Expression equalsNull = _inferrer.createEqualsNull(
        _nullAwareFileOffset, createVariableGet(_nullAwareVariable));
    ConditionalExpression condition = new ConditionalExpression(
        equalsNull,
        new NullLiteral()..fileOffset = _nullAwareFileOffset,
        nullAwareAction,
        inferredType)
      ..fileOffset = _nullAwareFileOffset;
    return new Let(_nullAwareVariable, condition)
      ..fileOffset = _nullAwareFileOffset;
  }

  @override
  String toString() =>
      'NullAwareGuard($_nullAwareVariable,$_nullAwareFileOffset)';
}

/// The result of an expression inference that is guarded with a null aware
/// variable.
class NullAwareExpressionInferenceResult implements ExpressionInferenceResult {
  /// The inferred type of the expression.
  @override
  final DartType inferredType;

  /// The inferred type of the [nullAwareAction].
  @override
  final DartType nullAwareActionType;

  @override
  final Link<NullAwareGuard> nullAwareGuards;

  @override
  final Expression nullAwareAction;

  NullAwareExpressionInferenceResult(this.inferredType,
      this.nullAwareActionType, this.nullAwareGuards, this.nullAwareAction)
      : assert(nullAwareGuards.isNotEmpty),
        // ignore: unnecessary_null_comparison
        assert(nullAwareAction != null);

  @override
  Expression get expression {
    throw new UnsupportedError('Shorting must be explicitly stopped before'
        'accessing the expression result of a '
        'NullAwareExpressionInferenceResult');
  }

  @override
  ExpressionInferenceResult stopShorting() {
    Expression expression = nullAwareAction;
    Link<NullAwareGuard> nullAwareGuard = nullAwareGuards;
    while (nullAwareGuard.isNotEmpty) {
      expression =
          nullAwareGuard.head.createExpression(inferredType, expression);
      nullAwareGuard = nullAwareGuard.tail!;
    }
    return new ExpressionInferenceResult(inferredType, expression);
  }

  @override
  String toString() =>
      'NullAwareExpressionInferenceResult($inferredType,$nullAwareGuards,'
      '$nullAwareAction)';
}

enum ObjectAccessTargetKind {
  /// A valid access to a statically known instance member on a non-nullable
  /// receiver.
  instanceMember,

  /// A potentially nullable access to a statically known instance member. This
  /// is an erroneous case and a compile-time error is reported.
  nullableInstanceMember,

  /// A valid access to a statically known instance Object member on a
  /// potentially nullable receiver.
  objectMember,

  /// A (non-nullable) access to the `.call` method of a function. This is used
  /// for access on `Function` and on function types.
  callFunction,

  /// A potentially nullable access to the `.call` method of a function. This is
  /// an erroneous case and a compile-time error is reported.
  nullableCallFunction,

  /// A valid access to an extension member.
  extensionMember,

  /// A potentially nullable access to an extension member on an extension of
  /// a non-nullable type. This is an erroneous case and a compile-time error is
  /// reported.
  nullableExtensionMember,

  /// An access on a receiver of type `dynamic`.
  dynamic,

  /// An access on a receiver of type `Never`.
  never,

  /// An access on a receiver of an invalid type. This case is the result of
  /// a previously report error and no error is report this case.
  invalid,

  /// An access to a statically unknown instance member. This is an erroneous
  /// case and a compile-time error is reported.
  missing,

  /// An access to multiple extension members, none of which are most specific.
  /// This is an erroneous case and a compile-time error is reported.
  ambiguous,
}

/// Result for performing an access on an object, like `o.foo`, `o.foo()` and
/// `o.foo = ...`.
class ObjectAccessTarget {
  final ObjectAccessTargetKind kind;
  final Member? member;

  const ObjectAccessTarget.internal(this.kind, this.member);

  /// Creates an access to the instance [member].
  factory ObjectAccessTarget.interfaceMember(Member member,
      {required bool isPotentiallyNullable}) {
    // ignore: unnecessary_null_comparison
    assert(member != null);
    // ignore: unnecessary_null_comparison
    assert(isPotentiallyNullable != null);
    return new ObjectAccessTarget.internal(
        isPotentiallyNullable
            ? ObjectAccessTargetKind.nullableInstanceMember
            : ObjectAccessTargetKind.instanceMember,
        member);
  }

  /// Creates an access to the Object [member].
  factory ObjectAccessTarget.objectMember(Member member) {
    // ignore: unnecessary_null_comparison
    assert(member != null);
    return new ObjectAccessTarget.internal(
        ObjectAccessTargetKind.objectMember, member);
  }

  /// Creates an access to the extension [member].
  factory ObjectAccessTarget.extensionMember(
      Member member,
      Member? tearoffTarget,
      ProcedureKind kind,
      List<DartType> inferredTypeArguments,
      {bool isPotentiallyNullable}) = ExtensionAccessTarget;

  /// Creates an access to a 'call' method on a function, i.e. a function
  /// invocation.
  const ObjectAccessTarget.callFunction()
      : this.internal(ObjectAccessTargetKind.callFunction, null);

  /// Creates an access to a 'call' method on a potentially nullable function,
  /// i.e. a function invocation.
  const ObjectAccessTarget.nullableCallFunction()
      : this.internal(ObjectAccessTargetKind.nullableCallFunction, null);

  /// Creates an access on a dynamic receiver type with no known target.
  const ObjectAccessTarget.dynamic()
      : this.internal(ObjectAccessTargetKind.dynamic, null);

  /// Creates an access on a receiver of type Never with no known target.
  const ObjectAccessTarget.never()
      : this.internal(ObjectAccessTargetKind.never, null);

  /// Creates an access with no target due to an invalid receiver type.
  ///
  /// This is not in itself an error but a consequence of another error.
  const ObjectAccessTarget.invalid()
      : this.internal(ObjectAccessTargetKind.invalid, null);

  /// Creates an access with no target.
  ///
  /// This is an error case.
  const ObjectAccessTarget.missing()
      : this.internal(ObjectAccessTargetKind.missing, null);

  /// Returns `true` if this is an access to an instance member.
  bool get isInstanceMember => kind == ObjectAccessTargetKind.instanceMember;

  /// Returns `true` if this is an access to an Object member.
  bool get isObjectMember => kind == ObjectAccessTargetKind.objectMember;

  /// Returns `true` if this is an access to an extension member.
  bool get isExtensionMember => kind == ObjectAccessTargetKind.extensionMember;

  /// Returns `true` if this is an access to the 'call' method on a function.
  bool get isCallFunction => kind == ObjectAccessTargetKind.callFunction;

  /// Returns `true` if this is an access to the 'call' method on a potentially
  /// nullable function.
  bool get isNullableCallFunction =>
      kind == ObjectAccessTargetKind.nullableCallFunction;

  /// Returns `true` if this is an access on a `dynamic` receiver type.
  bool get isDynamic => kind == ObjectAccessTargetKind.dynamic;

  /// Returns `true` if this is an access on a `Never` receiver type.
  bool get isNever => kind == ObjectAccessTargetKind.never;

  /// Returns `true` if this is an access on an invalid receiver type.
  bool get isInvalid => kind == ObjectAccessTargetKind.invalid;

  /// Returns `true` if this is an access with no target.
  bool get isMissing => kind == ObjectAccessTargetKind.missing;

  /// Returns `true` if this is an access with no unambiguous target. This
  /// occurs when an implicit extension access is ambiguous.
  bool get isAmbiguous => kind == ObjectAccessTargetKind.ambiguous;

  /// Returns `true` if this is an access to an instance member on a potentially
  /// nullable receiver.
  bool get isNullableInstanceMember =>
      kind == ObjectAccessTargetKind.nullableInstanceMember;

  /// Returns `true` if this is an access to an instance member on a potentially
  /// nullable receiver.
  bool get isNullableExtensionMember =>
      kind == ObjectAccessTargetKind.nullableExtensionMember;

  /// Returns `true` if this is an access to an instance member on a potentially
  /// nullable receiver.
  bool get isNullable =>
      isNullableInstanceMember ||
      isNullableCallFunction ||
      isNullableExtensionMember;

  /// Returns the candidates for an ambiguous extension access.
  List<ExtensionAccessCandidate> get candidates =>
      throw new UnsupportedError('ObjectAccessTarget.candidates');

  /// Returns the original procedure kind, if this is an extension method
  /// target.
  ///
  /// This is need because getters, setters, and methods are converted into
  /// top level methods, but access and invocation should still be treated as
  /// if they are the original procedure kind.
  ProcedureKind get extensionMethodKind =>
      throw new UnsupportedError('ObjectAccessTarget.extensionMethodKind');

  /// Returns inferred type arguments for the type parameters of an extension
  /// method that comes from the extension declaration.
  List<DartType> get inferredExtensionTypeArguments =>
      throw new UnsupportedError(
          'ObjectAccessTarget.inferredExtensionTypeArguments');

  /// Returns the member to use for a tearoff.
  ///
  /// This is currently used for extension methods.
  // TODO(johnniwinther): Normalize use by having `readTarget` and
  //  `invokeTarget`?
  Member? get tearoffTarget =>
      throw new UnsupportedError('ObjectAccessTarget.tearoffTarget');

  @override
  String toString() => 'ObjectAccessTarget($kind,$member)';
}

class ExtensionAccessTarget extends ObjectAccessTarget {
  @override
  final Member? tearoffTarget;
  @override
  final ProcedureKind extensionMethodKind;
  @override
  final List<DartType> inferredExtensionTypeArguments;

  ExtensionAccessTarget(Member member, this.tearoffTarget,
      this.extensionMethodKind, this.inferredExtensionTypeArguments,
      {bool isPotentiallyNullable: false})
      : super.internal(
            isPotentiallyNullable
                ? ObjectAccessTargetKind.nullableExtensionMember
                : ObjectAccessTargetKind.extensionMember,
            member);

  @override
  String toString() =>
      'ExtensionAccessTarget($kind,$member,$extensionMethodKind,'
      '$inferredExtensionTypeArguments)';
}

class AmbiguousExtensionAccessTarget extends ObjectAccessTarget {
  @override
  final List<ExtensionAccessCandidate> candidates;

  AmbiguousExtensionAccessTarget(this.candidates)
      : super.internal(ObjectAccessTargetKind.ambiguous, null);

  @override
  String toString() => 'AmbiguousExtensionAccessTarget($kind,$candidates)';
}

class ExtensionAccessCandidate {
  final MemberBuilder memberBuilder;
  final bool isPlatform;
  final DartType onType;
  final DartType onTypeInstantiateToBounds;
  final ObjectAccessTarget target;

  ExtensionAccessCandidate(this.memberBuilder, this.onType,
      this.onTypeInstantiateToBounds, this.target,
      {required this.isPlatform})
      // ignore: unnecessary_null_comparison
      : assert(isPlatform != null);

  bool? isMoreSpecificThan(TypeSchemaEnvironment typeSchemaEnvironment,
      ExtensionAccessCandidate other) {
    if (this.isPlatform == other.isPlatform) {
      // Both are platform or not platform.
      bool thisIsSubtype = typeSchemaEnvironment.isSubtypeOf(
          this.onType, other.onType, SubtypeCheckMode.withNullabilities);
      bool thisIsSupertype = typeSchemaEnvironment.isSubtypeOf(
          other.onType, this.onType, SubtypeCheckMode.withNullabilities);
      if (thisIsSubtype && !thisIsSupertype) {
        // This is subtype of other and not vice-versa.
        return true;
      } else if (thisIsSupertype && !thisIsSubtype) {
        // [other] is subtype of this and not vice-versa.
        return false;
      } else if (thisIsSubtype || thisIsSupertype) {
        thisIsSubtype = typeSchemaEnvironment.isSubtypeOf(
            this.onTypeInstantiateToBounds,
            other.onTypeInstantiateToBounds,
            SubtypeCheckMode.withNullabilities);
        thisIsSupertype = typeSchemaEnvironment.isSubtypeOf(
            other.onTypeInstantiateToBounds,
            this.onTypeInstantiateToBounds,
            SubtypeCheckMode.withNullabilities);
        if (thisIsSubtype && !thisIsSupertype) {
          // This is subtype of other and not vice-versa.
          return true;
        } else if (thisIsSupertype && !thisIsSubtype) {
          // [other] is subtype of this and not vice-versa.
          return false;
        }
      }
    } else if (other.isPlatform) {
      // This is not platform, [other] is: this  is more specific.
      return true;
    } else {
      // This is platform, [other] is not: other is more specific.
      return false;
    }
    // Neither is more specific than the other.
    return null;
  }
}

/// Describes assignability kind of one type to another.
enum AssignabilityKind {
  /// Unconditionally assignable.
  assignable,

  /// Assignable, but needs an implicit downcast.
  assignableCast,

  /// Unconditionally unassignable.
  unassignable,

  /// Trying to use void in an inappropriate context.
  unassignableVoid,

  /// The right-hand side type is precise, and the downcast will fail.
  unassignablePrecise,

  /// Unassignable because the tear-off can't be done on the nullable receiver.
  unassignableCantTearoff,

  /// Unassignable only because of nullability modifiers.
  unassignableNullability,
}

class AssignabilityResult {
  final AssignabilityKind kind;
  final DartType? subtype; // Can be null.
  final DartType? supertype; // Can be null.
  final bool needsTearOff;
  final ImplicitInstantiation? implicitInstantiation;

  const AssignabilityResult(this.kind,
      {required this.needsTearOff, this.implicitInstantiation})
      : subtype = null,
        supertype = null;

  AssignabilityResult.withTypes(this.kind, this.subtype, this.supertype,
      {required this.needsTearOff, this.implicitInstantiation});
}

/// Convenient way to return both a tear-off expression and its type.
class TypedTearoff {
  final DartType tearoffType;
  final Expression tearoff;

  TypedTearoff(this.tearoffType, this.tearoff);
}

FunctionType replaceReturnType(FunctionType functionType, DartType returnType) {
  return new FunctionType(functionType.positionalParameters, returnType,
      functionType.declaredNullability,
      requiredParameterCount: functionType.requiredParameterCount,
      namedParameters: functionType.namedParameters,
      typeParameters: functionType.typeParameters);
}

class InferredFunctionBody {
  final Statement body;
  final DartType? futureValueType;

  InferredFunctionBody(this.body, this.futureValueType);
}

class _WhyNotPromotedVisitor
    implements
        NonPromotionReasonVisitor<LocatedMessage?, Node, VariableDeclaration,
            DartType> {
  final InferenceVisitorBase inferrer;

  Member? propertyReference;

  DartType? propertyType;

  _WhyNotPromotedVisitor(this.inferrer);

  @override
  LocatedMessage? visitDemoteViaExplicitWrite(
      DemoteViaExplicitWrite<VariableDeclaration> reason) {
    TreeNode node = reason.node as TreeNode;
    if (inferrer.dataForTesting != null) {
      inferrer.dataForTesting!.flowAnalysisResult
          .nonPromotionReasonTargets[node] = reason.shortName;
    }
    int offset = node.fileOffset;
    return templateVariableCouldBeNullDueToWrite
        .withArguments(reason.variable.name!, reason.documentationLink)
        .withLocation(inferrer.helper.uri, offset, noLength);
  }

  @override
  LocatedMessage? visitPropertyNotPromoted(
      PropertyNotPromoted<DartType> reason) {
    Object? member = reason.propertyMember;
    if (member is Member) {
      propertyReference = member;
      propertyType = reason.staticType;
      return templateFieldNotPromoted
          .withArguments(reason.propertyName, reason.documentationLink)
          .withLocation(member.fileUri, member.fileOffset, noLength);
    } else {
      assert(member == null,
          'Unrecognized property member: ${member.runtimeType}');
      return null;
    }
  }

  @override
  LocatedMessage visitThisNotPromoted(ThisNotPromoted reason) {
    return templateThisNotPromoted
        .withArguments(reason.documentationLink)
        .withoutLocation();
  }
}

/// Sentinel type used as the result in top level inference when the type is
/// not needed.
// TODO(johnniwinther): Should we have a special DartType implementation for
// this.
final DartType noInferredType = new UnknownType();

class ImplicitInstantiation {
  /// The type arguments for the instantiation.
  final List<DartType> typeArguments;

  /// The function type before the instantiation.
  final FunctionType functionType;

  /// The function type after the instantiation.
  final DartType instantiatedType;

  ImplicitInstantiation(
      this.typeArguments, this.functionType, this.instantiatedType);
}

/// Information about an invocation argument that needs to be resolved later due
/// to the fact that it's a function literal and the `inference-update-1`
/// feature is enabled.
class _DeferredParamInfo extends _ParamInfo {
  /// The argument expression (possibly wrapped in an arbitrary number of
  /// ParenthesizedExpressions).
  final Expression argumentExpression;

  /// The unparenthesized argument expression.
  final FunctionExpression unparenthesizedExpression;

  /// Indicates whether this is a named argument.
  final bool isNamed;

  /// The index into the full argument list (considering both named and unnamed
  /// arguments) of the function literal expression.
  final int evaluationOrderIndex;

  /// The index into either [Arguments.named] or [Arguments.positional] of the
  /// function literal expression (depending upon the value of [isNamed]).
  final int index;

  _DeferredParamInfo(
      {required DartType formalType,
      required this.argumentExpression,
      required this.unparenthesizedExpression,
      required this.isNamed,
      required this.evaluationOrderIndex,
      required this.index})
      : super(formalType);
}

/// Extension of the shared [FunctionLiteralDependencies] logic used by the
/// front end.
class _FunctionLiteralDependencies extends FunctionLiteralDependencies<
    TypeParameter, _ParamInfo, _DeferredParamInfo> {
  _FunctionLiteralDependencies(
      Iterable<_DeferredParamInfo> deferredParamInfo,
      Iterable<TypeParameter> typeVariables,
      List<_ParamInfo> undeferredParamInfo)
      : super(deferredParamInfo, typeVariables, undeferredParamInfo);

  @override
  Iterable<TypeParameter> typeVarsFreeInParamParams(
      _DeferredParamInfo paramInfo) {
    DartType type = paramInfo.formalType;
    if (type is FunctionType) {
      Map<Object, DartType> parameterMap = _computeParameterMap(type);
      Set<Object> explicitlyTypedParameters =
          _computeExplicitlyTypedParameterSet(
              paramInfo.unparenthesizedExpression);
      Set<TypeParameter> result = {};
      for (MapEntry<Object, DartType> entry in parameterMap.entries) {
        if (explicitlyTypedParameters.contains(entry.key)) continue;
        result.addAll(allFreeTypeVariables(entry.value));
      }
      return result;
    } else {
      return const [];
    }
  }

  @override
  Iterable<TypeParameter> typeVarsFreeInParamReturns(_ParamInfo paramInfo) {
    DartType type = paramInfo.formalType;
    if (type is FunctionType) {
      return allFreeTypeVariables(type.returnType);
    } else {
      return allFreeTypeVariables(type);
    }
  }
}

/// Information about an invocation argument that may or may not have already
/// been resolved, as part of the deferred resolution mechanism for the
/// `inference-update-1` feature.
class _ParamInfo {
  /// The (unsubstituted) type of the formal parameter corresponding to this
  /// argument.
  final DartType formalType;

  _ParamInfo(this.formalType);
}
