// 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 file.

import 'package:js_shared/synced/embedded_names.dart' show JsGetName;
import 'package:js_shared/variance.dart';
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/class_hierarchy.dart' as ir;
import 'package:kernel/core_types.dart' as ir;
// ignore: implementation_imports
import 'package:kernel/src/bounds_checks.dart' as ir;
import 'package:kernel/text/debug_printer.dart';
import 'package:kernel/type_environment.dart' as ir;

import '../common.dart';
import '../common/elements.dart';
import '../common/names.dart';
import '../constants/values.dart';
import '../elements/entities.dart';
import '../elements/entity_map.dart';
import '../elements/names.dart';
import '../elements/types.dart';
import '../ir/annotations.dart';
import '../ir/element_map.dart';
import '../ir/impact.dart';
import '../ir/impact_data.dart';
import '../ir/types.dart';
import '../ir/util.dart';
import '../ir/visitors.dart';
import '../js/js.dart' as js;
import '../js_backend/annotations.dart';
import '../js_backend/backend_impact.dart';
import '../js_backend/backend_usage.dart';
import '../js_backend/custom_elements_analysis.dart';
import '../js_backend/namer.dart';
import '../js_backend/native_data.dart';
import '../js_backend/runtime_types_resolution.dart';
import '../js_model/elements.dart';
import '../js_model/locals.dart';
import '../native/behavior.dart';
import '../native/enqueue.dart';
import '../options.dart';
import '../ordered_typeset.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
import '../universe/world_impact.dart';
import 'dart2js_target.dart';
import 'element_map.dart';
import 'env.dart';
import 'kernel_impact.dart';
import 'transformations/modular/late_lowering.dart'
    as late_lowering
    show
        isBackingFieldForLateInstanceField,
        isBackingFieldForLateFinalInstanceField;

/// Implementation of [IrToElementMap] that only supports world
/// impact computation.
class KernelToElementMap implements IrToElementMap {
  final CompilerOptions options;
  @override
  final DiagnosticReporter reporter;
  final NativeBasicDataBuilder nativeBasicDataBuilder =
      NativeBasicDataBuilder();
  NativeBasicData? _nativeBasicData;
  late final KCommonElements _commonElements;
  late final KernelElementEnvironment _elementEnvironment;
  late final DartTypeConverter _typeConverter;
  late final KernelDartTypes _types;
  ir.CoreTypes? _coreTypes;
  ir.TypeEnvironment? _typeEnvironment;
  ir.ClassHierarchy? _classHierarchy;
  late final ConstantValuefier _constantValuefier;

  /// Library environment. Used for fast lookup.
  KProgramEnv env = KProgramEnv();

  /// TODO(natebiggs): Align J- and K- names here. We only have J- entities now
  /// so we should drop the J- prefix.
  final EntityDataEnvMap<JLibrary, KLibraryData, KLibraryEnv> libraries =
      EntityDataEnvMap<JLibrary, KLibraryData, KLibraryEnv>();
  final EntityDataEnvMap<JClass, KClassData, KClassEnv> classes =
      EntityDataEnvMap<JClass, KClassData, KClassEnv>();
  final EntityDataMap<JMember, KMemberData> members =
      EntityDataMap<JMember, KMemberData>();
  final EntityDataMap<JTypeVariable, KTypeVariableData> typeVariables =
      EntityDataMap<JTypeVariable, KTypeVariableData>();

  /// Set to `true` before creating the J-World from the K-World to assert that
  /// no entities are created late.
  bool envIsClosed = false;

  final Map<ir.Library, JLibrary> libraryMap = {};
  final Map<ir.Class, JClass> classMap = {};

  /// Map from [ir.TypeParameter] nodes to the corresponding
  /// [TypeVariableEntity].
  ///
  /// Normally the type variables are [JTypeVariable]s, but for type
  /// parameters on local function (in the frontend) these are _not_ since
  /// their type declaration is neither a class nor a member. In the backend,
  /// these type parameters belong to the call-method and are therefore indexed.
  final Map<ir.TypeParameter, TypeVariableEntity> typeVariableMap = {};
  final Map<ir.Member, JConstructor> constructorMap = {};
  final Map<ir.Procedure, JFunction> methodMap = {};
  final Map<ir.Field, JField> fieldMap = {};
  final Map<ir.TreeNode, Local> localFunctionMap = {};

  BehaviorBuilder? _nativeBehaviorBuilder;

  Map<ir.Member, ImpactData>? impactDataForTesting;

  KernelToElementMap(this.reporter, this.options) {
    _elementEnvironment = KernelElementEnvironment(this);
    _typeConverter = DartTypeConverter(this);
    _types = KernelDartTypes(this);
    _commonElements = KCommonElements(_types, _elementEnvironment);
    _constantValuefier = ConstantValuefier(this);
  }

  /// Access to the [DartTypes] object.
  DartTypes get types => _types;

  KernelElementEnvironment get elementEnvironment => _elementEnvironment;

  /// Access to the commonly used elements and types.
  @override
  KCommonElements get commonElements => _commonElements;

  FunctionEntity? get _mainFunction {
    return env.mainMethod != null
        ? getMethodInternal(env.mainMethod as ir.Procedure)
        : null;
  }

  LibraryEntity? get _mainLibrary {
    return env.mainMethod != null
        ? getLibraryInternal(env.mainMethod!.enclosingLibrary)
        : null;
  }

  SourceSpan getSourceSpan(Spannable spannable, Entity? currentElement) {
    SourceSpan fromSpannable(Spannable spannable) {
      if (spannable is JLibrary) {
        KLibraryEnv env = libraries.getEnv(spannable);
        return computeSourceSpanFromTreeNode(env.library);
      } else if (spannable is JClass) {
        KClassData data = classes.getData(spannable);
        return computeSourceSpanFromTreeNode(data.node);
      } else if (spannable is JMember) {
        KMemberData data = members.getData(spannable);
        return computeSourceSpanFromTreeNode(data.node);
      } else if (spannable is JLocalFunction) {
        return getSourceSpan(spannable.memberContext, currentElement);
      } else if (spannable is JLocal) {
        return getSourceSpan(spannable.memberContext, currentElement);
      }
      return SourceSpan.unknown();
    }

    SourceSpan sourceSpan = fromSpannable(spannable);
    if (sourceSpan.isKnown) return sourceSpan;
    return fromSpannable(currentElement!);
  }

  LibraryEntity? lookupLibrary(Uri uri) {
    KLibraryEnv? libraryEnv = env.lookupLibrary(uri);
    if (libraryEnv == null) return null;
    return getLibraryInternal(libraryEnv.library, libraryEnv);
  }

  String _getLibraryName(JLibrary library) {
    KLibraryEnv libraryEnv = libraries.getEnv(library);
    return libraryEnv.library.name ?? '';
  }

  MemberEntity? lookupLibraryMember(
    JLibrary library,
    String name, {
    bool setter = false,
  }) {
    KLibraryEnv libraryEnv = libraries.getEnv(library);
    ir.Member? member = libraryEnv.lookupMember(name, setter: setter);
    return member != null ? getMember(member) : null;
  }

  void _forEachLibraryMember(
    JLibrary library,
    void Function(MemberEntity member) f,
  ) {
    KLibraryEnv libraryEnv = libraries.getEnv(library);
    libraryEnv.forEachMember((ir.Member node) {
      f(getMember(node));
    });
  }

  ClassEntity? lookupClass(JLibrary library, String name) {
    KLibraryEnv libraryEnv = libraries.getEnv(library);
    KClassEnv? classEnv = libraryEnv.lookupClass(name);
    if (classEnv != null) {
      return getClassInternal(classEnv.cls, classEnv);
    }
    return null;
  }

  void _forEachClass(JLibrary library, void Function(ClassEntity cls) f) {
    KLibraryEnv libraryEnv = libraries.getEnv(library);
    libraryEnv.forEachClass((KClassEnv classEnv) {
      if (!classEnv.isUnnamedMixinApplication) {
        f(getClassInternal(classEnv.cls, classEnv));
      }
    });
  }

  /// Returns the [ClassEntity] for [node] while ensuring that the member
  /// environment for [node] is computed.
  ///
  /// This is needed to ensure that live members are always included in the
  /// environment of a class. Static members and mixed in members a member
  /// can be become live through static access and mixin application,
  /// respectively, which does not require lookup into the class members.
  ///
  /// Since the J-model class environment is computed from the K-model
  /// environment, not ensuring the computation of the class members, can result
  /// in a live member being present in the J-model but unavailable when queried
  /// as a member of its enclosing class.
  JClass getClassForMemberInternal(ir.Class node) {
    final cls = getClassInternal(node);
    classes.getEnv(cls).ensureMembers(this);
    return cls;
  }

  MemberEntity? lookupClassMember(
    JClass cls,
    Name name, {
    bool setter = false,
  }) {
    KClassEnv classEnv = classes.getEnv(cls);
    return classEnv.lookupMember(this, name);
  }

  ConstructorEntity? lookupConstructor(JClass cls, String name) {
    KClassEnv classEnv = classes.getEnv(cls);
    return classEnv.lookupConstructor(this, name);
  }

  /// Return the [InterfaceType] corresponding to the [cls] with the given
  /// [typeArguments] and [nullability].
  @override
  InterfaceType createInterfaceType(
    ir.Class cls,
    List<ir.DartType> typeArguments,
  ) {
    return types.interfaceType(getClass(cls), getDartTypes(typeArguments));
  }

  LibraryEntity getLibrary(ir.Library node) => getLibraryInternal(node);

  /// Returns the [ClassEntity] corresponding to the class [node].
  @override
  ClassEntity getClass(ir.Class node) => getClassInternal(node);

  @override
  InterfaceType? getSuperType(JClass cls) {
    KClassData data = classes.getData(cls);
    _ensureSupertypes(cls, data);
    return data.supertype;
  }

  /// Returns the superclass of [cls] if any.

  ClassEntity? getSuperClass(ClassEntity cls) {
    return getSuperType(cls as JClass)?.element;
  }

  void _ensureCallType(ClassEntity cls, KClassData data) {
    if (!data.isCallTypeComputed) {
      MemberEntity? callMember = _elementEnvironment.lookupClassMember(
        cls,
        Names.call,
      );
      if (callMember is FunctionEntity &&
          callMember.isFunction &&
          !callMember.isAbstract) {
        data.callType = _elementEnvironment.getFunctionType(callMember);
      }
      data.isCallTypeComputed = true;
    }
  }

  void _ensureThisAndRawType(ClassEntity cls, KClassData data) {
    if (data.thisType == null) {
      ir.Class node = data.node;
      if (node.typeParameters.isEmpty) {
        data.thisType = data.rawType = types.interfaceType(
          cls,
          const <DartType>[],
        );
      } else {
        data.thisType = types.interfaceType(
          cls,
          List<DartType>.generate(node.typeParameters.length, (int index) {
            return types.typeVariableType(
              getTypeVariableInternal(node.typeParameters[index]),
            );
          }),
        );
        data.rawType = types.interfaceType(
          cls,
          List<DartType>.filled(
            node.typeParameters.length,
            types.dynamicType(),
          ),
        );
      }
    }
  }

  void _ensureJsInteropType(ClassEntity cls, KClassData data) {
    if (data.jsInteropType == null) {
      ir.Class node = data.node;
      if (node.typeParameters.isEmpty) {
        _ensureThisAndRawType(cls, data);
        data.jsInteropType = data.thisType;
      } else {
        data.jsInteropType = types.interfaceType(
          cls,
          List<DartType>.filled(node.typeParameters.length, types.anyType()),
        );
      }
    }
  }

  void _ensureClassInstantiationToBounds(ClassEntity cls, KClassData data) {
    if (data.instantiationToBounds == null) {
      ir.Class node = data.node;
      if (node.typeParameters.isEmpty) {
        _ensureThisAndRawType(cls, data);
        data.instantiationToBounds = data.thisType;
      } else {
        data.instantiationToBounds = getInterfaceType(
          ir.instantiateToBounds(
            coreTypes.nonNullableRawType(node),
            coreTypes.objectClass,
          ) as ir.InterfaceType,
        );
      }
    }
  }

  @override
  TypeVariableEntity getTypeVariable(ir.TypeParameter node) =>
      getTypeVariableInternal(node);

  void _ensureSupertypes(ClassEntity cls, KClassData data) {
    if (data.orderedTypeSet == null) {
      _ensureThisAndRawType(cls, data);

      ir.Class node = data.node;

      if (node.supertype == null) {
        data.orderedTypeSet = OrderedTypeSet.singleton(data.thisType!);
        data.isMixinApplication = false;
        data.interfaces = const <InterfaceType>[];
      } else {
        // Set of canonical supertypes.
        //
        // This is necessary to support when a class implements the same
        // supertype in multiple non-conflicting ways, like implementing A<int*>
        // and A<int?> or B<Object?> and B<dynamic>.
        Set<InterfaceType> canonicalSupertypes = <InterfaceType>{};

        InterfaceType processSupertype(ir.Supertype supertypeNode) {
          supertypeNode = classHierarchy.getClassAsInstanceOf(
            node,
            supertypeNode.classNode,
          )!;
          InterfaceType supertype = _typeConverter.visitSupertype(
            supertypeNode,
          );
          canonicalSupertypes.add(supertype);
          JClass superclass = supertype.element as JClass;
          KClassData superdata = classes.getData(superclass);
          _ensureSupertypes(superclass, superdata);
          for (InterfaceType supertype
              in superdata.orderedTypeSet!.supertypes!) {
            ir.Supertype? canonicalSupertype = classHierarchy
                .getClassAsInstanceOf(
                  node,
                  getClassNode(supertype.element as JClass),
                );
            if (canonicalSupertype != null) {
              supertype = _typeConverter.visitSupertype(canonicalSupertype);
            } else {
              assert(
                supertype.typeArguments.isEmpty,
                "Generic synthetic supertypes are not supported",
              );
            }
            canonicalSupertypes.add(supertype);
          }
          return supertype;
        }

        InterfaceType supertype;
        List<InterfaceType> interfaces = <InterfaceType>[];
        if (node.isMixinDeclaration) {
          // A mixin declaration
          //
          //   mixin M on A, B, C {}
          //
          // is encoded by CFE as
          //
          //   abstract class M extends A implements B, C {}
          //   abstract class M extends A&B&C {}
          //
          // but we encode it as
          //
          //   abstract class M extends Object implements A, B, C {}
          //
          // so we need get the superclasses from the on-clause, A, B, and C,
          // through [superclassConstraints].
          for (ir.Supertype constraint in node.onClause) {
            interfaces.add(processSupertype(constraint));
          }
          // Set superclass to `Object`.
          supertype = _commonElements.objectType;
        } else {
          supertype = processSupertype(node.supertype!);
        }
        if (supertype == _commonElements.objectType) {
          ClassEntity defaultSuperclass = _commonElements.getDefaultSuperclass(
            cls,
            nativeBasicData,
          );
          data.supertype = _elementEnvironment.getRawType(defaultSuperclass);
          assert(
            data.supertype!.typeArguments.isEmpty,
            "Generic default supertypes are not supported",
          );
          canonicalSupertypes.add(data.supertype!);
        } else {
          data.supertype = supertype;
        }
        if (node.mixedInType != null) {
          data.isMixinApplication = true;
          interfaces.add(
            data.mixedInType = processSupertype(node.mixedInType!),
          );
        } else {
          data.isMixinApplication = false;
        }
        for (var supertype in node.implementedTypes) {
          interfaces.add(processSupertype(supertype));
        }
        OrderedTypeSetBuilder setBuilder = KernelOrderedTypeSetBuilder(
          this,
          cls,
        );
        data.orderedTypeSet = setBuilder.createOrderedTypeSet(
          canonicalSupertypes,
        );
        data.interfaces = interfaces;
      }
    }
  }

  /// Returns the [MemberEntity] corresponding to the member [node].
  @override
  MemberEntity getMember(ir.Member node) {
    if (node is ir.Field) {
      return getFieldInternal(node);
    } else if (node is ir.Constructor) {
      return getConstructorInternal(node);
    } else if (node is ir.Procedure) {
      if (node.kind == ir.ProcedureKind.Factory) {
        return getConstructorInternal(node);
      } else {
        return getMethodInternal(node);
      }
    }
    throw UnsupportedError("Unexpected member: $node");
  }

  /// Returns the [ConstructorEntity] corresponding to the generative or factory
  /// constructor [node].
  @override
  ConstructorEntity getConstructor(ir.Member node) =>
      getConstructorInternal(node);

  /// Returns the [ConstructorEntity] corresponding to a super initializer in
  /// [constructor].
  ///
  /// The IR resolves super initializers to a [target] up in the type hierarchy.
  /// Most of the time, the result of this function will be the entity
  /// corresponding to that target. In the presence of unnamed mixins, this
  /// function returns an entity for an intermediate synthetic constructor that
  /// kernel doesn't explicitly represent.
  ///
  /// For example:
  ///     class M {}
  ///     class C extends Object with M {}
  ///
  /// Kernel will say that C()'s super initializer resolves to Object(), but
  /// this function will return an entity representing the unnamed mixin
  /// application "Object+M"'s constructor.
  ConstructorEntity getSuperConstructor(
    ir.Constructor sourceNode,
    ir.Member targetNode,
  ) {
    ConstructorEntity source = getConstructor(sourceNode);
    ClassEntity sourceClass = source.enclosingClass;
    ConstructorEntity target = getConstructor(targetNode);
    ClassEntity targetClass = target.enclosingClass;
    JClass? superClass =
        getSuperType(sourceClass as JClass)?.element as JClass?;
    if (superClass == targetClass) {
      return target;
    }

    /// This path is needed for synthetically injected superclasses like
    /// `Interceptor` and `LegacyJavaScriptObject`.
    KClassEnv env = classes.getEnv(superClass!);
    ConstructorEntity? constructor = env.lookupConstructor(this, target.name);
    if (constructor != null) {
      return constructor;
    }
    throw failedAt(source, "Super constructor for $source not found.");
  }

  /// Returns the [FunctionEntity] corresponding to the procedure [node].
  @override
  FunctionEntity getMethod(ir.Procedure node) => getMethodInternal(node);

  /// Returns the [FieldEntity] corresponding to the field [node].
  @override
  FieldEntity getField(ir.Field node) => getFieldInternal(node);

  /// Returns the [DartType] corresponding to [type].
  @override
  DartType getDartType(ir.DartType type) => _typeConverter.visitType(type);

  /// Returns the [TypeVariableType] corresponding to [type].
  TypeVariableType getTypeVariableType(ir.TypeParameterType type) =>
      getDartType(type).withoutNullability as TypeVariableType;

  List<DartType> getDartTypes(List<ir.DartType> types) {
    List<DartType> list = <DartType>[];
    for (var type in types) {
      list.add(getDartType(type));
    }
    return list;
  }

  /// Returns the [InterfaceType] corresponding to [type].
  InterfaceType getInterfaceType(ir.InterfaceType type) =>
      _typeConverter.visitType(type).withoutNullability as InterfaceType;

  /// Returns the [FunctionType] of the [node].
  @override
  FunctionType getFunctionType(ir.FunctionNode node) {
    DartType returnType;
    if (node.parent is ir.Constructor) {
      // The return type on generative constructors is `void`, but we need
      // `dynamic` type to match the element model.
      returnType = types.dynamicType();
    } else {
      returnType = getDartType(node.returnType);
    }
    List<DartType> parameterTypes = <DartType>[];
    List<DartType> optionalParameterTypes = <DartType>[];

    DartType getParameterType(ir.Variable variable) {
      // isCovariant implies this FunctionNode is a class Procedure.
      var isCovariant =
          variable.isCovariantByDeclaration || variable.isCovariantByClass;
      return types.getTearOffParameterType(
        getDartType(variable.type),
        isCovariant,
      );
    }

    for (ir.PositionalParameter parameter in node.positionalParameters) {
      if (parameterTypes.length == node.requiredParameterCount) {
        optionalParameterTypes.add(getParameterType(parameter));
      } else {
        parameterTypes.add(getParameterType(parameter));
      }
    }
    List<String> namedParameters = <String>[];
    Set<String> requiredNamedParameters = <String>{};
    List<DartType> namedParameterTypes = <DartType>[];
    List<ir.NamedParameter> sortedNamedParameters =
        node.namedParameters.toList()
          ..sort((a, b) => a.parameterName.compareTo(b.parameterName));
    for (ir.NamedParameter parameter in sortedNamedParameters) {
      namedParameters.add(parameter.parameterName);
      namedParameterTypes.add(getParameterType(parameter));
      if (parameter.isRequired) {
        requiredNamedParameters.add(parameter.parameterName);
      }
    }
    List<FunctionTypeVariable> typeVariables;
    if (node.typeParameters.isNotEmpty) {
      List<DartType> typeParameters = <DartType>[];
      for (ir.TypeParameter typeParameter in node.typeParameters) {
        typeParameters.add(
          getDartType(
            ir.TypeParameterType(typeParameter, ir.Nullability.nonNullable),
          ),
        );
      }
      typeVariables = List<FunctionTypeVariable>.generate(
        node.typeParameters.length,
        (int index) => types.functionTypeVariable(index),
      );

      DartType subst(DartType type) {
        return types.subst(typeVariables, typeParameters, type);
      }

      returnType = subst(returnType);
      parameterTypes = parameterTypes.map(subst).toList();
      optionalParameterTypes = optionalParameterTypes.map(subst).toList();
      namedParameterTypes = namedParameterTypes.map(subst).toList();
      for (int index = 0; index < typeVariables.length; index++) {
        typeVariables[index].bound = subst(
          getDartType(node.typeParameters[index].bound),
        );
      }
    } else {
      typeVariables = const <FunctionTypeVariable>[];
    }

    return types.functionType(
      returnType,
      parameterTypes,
      optionalParameterTypes,
      namedParameters,
      requiredNamedParameters,
      namedParameterTypes,
      typeVariables,
    );
  }

  @override
  DartType substByContext(DartType type, InterfaceType context) {
    return types.subst(
      context.typeArguments,
      getThisType(context.element as JClass).typeArguments,
      type,
    );
  }

  /// Returns the type of the `call` method on 'type'.
  ///
  /// If [type] doesn't have a `call` member or has a non-method `call` member,
  /// `null` is returned.
  @override
  FunctionType? getCallType(InterfaceType type) {
    JClass cls = type.element as JClass;
    KClassData data = classes.getData(cls);
    _ensureCallType(cls, data);
    if (data.callType != null) {
      return substByContext(data.callType!, type) as FunctionType?;
    }
    return null;
  }

  @override
  InterfaceType getThisType(JClass cls) {
    KClassData data = classes.getData(cls);
    _ensureThisAndRawType(cls, data);
    return data.thisType!;
  }

  InterfaceType? _getJsInteropType(JClass cls) {
    KClassData data = classes.getData(cls);
    _ensureJsInteropType(cls, data);
    return data.jsInteropType;
  }

  InterfaceType _getRawType(JClass cls) {
    KClassData data = classes.getData(cls);
    _ensureThisAndRawType(cls, data);
    return data.rawType!;
  }

  InterfaceType _getClassInstantiationToBounds(JClass cls) {
    KClassData data = classes.getData(cls);
    _ensureClassInstantiationToBounds(cls, data);
    return data.instantiationToBounds!;
  }

  DartType _getFieldType(JField field) {
    KFieldData data = members.getData(field) as KFieldData;
    return data.getFieldType(this);
  }

  FunctionType _getFunctionType(JFunction function) {
    KFunctionData data = members.getData(function) as KFunctionData;
    return data.getFunctionType(this);
  }

  List<TypeVariableType> _getFunctionTypeVariables(JFunction function) {
    KFunctionData data = members.getData(function) as KFunctionData;
    return data.getFunctionTypeVariables(this);
  }

  @override
  DartType getTypeVariableBound(JTypeVariable typeVariable) {
    KTypeVariableData data = typeVariables.getData(typeVariable);
    return data.getBound(this);
  }

  @override
  List<Variance> getTypeVariableVariances(JClass cls) {
    KClassData data = classes.getData(cls);
    return data.getVariances();
  }

  /// Returns the class mixed into [cls] if any.
  // TODO(johnniwinther): Replace this by a `getAppliedMixins` function that
  // return transitively mixed in classes like in:
  //     class A {}
  //     class B = Object with A;
  //     class C = Object with B;
  ClassEntity? getAppliedMixin(JClass cls) {
    KClassData data = classes.getData(cls);
    _ensureSupertypes(cls, data);
    return data.mixedInType?.element;
  }

  bool _isMixinApplication(JClass cls) {
    KClassData data = classes.getData(cls);
    _ensureSupertypes(cls, data);
    return data.isMixinApplication;
  }

  bool _isUnnamedMixinApplication(JClass cls) {
    KClassEnv env = classes.getEnv(cls);
    return env.isUnnamedMixinApplication;
  }

  void _forEachSupertype(JClass cls, void Function(InterfaceType supertype) f) {
    KClassData data = classes.getData(cls);
    _ensureSupertypes(cls, data);
    data.orderedTypeSet!.supertypes!.forEach(f);
  }

  void _forEachMixin(JClass? cls, void Function(ClassEntity mixin) f) {
    while (cls != null) {
      KClassData data = classes.getData(cls);
      _ensureSupertypes(cls, data);
      if (data.mixedInType != null) {
        f(data.mixedInType!.element);
      }
      cls = data.supertype?.element as JClass?;
    }
  }

  void _forEachConstructor(
    JClass cls,
    void Function(ConstructorEntity member) f,
  ) {
    KClassEnv env = classes.getEnv(cls);
    env.forEachConstructor(this, f);
  }

  void _forEachLocalClassMember(
    JClass cls,
    void Function(MemberEntity member) f,
  ) {
    KClassEnv env = classes.getEnv(cls);
    env.forEachMember(this, (MemberEntity member) {
      f(member);
    });
  }

  void forEachInjectedClassMember(
    JClass cls,
    void Function(MemberEntity member) f,
  ) {
    throw UnsupportedError(
      'KernelToElementMapBase._forEachInjectedClassMember',
    );
  }

  void _forEachClassMember(
    JClass cls,
    void Function(ClassEntity cls, MemberEntity member) f,
  ) {
    KClassEnv env = classes.getEnv(cls);
    env.forEachMember(this, (MemberEntity member) {
      f(cls, member);
    });
    KClassData data = classes.getData(cls);
    _ensureSupertypes(cls, data);
    if (data.supertype != null) {
      _forEachClassMember(data.supertype!.element as JClass, f);
    }
  }

  @override
  InterfaceType? asInstanceOf(InterfaceType type, ClassEntity cls) {
    OrderedTypeSet orderedTypeSet = getOrderedTypeSet(type.element as JClass);
    InterfaceType? supertype = orderedTypeSet.asInstanceOf(
      cls,
      getHierarchyDepth(cls as JClass),
    );
    if (supertype != null) {
      supertype = substByContext(supertype, type) as InterfaceType?;
    }
    return supertype;
  }

  @override
  OrderedTypeSet getOrderedTypeSet(JClass cls) {
    KClassData data = classes.getData(cls);
    _ensureSupertypes(cls, data);
    return data.orderedTypeSet!;
  }

  /// Returns all supertypes of [cls].
  Iterable<InterfaceType> getSuperTypes(ClassEntity cls) {
    return getOrderedTypeSet(cls as JClass).supertypes!;
  }

  /// Returns the hierarchy depth of [cls].
  @override
  int getHierarchyDepth(JClass cls) {
    KClassData data = classes.getData(cls);
    _ensureSupertypes(cls, data);
    return data.orderedTypeSet!.maxDepth;
  }

  @override
  Iterable<InterfaceType> getInterfaces(JClass cls) {
    KClassData data = classes.getData(cls);
    _ensureSupertypes(cls, data);
    assert(data.interfaces != null);
    return data.interfaces!;
  }

  /// Returns the defining node for [member].
  ir.Member getMemberNode(MemberEntity member) {
    return members.getData(member as JMember).node;
  }

  /// Returns the defining node for [cls].
  ir.Class getClassNode(ClassEntity cls) {
    return classes.getData(cls as JClass).node;
  }

  /// Return the [ImportEntity] corresponding to [node].
  ImportEntity? getImport(ir.LibraryDependency? node) {
    if (node == null) return null;
    ir.Library library = node.enclosingLibrary;
    KLibraryData data = libraries.getData(getLibraryInternal(library));
    return data.imports![node];
  }

  /// Returns the core types for the underlying kernel model.
  @override
  ir.CoreTypes get coreTypes => _coreTypes ??= ir.CoreTypes(env.mainComponent);

  /// Returns the type environment for the underlying kernel model.
  ir.TypeEnvironment get typeEnvironment =>
      _typeEnvironment ??= ir.TypeEnvironment(coreTypes, classHierarchy);

  /// Returns the class hierarchy for the underlying kernel model.
  ir.ClassHierarchy get classHierarchy =>
      _classHierarchy ??= ir.ClassHierarchy(env.mainComponent, coreTypes);

  @override
  Name getName(ir.Name name, {bool setter = false}) {
    return Name(
      name.text,
      name.isPrivate ? name.library!.importUri : null,
      isSetter: setter,
    );
  }

  /// Returns the [CallStructure] corresponding to the [arguments].

  @override
  CallStructure getCallStructure(ir.Arguments arguments) {
    int argumentCount = arguments.positional.length + arguments.named.length;
    List<String> namedArguments = arguments.named.map((e) => e.name).toList();
    return CallStructure(argumentCount, namedArguments, arguments.types.length);
  }

  ParameterStructure getParameterStructure(
    ir.FunctionNode node, {
    // TODO(johnniwinther): Remove this when type arguments are passed to
    // constructors like calling a generic method.
    bool includeTypeParameters = true,
  }) {
    // TODO(johnniwinther): Cache the computed function type.
    int requiredPositionalParameters = node.requiredParameterCount;
    int positionalParameters = node.positionalParameters.length;
    int typeParameters = node.typeParameters.length;
    List<String> namedParameters = <String>[];
    Set<String> requiredNamedParameters = <String>{};
    List<ir.NamedParameter> sortedNamedParameters =
        node.namedParameters.toList()
          ..sort((a, b) => a.parameterName.compareTo(b.parameterName));
    for (var variable in sortedNamedParameters) {
      namedParameters.add(variable.parameterName);
      if (variable.isRequired) {
        requiredNamedParameters.add(variable.parameterName);
      }
    }
    return ParameterStructure(
      requiredPositionalParameters,
      positionalParameters,
      namedParameters,
      requiredNamedParameters,
      includeTypeParameters ? typeParameters : 0,
    );
  }

  /// Returns the [Selector] corresponding to the invocation of [name] with
  /// [arguments].
  Selector getInvocationSelector(
    ir.Name irName,
    int positionalArguments,
    List<String> namedArguments,
    int typeArguments,
  ) {
    Name name = getName(irName);
    SelectorKind kind;
    if (Selector.isOperatorName(name.text)) {
      if (name == Names.indexName || name == Names.indexSetName) {
        kind = SelectorKind.index_;
      } else {
        kind = SelectorKind.operator;
      }
    } else {
      kind = SelectorKind.call;
    }

    CallStructure callStructure = CallStructure(
      positionalArguments + namedArguments.length,
      namedArguments,
      typeArguments,
    );
    return Selector(kind, name, callStructure);
  }

  Selector getGetterSelector(ir.Name irName) {
    Name name = Name(
      irName.text,
      irName.isPrivate ? irName.library!.importUri : null,
    );
    return Selector.getter(name);
  }

  Selector getSetterSelector(ir.Name irName) {
    Name name = Name(
      irName.text,
      irName.isPrivate ? irName.library!.importUri : null,
    );
    return Selector.setter(name);
  }

  /// Looks up [typeName] for use in the spec-string of a `JS` call.
  // TODO(johnniwinther): Use this in [NativeBehavior] instead of calling
  // the `ForeignResolver`.
  TypeLookup typeLookup({required bool resolveAsRaw}) {
    return resolveAsRaw ? _cachedTypeLookupRaw : _cachedTypeLookupFull;
  }

  late final TypeLookup _cachedTypeLookupRaw = _typeLookup(resolveAsRaw: true);
  late final TypeLookup _cachedTypeLookupFull = _typeLookup(
    resolveAsRaw: false,
  );

  TypeLookup _typeLookup({required bool resolveAsRaw}) {
    bool? cachedMayLookupInMain;

    DartType lookup(String typeName, {bool? required}) {
      DartType? findInLibrary(LibraryEntity? library) {
        if (library != null) {
          ClassEntity? cls = elementEnvironment.lookupClass(library, typeName);
          if (cls != null) {
            // TODO(johnniwinther): Align semantics.
            return resolveAsRaw
                ? elementEnvironment.getRawType(cls)
                : elementEnvironment.getThisType(cls);
          }
        }
        return null;
      }

      DartType? findIn(Uri uri) {
        return findInLibrary(elementEnvironment.lookupLibrary(uri));
      }

      // TODO(johnniwinther): Narrow the set of lookups based on the depending
      // library.
      // TODO(johnniwinther): Cache more results to avoid redundant lookups?
      cachedMayLookupInMain ??=
          // Tests permit lookup outside of dart: libraries.
          allowedNativeTest(elementEnvironment.mainLibrary!.canonicalUri);
      DartType? type;
      if (cachedMayLookupInMain!) {
        type ??= findInLibrary(elementEnvironment.mainLibrary);
      }
      type ??= findIn(Uris.dartCore);
      type ??= findIn(Uris.dartJSHelper);
      type ??= findIn(Uris.dartLateHelper);
      type ??= findIn(Uris.dartInterceptors);
      type ??= findIn(Uris.dartNativeTypedData);
      type ??= findIn(Uris.dartCollection);
      type ??= findIn(Uris.dartMath);
      type ??= findIn(Uris.dartHtml);
      type ??= findIn(Uris.dartHtmlCommon);
      type ??= findIn(Uris.dartSvg);
      type ??= findIn(Uris.dartWebAudio);
      type ??= findIn(Uris.dartWebGL);
      type ??= findIn(Uris.dartIndexedDB);
      type ??= findIn(Uris.dartTypedData);
      type ??= findIn(Uris.dartRti);
      type ??= findIn(Uris.dartMirrors);
      if (type == null && required!) {
        reporter.reportErrorMessage(
          currentElementSpannable,
          MessageKind.generic,
          {'text': "Type '$typeName' not found."},
        );
      }
      return type!;
    }

    return lookup;
  }

  String? _getStringArgument(ir.StaticInvocation node, int index) {
    return node.arguments.positional[index].accept(Stringifier());
  }

  /// Computes the [NativeBehavior] for a call to the [JS] function.
  /// TODO(johnniwinther): Cache this for later use.
  NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
    if (node.arguments.positional.length < 2 ||
        node.arguments.named.isNotEmpty) {
      reporter.reportErrorMessage(
        currentElementSpannable,
        MessageKind.wrongArgumentForJS,
      );
      return NativeBehavior();
    }
    String? specString = _getStringArgument(node, 0);
    if (specString == null) {
      reporter.reportErrorMessage(
        currentElementSpannable,
        MessageKind.wrongArgumentForJSFirst,
      );
      return NativeBehavior();
    }

    String? codeString = _getStringArgument(node, 1);
    if (codeString == null) {
      reporter.reportErrorMessage(
        currentElementSpannable,
        MessageKind.wrongArgumentForJSSecond,
      );
      return NativeBehavior();
    }

    return NativeBehavior.ofJsCall(
      specString,
      codeString,
      typeLookup(resolveAsRaw: true),
      currentElementSpannable,
      reporter,
      commonElements,
    );
  }

  /// TODO(johnniwinther): Cache this for later use.
  /// Computes the [NativeBehavior] for a call to the [JS_BUILTIN]
  /// function.
  NativeBehavior getNativeBehaviorForJsBuiltinCall(ir.StaticInvocation node) {
    if (node.arguments.positional.isEmpty) {
      reporter.internalError(
        currentElementSpannable,
        "JS builtin expression has no type.",
      );
    }
    if (node.arguments.positional.length < 2) {
      reporter.internalError(
        currentElementSpannable,
        "JS builtin is missing name.",
      );
    }
    String? specString = _getStringArgument(node, 0);
    if (specString == null) {
      reporter.internalError(
        currentElementSpannable,
        "Unexpected first argument.",
      );
    }
    return NativeBehavior.ofJsBuiltinCall(
      specString,
      typeLookup(resolveAsRaw: true),
      currentElementSpannable,
      reporter,
      commonElements,
    );
  }

  /// Computes the [NativeBehavior] for a call to the
  /// [JS_EMBEDDED_GLOBAL] function.
  /// TODO(johnniwinther): Cache this for later use.
  NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
    ir.StaticInvocation node,
  ) {
    if (node.arguments.positional.isEmpty) {
      reporter.internalError(
        currentElementSpannable,
        "JS embedded global expression has no type.",
      );
    }
    if (node.arguments.positional.length < 2) {
      reporter.internalError(
        currentElementSpannable,
        "JS embedded global is missing name.",
      );
    }
    if (node.arguments.positional.length > 2 ||
        node.arguments.named.isNotEmpty) {
      reporter.internalError(
        currentElementSpannable,
        "JS embedded global has more than 2 arguments.",
      );
    }
    String? specString = _getStringArgument(node, 0);
    if (specString == null) {
      reporter.internalError(
        currentElementSpannable,
        "Unexpected first argument.",
      );
    }
    return NativeBehavior.ofJsEmbeddedGlobalCall(
      specString,
      typeLookup(resolveAsRaw: true),
      currentElementSpannable,
      reporter,
      commonElements,
    );
  }

  /// Returns the [js.Name] for the `JsGetName` [constant] value.
  js.Name? getNameForJsGetName(ConstantValue constant, ModularNamer namer) {
    int? index = extractEnumIndexFromConstantValue(
      constant,
      commonElements.jsGetNameEnum,
    );
    if (index == null) return null;
    return namer.getNameForJsGetName(
      currentElementSpannable,
      JsGetName.values[index],
    );
  }

  int? extractEnumIndexFromConstantValue(
    ConstantValue constant,
    ClassEntity classElement,
  ) {
    if (constant is ConstructedConstantValue) {
      if (constant.type.element == classElement) {
        assert(constant.fields.length == 1 || constant.fields.length == 2);
        ConstantValue indexConstant = constant.fields.values.first;
        if (indexConstant is IntConstantValue) {
          return indexConstant.intValue.toInt();
        }
      }
    }
    return null;
  }

  /// Computes the [ConstantValue] for the constant [node].
  ConstantValue? getConstantValue(
    ir.Expression? node, {
    bool requireConstant = true,
    bool implicitNull = false,
    bool checkCasts = true,
  }) {
    if (node == null) {
      if (!implicitNull) {
        throw failedAt(currentElementSpannable, 'No expression for constant.');
      }
      return NullConstantValue();
    }
    final constant = node is ir.ConstantExpression ? node.constant : null;
    if (constant == null) {
      if (requireConstant) {
        throw UnsupportedError(
          'No constant for ${DebugPrinter.prettyPrint(node)}',
        );
      }
    } else {
      ConstantValue value = _constantValuefier.visitConstant(constant);
      if (!value.isConstant && !requireConstant) {
        return null;
      }
      return value;
    }

    return null;
  }

  /// Converts [annotations] into a list of [ConstantValue]s.
  List<ConstantValue> getMetadata(List<ir.Expression> annotations) {
    if (annotations.isEmpty) return const <ConstantValue>[];
    List<ConstantValue> metadata = <ConstantValue>[];
    for (var node in annotations) {
      // We skip the implicit cast checks for metadata to avoid circular
      // dependencies in the js-interop class registration.
      metadata.add(getConstantValue(node, checkCasts: false)!);
    }
    return metadata;
  }

  /// Returns the `noSuchMethod` [FunctionEntity] call from a
  /// `super.noSuchMethod` invocation within [cls].
  FunctionEntity getSuperNoSuchMethod(ClassEntity cls) {
    while (true) {
      ClassEntity? superclass = elementEnvironment.getSuperClass(cls);
      if (superclass == null) break;
      MemberEntity? member = elementEnvironment.lookupLocalClassMember(
        superclass,
        Names.noSuchMethod_,
      );
      if (member != null && !member.isAbstract) {
        if (member is JMethod) {
          if (member.parameterStructure.positionalParameters >= 1) {
            return member;
          }
        }
        // If [member] is not a valid `noSuchMethod` the target is
        // `Object.superNoSuchMethod`.
        break;
      }
      cls = superclass;
    }
    return elementEnvironment.lookupLocalClassMember(
          commonElements.objectClass,
          Names.noSuchMethod_,
        )!
        as FunctionEntity;
  }

  Iterable<LibraryEntity> get libraryListInternal {
    if (env.length != libraryMap.length) {
      // Create a [JLibrary] for each library.
      env.forEachLibrary((KLibraryEnv env) {
        getLibraryInternal(env.library, env);
      });
    }
    return libraryMap.values;
  }

  JLibrary getLibraryInternal(ir.Library node, [KLibraryEnv? libraryEnv]) {
    return libraryMap[node] ??= _getLibraryCreate(node, libraryEnv);
  }

  JLibrary _getLibraryCreate(ir.Library node, KLibraryEnv? libraryEnv) {
    assert(
      !envIsClosed,
      "Environment of $this is closed. Trying to create "
      "library for $node.",
    );
    Uri canonicalUri = node.importUri;
    String? name = node.name;
    if (name == null) {
      // Use the file name as script name.
      String path = canonicalUri.path;
      name = path.substring(path.lastIndexOf('/') + 1);
    }
    JLibrary library = createLibrary(name, canonicalUri);
    return libraries.register<JLibrary, KLibraryData, KLibraryEnv>(
      library,
      KLibraryData(node),
      libraryEnv ?? env.lookupLibrary(canonicalUri)!,
    );
  }

  JClass getClassInternal(ir.Class node, [KClassEnv? classEnv]) {
    return classMap[node] ??= _getClassCreate(node, classEnv);
  }

  JClass _getClassCreate(ir.Class node, KClassEnv? classEnv) {
    assert(
      !envIsClosed,
      "Environment of $this is closed. Trying to create "
      "class for $node.",
    );
    JLibrary library = getLibraryInternal(node.enclosingLibrary);
    classEnv ??= libraries.getEnv(library).lookupClass(node.name)!;
    JClass cls = createClass(library, node.name, isAbstract: node.isAbstract);
    return classes.register(cls, KClassData(node), classEnv);
  }

  TypeVariableEntity getTypeVariableInternal(ir.TypeParameter node) {
    return typeVariableMap[node] ??= _getTypeVariableCreate(node)!;
  }

  TypeVariableEntity? _getTypeVariableCreate(ir.TypeParameter node) {
    assert(
      !envIsClosed,
      "Environment of $this is closed. Trying to create "
      "type variable for $node.",
    );
    final declaration = node.declaration;
    // TODO(fishythefish): Use exhaustive pattern switch.
    if (declaration is ir.Class) {
      int index = declaration.typeParameters.indexOf(node);
      return typeVariables.register(
        createTypeVariable(getClassInternal(declaration), node.name!, index),
        KTypeVariableData(node),
      );
    } else if (declaration is ir.Procedure) {
      int index = declaration.typeParameters.indexOf(node);
      if (declaration.kind == ir.ProcedureKind.Factory) {
        ir.Class cls = declaration.enclosingClass!;
        return getTypeVariableInternal(cls.typeParameters[index]);
      } else {
        return typeVariables.register(
          createTypeVariable(getMethodInternal(declaration), node.name!, index),
          KTypeVariableData(node),
        );
      }
    } else if (declaration is ir.LocalFunction) {
      // Ensure that local function type variables have been created.
      getLocalFunction(declaration);
      return typeVariableMap[node];
    }
    throw UnsupportedError('Unsupported type parameter type node $node.');
  }

  JConstructor getConstructorInternal(ir.Member node) {
    return constructorMap[node] ??= _getConstructorCreate(node);
  }

  JConstructor _getConstructorCreate(ir.Member node) {
    assert(
      !envIsClosed,
      "Environment of $this is closed. Trying to create "
      "constructor for $node.",
    );
    ir.FunctionNode functionNode;
    final enclosingClass = getClassForMemberInternal(node.enclosingClass!);
    Name name = getName(node.name);
    bool isExternal = node.isExternal;

    JConstructor constructor;
    if (node is ir.Constructor) {
      functionNode = node.function;
      constructor = createGenerativeConstructor(
        enclosingClass,
        name,
        getParameterStructure(functionNode, includeTypeParameters: false),
        isExternal: isExternal,
        isConst: node.isConst,
      );
    } else if (node is ir.Procedure) {
      functionNode = node.function;
      // TODO(sigmund): Check more strictly than just the class name.
      bool isEnvironmentConstructor =
          isExternal &&
          (name.text == 'fromEnvironment' &&
                  const [
                    'int',
                    'bool',
                    'String',
                  ].contains(enclosingClass.name) ||
              name.text == 'hasEnvironment' && enclosingClass.name == 'bool');
      constructor = createFactoryConstructor(
        enclosingClass,
        name,
        getParameterStructure(functionNode, includeTypeParameters: false),
        isExternal: isExternal,
        isConst: node.isConst,
        isFromEnvironmentConstructor: isEnvironmentConstructor,
      );
    } else {
      // TODO(johnniwinther): Convert `node.location` to a [SourceSpan].
      throw failedAt(
        noLocationSpannable,
        "Unexpected constructor node: $node.",
      );
    }
    return members.register<JConstructor, KConstructorData>(
      constructor,
      KConstructorData(node, functionNode),
    );
  }

  JFunction getMethodInternal(ir.Procedure node) {
    // [_getMethodCreate] inserts the created function in [methodMap] so we
    // don't need to use ??= here.
    return methodMap[node] ?? _getMethodCreate(node);
  }

  JFunction _getMethodCreate(ir.Procedure node) {
    assert(
      !envIsClosed,
      "Environment of $this is closed. Trying to create "
      "function for $node.",
    );
    late JFunction function;
    JLibrary library;
    JClass? enclosingClass;
    if (node.enclosingClass != null) {
      enclosingClass = getClassForMemberInternal(node.enclosingClass!);
      library = enclosingClass.library;
    } else {
      library = getLibraryInternal(node.enclosingLibrary);
    }
    Name name = getName(node.name);
    bool isStatic = node.isStatic;
    bool isExternal = node.isExternal;
    bool isAbstract = node.isAbstract;
    AsyncMarker asyncMarker = getAsyncMarker(node.function);
    switch (node.kind) {
      case ir.ProcedureKind.Factory:
        throw UnsupportedError("Cannot create method from factory.");
      case ir.ProcedureKind.Getter:
        function = createGetter(
          library,
          enclosingClass,
          name,
          asyncMarker,
          isStatic: isStatic,
          isExternal: isExternal,
          isAbstract: isAbstract,
        );
        break;
      case ir.ProcedureKind.Method:
      case ir.ProcedureKind.Operator:
        function = createMethod(
          library,
          enclosingClass,
          name,
          getParameterStructure(node.function),
          asyncMarker,
          isStatic: isStatic,
          isExternal: isExternal,
          isAbstract: isAbstract,
        );
        break;
      case ir.ProcedureKind.Setter:
        assert(asyncMarker == AsyncMarker.sync);
        function = createSetter(
          library,
          enclosingClass,
          name.setter,
          isStatic: isStatic,
          isExternal: isExternal,
          isAbstract: isAbstract,
        );
        break;
    }
    members.register<JFunction, KFunctionData>(
      function,
      KFunctionData(node, node.function),
    );
    // We need to register the function before creating the type variables.
    methodMap[node] = function;
    for (ir.TypeParameter typeParameter in node.function.typeParameters) {
      getTypeVariable(typeParameter);
    }
    return function;
  }

  JField getFieldInternal(ir.Field node) {
    return fieldMap[node] ??= _getFieldCreate(node);
  }

  JField _getFieldCreate(ir.Field node) {
    assert(
      !envIsClosed,
      "Environment of $this is closed. Trying to create "
      "field for $node.",
    );
    JLibrary library;
    JClass? enclosingClass;
    if (node.enclosingClass != null) {
      enclosingClass = getClassForMemberInternal(node.enclosingClass!);
      library = enclosingClass.library;
    } else {
      library = getLibraryInternal(node.enclosingLibrary);
    }
    Name name = getName(node.name);
    bool isStatic = node.isStatic;
    bool isLateBackingField = false;
    bool isLateFinalBackingField = false;
    if (enclosingClass != null && !isStatic) {
      isLateBackingField = late_lowering.isBackingFieldForLateInstanceField(
        node,
      );
      isLateFinalBackingField = late_lowering
          .isBackingFieldForLateFinalInstanceField(node);
    }
    JField field = createField(
      library,
      enclosingClass,
      name,
      isStatic: isStatic,
      isAssignable: node.hasSetter,
      isConst: node.isConst,
    );
    return members.register<JField, KFieldData>(
      field,
      KFieldData(
        node,
        isLateBackingField: isLateBackingField,
        isLateFinalBackingField: isLateFinalBackingField,
      ),
    );
  }

  /// NativeBasicData is need for computation of the default super class.
  NativeBasicData get nativeBasicData {
    var data = _nativeBasicData;
    if (data == null) {
      data = _nativeBasicData = nativeBasicDataBuilder.close(
        elementEnvironment,
      );
      assert(
        _nativeBasicData != null,
        failedAt(
          noLocationSpannable,
          "NativeBasicData has not been computed yet.",
        ),
      );
    }
    return data;
  }

  /// Adds libraries in [component] to the set of libraries.
  ///
  /// The main method of the first component is used as the main method for the
  /// compilation.
  void addComponent(ir.Component component) {
    env.addComponent(component);
  }

  BehaviorBuilder get nativeBehaviorBuilder =>
      _nativeBehaviorBuilder ??= BehaviorBuilder(
        elementEnvironment,
        commonElements,
        nativeBasicData,
        reporter,
        options,
      );

  WorldImpact computeWorldImpact(
    JMember member,
    BackendImpacts impacts,
    NativeResolutionEnqueuer nativeResolutionEnqueuer,
    BackendUsageBuilder backendUsageBuilder,
    CustomElementsResolutionAnalysis customElementsResolutionAnalysis,
    RuntimeTypesNeedBuilder rtiNeedBuilder,
    AnnotationsData annotationsData,
    ImpactBuilderData impactBuilderData,
  ) {
    KMemberData memberData = members.getData(member);
    ir.Member node = memberData.node;

    ImpactData impactData = impactBuilderData.impactData;
    if (retainDataForTesting) {
      impactDataForTesting ??= {};
      impactDataForTesting![node] = impactData;
    }
    KernelImpactConverter converter = KernelImpactConverter(
      this,
      member,
      reporter,
      _constantValuefier,
      // TODO(johnniwinther): Pull the static type context from the cached
      // static types.
      ir.StaticTypeContext(node, typeEnvironment),
      impacts,
      nativeResolutionEnqueuer,
      backendUsageBuilder,
      customElementsResolutionAnalysis,
      rtiNeedBuilder,
      annotationsData,
    );
    return converter.convert(impactData);
  }

  /// Returns the kernel [ir.Procedure] node for the [method].
  ir.Procedure lookupProcedure(JFunction method) {
    return members.getData(method).node as ir.Procedure;
  }

  /// Returns the [ir.Library] corresponding to [library].
  ir.Library getLibraryNode(LibraryEntity library) {
    return libraries.getData(library as JLibrary).library;
  }

  /// Returns the [Local] corresponding to the local function [node].
  JLocalFunction getLocalFunction(ir.LocalFunction? node) {
    JLocalFunction? localFunction = localFunctionMap[node!] as JLocalFunction?;
    if (localFunction == null) {
      late MemberEntity memberContext;
      late Entity executableContext;
      ir.TreeNode? parent = node.parent;
      while (parent != null) {
        if (parent is ir.Member) {
          executableContext = memberContext = getMember(parent);
          break;
        }
        if (parent is ir.LocalFunction) {
          JLocalFunction localFunction = getLocalFunction(parent);
          executableContext = localFunction;
          memberContext = localFunction.memberContext;
          break;
        }
        parent = parent.parent;
      }
      String? name;
      late ir.FunctionNode function;
      if (node is ir.FunctionDeclaration) {
        name = node.variable.name;
        function = node.function;
      } else if (node is ir.FunctionExpression) {
        function = node.function;
      }
      localFunction = localFunctionMap[node] = JLocalFunction(
        name,
        memberContext,
        executableContext,
        node,
      );
      int index = 0;
      List<JLocalTypeVariable> typeVariables = <JLocalTypeVariable>[];
      for (ir.TypeParameter typeParameter in function.typeParameters) {
        typeVariables.add(
          typeVariableMap[typeParameter] = JLocalTypeVariable(
            localFunction,
            typeParameter.name!,
            index,
          ),
        );
        index++;
      }
      index = 0;
      for (ir.TypeParameter typeParameter in function.typeParameters) {
        typeVariables[index].bound = getDartType(typeParameter.bound);
        typeVariables[index].defaultType = getDartType(
          typeParameter.defaultType,
        );
        index++;
      }
      localFunction.functionType = getFunctionType(function);
    }
    return localFunction;
  }

  /// Returns `true` if [cls] implements `Function` either explicitly or through
  /// a `call` method.
  bool implementsFunction(JClass cls) {
    KClassData data = classes.getData(cls);
    OrderedTypeSet orderedTypeSet = data.orderedTypeSet!;
    InterfaceType? supertype = orderedTypeSet.asInstanceOf(
      commonElements.functionClass,
      getHierarchyDepth(commonElements.functionClass as JClass),
    );
    if (supertype != null) {
      return true;
    }
    return data.callType?.withoutNullability is FunctionType;
  }

  /// Compute the kind of foreign helper function called by [node], if any.
  ForeignKind getForeignKind(ir.StaticInvocation node) {
    if (commonElements.isForeignHelper(getMember(node.target))) {
      return getForeignKindFromName(node.target.name.text);
    }
    return ForeignKind.none;
  }

  /// Computes the [InterfaceType] referenced by a call to the
  /// [JS_INTERCEPTOR_CONSTANT] function, if any.
  InterfaceType? getInterfaceTypeForJsInterceptorCall(
    ir.StaticInvocation node,
  ) {
    if (node.arguments.positional.length != 1 ||
        node.arguments.named.isNotEmpty) {
      reporter.reportErrorMessage(
        currentElementSpannable,
        MessageKind.wrongArgumentForJSInterceptorConstant,
      );
    }
    ir.Node argument = node.arguments.positional.first;
    if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) {
      return getInterfaceType(argument.type as ir.InterfaceType);
    } else if (argument is ir.ConstantExpression &&
        argument.constant is ir.TypeLiteralConstant) {
      ir.TypeLiteralConstant constant =
          argument.constant as ir.TypeLiteralConstant;
      if (constant.type is ir.InterfaceType) {
        return getInterfaceType(constant.type as ir.InterfaceType);
      }
    }
    return null;
  }

  /// Computes the native behavior for reading the native [field].
  /// TODO(johnniwinther): Cache this for later use.
  NativeBehavior getNativeBehaviorForFieldLoad(
    ir.Field field,
    Iterable<String> createsAnnotations,
    Iterable<String> returnsAnnotations, {
    required bool isJsInterop,
  }) {
    DartType type = getDartType(field.type);
    return nativeBehaviorBuilder.buildFieldLoadBehavior(
      type,
      createsAnnotations,
      returnsAnnotations,
      typeLookup(resolveAsRaw: false),
      isJsInterop: isJsInterop,
    );
  }

  /// Computes the native behavior for writing to the native [field].
  /// TODO(johnniwinther): Cache this for later use.
  NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
    DartType type = getDartType(field.type);
    return nativeBehaviorBuilder.buildFieldStoreBehavior(type);
  }

  /// Computes the native behavior for calling the function or constructor
  /// [member].
  /// TODO(johnniwinther): Cache this for later use.
  NativeBehavior getNativeBehaviorForMethod(
    ir.Member member,
    Iterable<String> createsAnnotations,
    Iterable<String> returnsAnnotations, {
    required bool isJsInterop,
  }) {
    late DartType type;
    if (member is ir.Procedure) {
      type = getFunctionType(member.function);
    } else if (member is ir.Constructor) {
      type = getFunctionType(member.function);
    } else {
      failedAt(currentElementSpannable, "Unexpected method node $member.");
    }
    return nativeBehaviorBuilder.buildMethodBehavior(
      type as FunctionType,
      createsAnnotations,
      returnsAnnotations,
      typeLookup(resolveAsRaw: false),
      isJsInterop: isJsInterop,
    );
  }

  JLibrary createLibrary(String name, Uri canonicalUri) {
    return JLibrary(name, canonicalUri);
  }

  JClass createClass(
    JLibrary library,
    String name, {
    required bool isAbstract,
  }) {
    return JClass(library, name, isAbstract: isAbstract);
  }

  JTypeVariable createTypeVariable(
    Entity typeDeclaration,
    String name,
    int index,
  ) {
    return JTypeVariable(typeDeclaration, name, index);
  }

  JConstructor createGenerativeConstructor(
    JClass enclosingClass,
    Name name,
    ParameterStructure parameterStructure, {
    required bool isExternal,
    required bool isConst,
  }) {
    return JGenerativeConstructor(
      enclosingClass,
      name,
      parameterStructure,
      isExternal: isExternal,
      isConst: isConst,
    );
  }

  // TODO(dart2js-team): Rename isFromEnvironmentConstructor to
  // isEnvironmentConstructor: Here, and everywhere in the compiler.
  JConstructor createFactoryConstructor(
    JClass enclosingClass,
    Name name,
    ParameterStructure parameterStructure, {
    required bool isExternal,
    required bool isConst,
    required bool isFromEnvironmentConstructor,
  }) {
    return JFactoryConstructor(
      enclosingClass,
      name,
      parameterStructure,
      isExternal: isExternal,
      isConst: isConst,
      isFromEnvironmentConstructor: isFromEnvironmentConstructor,
    );
  }

  JFunction createGetter(
    JLibrary library,
    JClass? enclosingClass,
    Name name,
    AsyncMarker asyncMarker, {
    required bool isStatic,
    required bool isExternal,
    required bool isAbstract,
  }) {
    return JGetter(
      library,
      enclosingClass,
      name,
      asyncMarker,
      isStatic: isStatic,
      isExternal: isExternal,
      isAbstract: isAbstract,
    );
  }

  JFunction createMethod(
    JLibrary library,
    JClass? enclosingClass,
    Name name,
    ParameterStructure parameterStructure,
    AsyncMarker asyncMarker, {
    required bool isStatic,
    required bool isExternal,
    required bool isAbstract,
  }) {
    return JMethod(
      library,
      enclosingClass,
      name,
      parameterStructure,
      asyncMarker,
      isStatic: isStatic,
      isExternal: isExternal,
      isAbstract: isAbstract,
    );
  }

  JFunction createSetter(
    JLibrary library,
    JClass? enclosingClass,
    Name name, {
    required bool isStatic,
    required bool isExternal,
    required bool isAbstract,
  }) {
    return JSetter(
      library,
      enclosingClass,
      name,
      isStatic: isStatic,
      isExternal: isExternal,
      isAbstract: isAbstract,
    );
  }

  JField createField(
    JLibrary library,
    JClass? enclosingClass,
    Name name, {
    required bool isStatic,
    required bool isAssignable,
    required bool isConst,
  }) {
    return JField(
      library,
      enclosingClass,
      name,
      isStatic: isStatic,
      isAssignable: isAssignable,
      isConst: isConst,
    );
  }

  final Map<ConstantValue, Uri> _symbolLibraries = {};

  @override
  void registerSymbolLibrary(ConstantValue value, Uri libraryUri) {
    _symbolLibraries[value] = libraryUri;
  }

  @override
  Uri? getSymbolLibraryUri(ConstantValue value) {
    return _symbolLibraries[value];
  }
}

class KernelElementEnvironment extends ElementEnvironment
    implements KElementEnvironment {
  @override
  final KernelToElementMap elementMap;

  KernelElementEnvironment(this.elementMap);

  @override
  DartType get dynamicType => elementMap.types.dynamicType();

  @override
  LibraryEntity? get mainLibrary => elementMap._mainLibrary;

  @override
  FunctionEntity? get mainFunction => elementMap._mainFunction;

  @override
  Iterable<LibraryEntity> get libraries => elementMap.libraryListInternal;

  @override
  String getLibraryName(LibraryEntity library) {
    return elementMap._getLibraryName(library as JLibrary);
  }

  @override
  InterfaceType getThisType(ClassEntity cls) {
    return elementMap.getThisType(cls as JClass);
  }

  @override
  InterfaceType getJsInteropType(ClassEntity cls) {
    return elementMap._getJsInteropType(cls as JClass)!;
  }

  @override
  InterfaceType getRawType(ClassEntity cls) {
    return elementMap._getRawType(cls as JClass);
  }

  @override
  InterfaceType getClassInstantiationToBounds(ClassEntity cls) =>
      elementMap._getClassInstantiationToBounds(cls as JClass);

  @override
  bool isGenericClass(ClassEntity cls) {
    return getThisType(cls).typeArguments.isNotEmpty;
  }

  @override
  bool isMixinApplication(ClassEntity cls) {
    return elementMap._isMixinApplication(cls as JClass);
  }

  @override
  bool isUnnamedMixinApplication(ClassEntity cls) {
    return elementMap._isUnnamedMixinApplication(cls as JClass);
  }

  @override
  DartType getTypeVariableBound(TypeVariableEntity typeVariable) {
    if (typeVariable is JLocalTypeVariable) return typeVariable.bound;
    return elementMap.getTypeVariableBound(typeVariable as JTypeVariable);
  }

  @override
  List<Variance> getTypeVariableVariances(ClassEntity cls) {
    return elementMap.getTypeVariableVariances(cls as JClass);
  }

  @override
  InterfaceType createInterfaceType(
    ClassEntity cls,
    List<DartType> typeArguments,
  ) {
    return elementMap.types.interfaceType(cls, typeArguments);
  }

  @override
  FunctionType getFunctionType(FunctionEntity function) {
    return elementMap._getFunctionType(function as JFunction);
  }

  @override
  List<TypeVariableType> getFunctionTypeVariables(FunctionEntity function) {
    return elementMap._getFunctionTypeVariables(function as JFunction);
  }

  @override
  DartType getFieldType(FieldEntity field) {
    return elementMap._getFieldType(field as JField);
  }

  @override
  FunctionType getLocalFunctionType(covariant JLocalFunction function) {
    return function.functionType;
  }

  @override
  ConstructorEntity? lookupConstructor(
    ClassEntity cls,
    String name, {
    bool required = false,
  }) {
    ConstructorEntity? constructor = elementMap.lookupConstructor(
      cls as JClass,
      name,
    );
    if (constructor == null && required) {
      throw failedAt(
        currentElementSpannable,
        "The constructor '$name' was not found in class '${cls.name}' "
        "in library ${cls.library.canonicalUri}.",
      );
    }
    return constructor;
  }

  @override
  MemberEntity? lookupLocalClassMember(
    ClassEntity cls,
    Name name, {
    bool required = false,
  }) {
    MemberEntity? member = elementMap.lookupClassMember(cls as JClass, name);
    if (member == null && required) {
      throw failedAt(
        currentElementSpannable,
        "The member '$name' was not found in ${cls.name}.",
      );
    }
    return member;
  }

  @override
  ClassEntity? getSuperClass(
    ClassEntity cls, {
    bool skipUnnamedMixinApplications = false,
  }) {
    ClassEntity? superclass = elementMap.getSuperType(cls as JClass)?.element;
    if (skipUnnamedMixinApplications) {
      while (superclass != null &&
          elementMap._isUnnamedMixinApplication(superclass as JClass)) {
        superclass = elementMap.getSuperType(superclass)?.element;
      }
    }
    return superclass;
  }

  @override
  void forEachSupertype(
    ClassEntity cls,
    void Function(InterfaceType supertype) f,
  ) {
    elementMap._forEachSupertype(cls as JClass, f);
  }

  @override
  void forEachMixin(ClassEntity cls, void Function(ClassEntity mixin) f) {
    elementMap._forEachMixin(cls as JClass, f);
  }

  @override
  void forEachLocalClassMember(
    ClassEntity cls,
    void Function(MemberEntity member) f,
  ) {
    elementMap._forEachLocalClassMember(cls as JClass, f);
  }

  @override
  void forEachClassMember(
    ClassEntity cls,
    void Function(ClassEntity declarer, MemberEntity member) f,
  ) {
    elementMap._forEachClassMember(cls as JClass, f);
  }

  @override
  void forEachConstructor(
    ClassEntity cls,
    void Function(ConstructorEntity constructor) f,
  ) {
    elementMap._forEachConstructor(cls as JClass, f);
  }

  @override
  void forEachLibraryMember(
    LibraryEntity library,
    void Function(MemberEntity member) f,
  ) {
    elementMap._forEachLibraryMember(library as JLibrary, f);
  }

  @override
  MemberEntity? lookupLibraryMember(
    LibraryEntity library,
    String name, {
    bool setter = false,
    bool required = false,
  }) {
    MemberEntity? member = elementMap.lookupLibraryMember(
      library as JLibrary,
      name,
      setter: setter,
    );
    if (member == null && required) {
      failedAt(
        currentElementSpannable,
        "The member '$name' was not found in library '${library.name}'.",
      );
    }
    return member;
  }

  @override
  ClassEntity? lookupClass(
    LibraryEntity library,
    String name, {
    bool required = false,
  }) {
    ClassEntity? cls = elementMap.lookupClass(library as JLibrary, name);
    if (cls == null && required) {
      failedAt(
        currentElementSpannable,
        "The class '$name'  was not found in library '${library.name}'.",
      );
    }
    return cls;
  }

  @override
  void forEachClass(LibraryEntity library, void Function(ClassEntity cls) f) {
    elementMap._forEachClass(library as JLibrary, f);
  }

  @override
  LibraryEntity? lookupLibrary(Uri uri, {bool required = false}) {
    LibraryEntity? library = elementMap.lookupLibrary(uri);
    if (library == null && required) {
      failedAt(currentElementSpannable, "The library '$uri' was not found.");
    }
    return library;
  }

  @override
  Iterable<ImportEntity> getImports(covariant JLibrary library) {
    KLibraryData libraryData = elementMap.libraries.getData(library);
    return libraryData.getImports(elementMap);
  }

  @override
  Iterable<ConstantValue> getMemberMetadata(
    covariant JMember member, {
    bool includeParameterMetadata = false,
  }) {
    // TODO(redemption): Support includeParameterMetadata.
    KMemberData memberData = elementMap.members.getData(member);
    return memberData.getMetadata(elementMap);
  }

  @override
  bool isEnumClass(ClassEntity cls) {
    KClassData classData = elementMap.classes.getData(cls as JClass);
    return classData.isEnumClass;
  }

  @override
  ClassEntity? getEffectiveMixinClass(ClassEntity cls) {
    if (!isMixinApplication(cls)) return null;
    do {
      cls = elementMap.getAppliedMixin(cls as JClass)!;
    } while (isMixinApplication(cls));
    return cls;
  }

  @override
  bool isLateBackingField(covariant JField field) {
    KFieldData fieldData = elementMap.members.getData(field) as KFieldData;
    return fieldData.isLateBackingField;
  }

  @override
  bool isLateFinalBackingField(covariant JField field) {
    KFieldData fieldData = elementMap.members.getData(field) as KFieldData;
    return fieldData.isLateFinalBackingField;
  }
}

class KernelNativeMemberResolver {
  static final RegExp _identifier = RegExp(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$');

  final KernelToElementMap _elementMap;
  final NativeBasicData _nativeBasicData;
  final NativeDataBuilder? _nativeDataBuilder;

  KernelNativeMemberResolver(
    this._elementMap,
    this._nativeBasicData,
    this._nativeDataBuilder,
  );

  /// Computes whether [node] is native or JsInterop.
  void resolveNativeMember(ir.Member node, IrAnnotationData annotationData) {
    bool isJsInterop = _isJsInteropMember(node);
    if (node is ir.Procedure || node is ir.Constructor) {
      FunctionEntity method = _elementMap.getMember(node) as FunctionEntity;
      bool isNative = _processMethodAnnotations(node, annotationData);
      if (isNative || isJsInterop) {
        NativeBehavior behavior = _computeNativeMethodBehavior(
          method as JFunction,
          annotationData,
          isJsInterop: isJsInterop,
        );
        _nativeDataBuilder!.setNativeMethodBehavior(method, behavior);
      }
    } else if (node is ir.Field) {
      FieldEntity field = _elementMap.getMember(node) as FieldEntity;
      bool isNative = _processFieldAnnotations(node, annotationData);
      if (isNative || isJsInterop) {
        NativeBehavior fieldLoadBehavior = _computeNativeFieldLoadBehavior(
          field as JField,
          annotationData,
          isJsInterop: isJsInterop,
        );
        NativeBehavior fieldStoreBehavior = _computeNativeFieldStoreBehavior(
          field,
        );
        _nativeDataBuilder!
          ..setNativeFieldLoadBehavior(field, fieldLoadBehavior)
          ..setNativeFieldStoreBehavior(field, fieldStoreBehavior);
      }
    }
  }

  /// Process the potentially native [field]. Adds information from metadata
  /// attributes. Returns `true` of [method] is native.
  bool _processFieldAnnotations(
    ir.Field node,
    IrAnnotationData annotationData,
  ) {
    if (node.isInstanceMember &&
        _nativeBasicData.isNativeClass(
          _elementMap.getClass(node.enclosingClass!),
        )) {
      // Exclude non-instance (static) fields - they are not really native and
      // are compiled as isolate globals.  Access of a property of a constructor
      // function or a non-method property in the prototype chain, must be coded
      // using a JS-call.
      _setNativeName(node, annotationData);
      return true;
    } else {
      String? name = _findJsNameFromAnnotation(node, annotationData);
      if (name != null) {
        failedAt(
          computeSourceSpanFromTreeNode(node),
          '@JSName(...) annotation is not supported for static fields: '
          '$node.',
        );
      }
    }
    return false;
  }

  /// Process the potentially native [method]. Adds information from metadata
  /// attributes. Returns `true` of [method] is native.
  bool _processMethodAnnotations(
    ir.Member node,
    IrAnnotationData annotationData,
  ) {
    if (_isNativeMethod(node, annotationData)) {
      if (node.enclosingClass != null && !node.isInstanceMember) {
        if (!_nativeBasicData.isNativeClass(
          _elementMap.getClass(node.enclosingClass!),
        )) {
          _elementMap.reporter.reportErrorMessage(
            computeSourceSpanFromTreeNode(node),
            MessageKind.nativeNonInstanceInNonNativeClass,
          );
          return false;
        }
        _setNativeNameForStaticMethod(node, annotationData);
      } else {
        _setNativeName(node, annotationData);
      }
      return true;
    }
    return false;
  }

  /// Sets the native name of [element], either from an annotation, or
  /// defaulting to the Dart name.
  void _setNativeName(ir.Member node, IrAnnotationData annotationData) {
    String? name = _findJsNameFromAnnotation(node, annotationData);
    name ??= node.name.text;
    _nativeDataBuilder!.setNativeMemberName(_elementMap.getMember(node), name);
  }

  /// Sets the native name of the static native method [element], using the
  /// following rules:
  /// 1. If [element] has a @JSName annotation that is an identifier, qualify
  ///    that identifier to the @Native name of the enclosing class
  /// 2. If [element] has a @JSName annotation that is not an identifier,
  ///    use the declared @JSName as the expression
  /// 3. If [element] does not have a @JSName annotation, qualify the name of
  ///    the method with the @Native name of the enclosing class.
  void _setNativeNameForStaticMethod(
    ir.Member node,
    IrAnnotationData annotationData,
  ) {
    String? name = _findJsNameFromAnnotation(node, annotationData);
    name ??= node.name.text;
    if (_isIdentifier(name)) {
      ClassEntity cls = _elementMap.getClass(node.enclosingClass!);
      List<String> nativeNames = _nativeBasicData.getNativeTagsOfClass(cls);
      if (nativeNames.length != 1) {
        failedAt(
          computeSourceSpanFromTreeNode(node),
          'Unable to determine a native name for the enclosing class, '
          'options: $nativeNames',
        );
      }
      _nativeDataBuilder!.setNativeMemberName(
        _elementMap.getMember(node),
        '${nativeNames[0]}.$name',
      );
    } else {
      _nativeDataBuilder!.setNativeMemberName(
        _elementMap.getMember(node),
        name,
      );
    }
  }

  bool _isIdentifier(String s) => _identifier.hasMatch(s);

  /// Returns the JSName annotation string or `null` if no JSName annotation is
  /// present.
  String? _findJsNameFromAnnotation(
    ir.Member node,
    IrAnnotationData annotationData,
  ) {
    return annotationData.getNativeMemberName(node);
  }

  NativeBehavior _computeNativeFieldStoreBehavior(covariant JField field) {
    ir.Field node = _elementMap.getMemberNode(field) as ir.Field;
    return _elementMap.getNativeBehaviorForFieldStore(node);
  }

  NativeBehavior _computeNativeFieldLoadBehavior(
    JField field,
    IrAnnotationData annotationData, {
    required bool isJsInterop,
  }) {
    ir.Field node = _elementMap.getMemberNode(field) as ir.Field;
    Iterable<String> createsAnnotations = annotationData.getCreatesAnnotations(
      node,
    );
    Iterable<String> returnsAnnotations = annotationData.getReturnsAnnotations(
      node,
    );
    return _elementMap.getNativeBehaviorForFieldLoad(
      node,
      createsAnnotations,
      returnsAnnotations,
      isJsInterop: isJsInterop,
    );
  }

  NativeBehavior _computeNativeMethodBehavior(
    JFunction function,
    IrAnnotationData annotationData, {
    required bool isJsInterop,
  }) {
    ir.Member node = _elementMap.getMemberNode(function);
    Iterable<String> createsAnnotations = annotationData.getCreatesAnnotations(
      node,
    );
    Iterable<String> returnsAnnotations = annotationData.getReturnsAnnotations(
      node,
    );
    return _elementMap.getNativeBehaviorForMethod(
      node,
      createsAnnotations,
      returnsAnnotations,
      isJsInterop: isJsInterop,
    );
  }

  bool _isNativeMethod(ir.Member node, IrAnnotationData annotationData) {
    if (!maybeEnableNative(node.enclosingLibrary.importUri)) return false;
    bool hasNativeBody = annotationData.hasNativeBody(node);
    // TODO(rileyporter): Move this check on non-native external usage to
    // js_interop_checks when `native` and `external` can be disambiguated.
    if (!hasNativeBody &&
        node.isExternal &&
        !_nativeBasicData.isJsInteropMember(_elementMap.getMember(node)) &&
        !(node is ir.Procedure && node.hasExternalEffectPragma)) {
      // TODO(johnniwinther): Should we change dart:html and friends to use
      //  `external` instead of the native body syntax?
      _elementMap.reporter.reportErrorMessage(
        computeSourceSpanFromTreeNode(node),
        MessageKind.nonNativeExternal,
      );
    }
    return hasNativeBody;
  }

  bool _isJsInteropMember(ir.Member node) {
    return _nativeBasicData.isJsInteropMember(_elementMap.getMember(node));
  }
}

ForeignKind getForeignKindFromName(String name) {
  switch (name) {
    case Identifiers.js:
      return ForeignKind.js;
    case Identifiers.jsBuiltin:
      return ForeignKind.jsBuiltin;
    case Identifiers.jsEmbeddedGlobal:
      return ForeignKind.jsEmbeddedGlobal;
    case Identifiers.jsInterceptorConstant:
      return ForeignKind.jsInterceptorConstant;
    default:
      return ForeignKind.none;
  }
}
