// Copyright (c) 2025, 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:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/library_index.dart';
import 'package:vm/metadata/direct_call.dart' show DirectCallMetadata;
import 'package:vm/metadata/procedure_attributes.dart';
import 'package:vm/metadata/table_selector.dart';
import 'package:vm/transformations/devirtualization.dart';
import 'package:vm/transformations/dynamic_interface_annotator.dart'
    as dynamic_interface_annotator;
import 'package:vm/transformations/pragma.dart';
import 'package:vm/transformations/type_flow/table_selector_assigner.dart';
import 'package:wasm_builder/wasm_builder.dart' as w;

import 'class_info.dart';
import 'code_generator.dart';
import 'compiler_options.dart';
import 'constants.dart' show maxArrayNewFixedLength;
import 'dispatch_table.dart';
import 'dynamic_module_kernel_metadata.dart';
import 'intrinsics.dart' show MemberIntrinsic;
import 'kernel_nodes.dart';
import 'modules.dart';
import 'param_info.dart';
import 'record_class_generator.dart' show dynamicModulesRecordsLibraryUri;
import 'reference_extensions.dart';
import 'target.dart';
import 'translator.dart';
import 'types.dart' show InstanceConstantInterfaceType;
import 'util.dart';

// Pragmas used to annotate the kernel during main module compilation.
const String _mainModLibPragma = 'wasm:mainMod';
const String _submoduleEntryPointName = '\$invokeEntryPoint';

enum DynamicModuleType {
  main,
  submodule;

  static DynamicModuleType parse(String s) => switch (s) {
        "main" => main,
        "submodule" => submodule,
        _ => throw ArgumentError("Unrecognized dynamic module type $s."),
      };
}

extension DynamicSubmoduleComponent on Component {
  static final Expando<Procedure> _submoduleEntryPoint = Expando<Procedure>();

  Procedure? get dynamicSubmoduleEntryPoint => _submoduleEntryPoint[this];
  List<Library> getDynamicSubmoduleLibraries(CoreTypes coreTypes) =>
      [...libraries.where((l) => !l.isFromMainModule(coreTypes))];
}

extension DynamicModuleLibrary on Library {
  bool isFromMainModule(CoreTypes coreTypes) =>
      hasPragma(coreTypes, this, _mainModLibPragma);
}

extension DynamicModuleClass on Class {
  bool isDynamicSubmoduleExtendable(CoreTypes coreTypes) =>
      hasPragma(coreTypes, this, kDynModuleExtendablePragmaName) ||
      hasPragma(coreTypes, this, kDynModuleImplicitlyExtendablePragmaName);
}

extension DynamicModuleMember on Member {
  bool isDynamicSubmoduleCallable(CoreTypes coreTypes) =>
      hasPragma(coreTypes, this, kDynModuleCallablePragmaName) ||
      hasPragma(coreTypes, this, kDynModuleImplicitlyCallablePragmaName);

  bool isDynamicSubmoduleCallableNoTearOff(CoreTypes coreTypes) =>
      getPragma(coreTypes, this, kDynModuleCallablePragmaName,
          defaultValue: '') ==
      'call';

  bool isDynamicSubmoduleOverridable(CoreTypes coreTypes) =>
      hasPragma(coreTypes, this, kDynModuleCanBeOverriddenPragmaName) ||
      hasPragma(coreTypes, this, kDynModuleCanBeOverriddenImplicitlyPragmaName);
}

class DynamicSubmoduleOutputData extends ModuleOutputData {
  final CoreTypes coreTypes;
  final ModuleOutput _submodule;
  DynamicSubmoduleOutputData(this.coreTypes, super.modules, super.importMap)
      : _submodule = modules[1];

  @override
  ModuleOutput moduleForReference(Reference reference) {
    // Rather than create tear-offs for all dynamic callable methods in the main
    // module, we create them as needed in the submodules.
    if (reference.isTearOffReference) return _submodule;

    return super.moduleForReference(reference);
  }
}

class DynamicMainModuleStrategy extends ModuleStrategy with KernelNodes {
  @override
  final Component component;
  @override
  final CoreTypes coreTypes;
  @override
  final LibraryIndex index;
  final Uri dynamicInterfaceSpecificationBaseUri;
  final String dynamicInterfaceSpecification;

  DynamicMainModuleStrategy(
      this.component,
      this.coreTypes,
      this.dynamicInterfaceSpecification,
      this.dynamicInterfaceSpecificationBaseUri)
      : index = coreTypes.index;

  @override
  void prepareComponent() {
    // Annotate the kernel with info from dynamic interface.
    dynamic_interface_annotator.annotateComponent(dynamicInterfaceSpecification,
        dynamicInterfaceSpecificationBaseUri, component, coreTypes);
    _addImplicitPragmas();

    for (final lib in component.libraries) {
      lib.annotations = [...lib.annotations];
      addPragma(lib, _mainModLibPragma, coreTypes);
    }

    component.addMetadataRepository(DynamicModuleConstantRepository());
    component.addMetadataRepository(DynamicModuleGlobalIdRepository());
  }

  @override
  ModuleOutputData buildModuleOutputData() {
    final builder = ModuleOutputBuilder();
    final mainModule = builder.buildModule();
    mainModule.libraries.addAll(component.libraries);
    final placeholderModule = builder.buildModule(skipEmit: true);
    return ModuleOutputData([mainModule, placeholderModule], const {});
  }

  void _addImplicitPragmas() {
    final pragmasAdded = <(Member, String)>{};

    void add(Member member, String pragma) {
      if (pragmasAdded.add((member, pragma))) {
        addPragma(member, pragma, coreTypes);
      }
    }

    // These members don't have normal bodies and should therefore not be
    // considered directly callable from submodules.
    final Set<Member> excludedIntrinsics = {
      coreTypes.index.getProcedure("dart:_wasm", "WasmFunction", "get:call"),
      coreTypes.index.getConstructor("dart:_boxed_int", "BoxedInt", "_"),
      coreTypes.index.getConstructor("dart:_boxed_double", "BoxedDouble", "_"),
    };

    void checkMemberEntryPoint(Member member) {
      if (excludedIntrinsics.contains(member)) return;
      // Entrypoints are all dynamically callable and vice versa.
      final isEntryPoint = getPragma(
              coreTypes, member, kWasmEntryPointPragmaName,
              defaultValue: '') !=
          null;
      final isSubmoduleCallable = member.isDynamicSubmoduleCallable(coreTypes);

      if (isEntryPoint && !isSubmoduleCallable) {
        add(member, kDynModuleCallablePragmaName);
      }
    }

    for (final library in component.libraries) {
      for (final member in library.members) {
        checkMemberEntryPoint(member);
      }
      for (final cls in library.classes) {
        for (final member in cls.members) {
          checkMemberEntryPoint(member);
        }
      }
    }

    // Add implicit pragmas

    // Object has some inherent properties even though it is not explicitly
    // annotated.
    addPragma(coreTypes.objectClass, kDynModuleExtendablePragmaName, coreTypes);
    for (final procedure in coreTypes.objectClass.procedures) {
      add(procedure, kDynModuleCanBeOverriddenPragmaName);
      add(procedure, kDynModuleCallablePragmaName);
    }

    // Mark all record classes as dynamic module extendable.
    addPragma(coreTypes.recordClass, kDynModuleExtendablePragmaName, coreTypes);

    // SystemHash.combine used by closures.
    add(systemHashCombine, kDynModuleCallablePragmaName);
  }
}

class DynamicSubmoduleStrategy extends ModuleStrategy {
  final Component component;
  final WasmCompilerOptions options;
  final WasmTarget kernelTarget;
  final Uri mainModuleComponentUri;
  final CoreTypes coreTypes;

  DynamicSubmoduleStrategy(this.component, this.options, this.kernelTarget,
      this.coreTypes, this.mainModuleComponentUri);

  @override
  void prepareComponent() {
    final submoduleEntryPoint = _findSubmoduleEntryPoint(component, coreTypes);
    addWasmEntryPointPragma(submoduleEntryPoint, coreTypes);
    DynamicSubmoduleComponent._submoduleEntryPoint[component] =
        submoduleEntryPoint;

    _registerLibraries();
    _prepareWasmEntryPoint(submoduleEntryPoint);
    _addTfaMetadata();
  }

  void _prepareWasmEntryPoint(Procedure submoduleEntryPoint) {
    submoduleEntryPoint.function.returnType = const DynamicType();

    // Export the entry point so that the JS runtime can get the function and
    // pass it to the main module.
    addPragma(submoduleEntryPoint, 'wasm:export', coreTypes,
        value: StringConstant(_submoduleEntryPointName));
  }

  void _registerLibraries() {
    // Register each library with the SDK. This will ensure no duplicate
    // libraries are included across dynamic modules.
    final registerLibraryUris = coreTypes.index
        .getTopLevelProcedure('dart:_internal', 'registerLibraryUris');
    final entryPoint = component.dynamicSubmoduleEntryPoint!;
    final libraryUris = ListLiteral([
      ...component
          .getDynamicSubmoduleLibraries(coreTypes)
          .where((l) => '${l.importUri}' != dynamicModulesRecordsLibraryUri)
          .map((l) => StringLiteral(l.importUri.toString()))
    ], typeArgument: coreTypes.stringNonNullableRawType);
    entryPoint.function.body = Block([
      ExpressionStatement(
          StaticInvocation(registerLibraryUris, Arguments([libraryUris]))),
      entryPoint.function.body!,
    ])
      ..parent = entryPoint.function;
  }

  static Procedure _findSubmoduleEntryPoint(
      Component component, CoreTypes coreTypes) {
    for (final library in component.libraries) {
      for (final procedure in library.procedures) {
        final entryPointPragma = getPragma(
                coreTypes, procedure, kDynModuleEntryPointPragmaName,
                defaultValue: true) ??
            false;
        if (entryPointPragma) {
          return procedure;
        }
      }
    }
    throw StateError('Entry point not found for dynamic submodule.');
  }

  void _addTfaMetadata() {
    component.metadata[dynamicMainModuleProcedureAttributeMetadataTag] =
        component
            .metadata[ProcedureAttributesMetadataRepository.repositoryTag]!;
    component.metadata[dynamicMainModuleSelectorMetadataTag] =
        component.metadata[TableSelectorMetadataRepository.repositoryTag]!;

    final selectorAssigner = TableSelectorAssigner(component);
    for (final selector in selectorAssigner.metadata.selectors) {
      selector.callCount++;
      selector.tornOff = true;
      selector.calledOnNull = true;
    }

    final selectorMetadataRepository = TableSelectorMetadataRepository();
    component.metadata[TableSelectorMetadataRepository.repositoryTag] =
        selectorMetadataRepository;
    selectorMetadataRepository.mapping[component] = selectorAssigner.metadata;

    final dynamicModuleProcedureAttributes =
        ProcedureAttributesMetadataRepository();
    for (final library in component.libraries) {
      for (final cls in library.classes) {
        for (final member in cls.members) {
          if (!member.isInstanceMember) continue;
          dynamicModuleProcedureAttributes.mapping[member] =
              ProcedureAttributesMetadata(
                  getterSelectorId: selectorAssigner.getterSelectorId(member),
                  methodOrSetterSelectorId:
                      selectorAssigner.methodOrSetterSelectorId(member));
        }
      }
    }
    component.metadata[ProcedureAttributesMetadataRepository.repositoryTag] =
        dynamicModuleProcedureAttributes;

    final classHierarchy =
        ClassHierarchy(component, coreTypes) as ClosedWorldClassHierarchy;

    component.accept(_Devirtualization(coreTypes, component, classHierarchy,
        classHierarchy.computeSubtypesInformation()));
  }

  @override
  ModuleOutputData buildModuleOutputData() {
    final moduleBuilder = ModuleOutputBuilder();
    final mainModule = moduleBuilder.buildModule(skipEmit: true);
    final submodule = moduleBuilder.buildModule(emitAsMain: true);
    for (final library in component.libraries) {
      final module = hasPragma(coreTypes, library, _mainModLibPragma)
          ? mainModule
          : submodule;
      module.libraries.add(library);
    }

    return DynamicSubmoduleOutputData(
        coreTypes, [mainModule, submodule], const {});
  }
}

void _recordIdMain(w.FunctionBuilder f, Translator translator) {
  final ranges = translator.classIdNumbering
      .getConcreteClassIdRangeForMainModule(translator.coreTypes.recordClass);

  final ib = f.body;
  ib.local_get(ib.locals[0]);
  ib.emitClassIdRangeCheck(ranges);
  ib.end();
}

void _recordIdSubmodule(w.FunctionBuilder f, Translator translator) {
  final ranges = translator.classIdNumbering
      .getConcreteClassIdRangeForDynamicSubmodule(
          translator.coreTypes.recordClass);

  final ib = f.body;
  if (ranges.isEmpty) {
    ib.i32_const(0);
  } else {
    ib.local_get(ib.locals[0]);
    translator.callReference(translator.localizeClassId.reference, ib);
    ib.emitClassIdRangeCheck(ranges);
  }
  ib.end();
}

w.FunctionType _recordIdBuildType(Translator translator) {
  return translator.typesBuilder
      .defineFunction(const [w.NumType.i32], const [w.NumType.i32]);
}

enum BuiltinUpdatableFunctions {
  recordId(_recordIdMain, _recordIdSubmodule, _recordIdBuildType);

  final void Function(w.FunctionBuilder, Translator) _buildMain;
  final void Function(w.FunctionBuilder, Translator) _buildSubmodule;
  final w.FunctionType Function(Translator) _buildType;

  const BuiltinUpdatableFunctions(
      this._buildMain, this._buildSubmodule, this._buildType);
}

class DynamicModuleInfo {
  final Translator translator;
  Procedure? get submoduleEntryPoint =>
      translator.component.dynamicSubmoduleEntryPoint;
  bool get isSubmodule => submoduleEntryPoint != null;
  late final w.FunctionBuilder initFunction;
  late final MainModuleMetadata metadata;

  late final w.Global moduleIdGlobal;

  // null is used to indicate that skipDynamic was passed for this key.
  final Map<int, w.BaseFunction?> overridableFunctions = {};

  final Map<ClassInfo, Map<w.ModuleBuilder, w.BaseFunction>>
      _constantCacheCheckers = {};
  final Map<w.StorageType, Map<w.ModuleBuilder, w.BaseFunction>>
      _mutableArrayConstantCacheCheckers = {};
  final Map<w.StorageType, Map<w.ModuleBuilder, w.BaseFunction>>
      _immutableArrayConstantCacheCheckers = {};

  late final w.ModuleBuilder submodule =
      translator.modules.firstWhere((m) => m != translator.mainModule);

  DynamicModuleInfo(this.translator, this.metadata);

  void initSubmodule() {
    submodule.functions.start = initFunction = submodule.functions.define(
        translator.typesBuilder.defineFunction(const [], const []), "#init");

    // Make sure the exception tag is exported from the main module.
    translator.getExceptionTag(submodule);

    if (isSubmodule) {
      _initSubmoduleId();
      _initModuleRtt();
    } else {
      _initializeSubmoduleAllocatableClasses();
      _initializeCallableReferences();
    }

    _initializeOverridableReferences();
  }

  void _initModuleRtt() {
    final b = initFunction.body;
    translator.pushModuleId(b);
    final moduleRtt = translator.types.rtt.getModuleRtt(isMainModule: false);
    translator.constants.instantiateConstant(
        b, moduleRtt, translator.translateType(moduleRtt.interfaceType));
    translator.callReference(translator.registerModuleRtt.reference, b);
    b.drop();
  }

  void _initSubmoduleId() {
    final global = moduleIdGlobal = submodule.globals
        .define(w.GlobalType(w.NumType.i64, mutable: true), '#_moduleId');
    global.initializer
      ..i64_const(0)
      ..end();

    final b = initFunction.body;

    final rangeSize = translator.classIdNumbering.maxDynamicSubmoduleClassId! -
        translator.classIdNumbering.firstDynamicSubmoduleClassId +
        1;

    b.i32_const(rangeSize);
    translator.callReference(translator.registerModuleClassRange.reference, b);
    b.global_set(moduleIdGlobal);
  }

  bool _isClassSubmoduleInstantiable(Class cls) {
    return cls.isDynamicSubmoduleExtendable(translator.coreTypes) ||
        cls.constructors
            .any((e) => e.isDynamicSubmoduleCallable(translator.coreTypes)) ||
        cls.procedures.any((e) =>
            e.isFactory && e.isDynamicSubmoduleCallable(translator.coreTypes));
  }

  void _initializeCallableReferences() {
    for (final lib in translator.component.libraries) {
      for (final member in lib.members) {
        if (!member.isDynamicSubmoduleCallable(translator.coreTypes)) continue;
        _forEachMemberReference(member, _registerStaticCallableTarget);
      }
    }

    for (final classInfo in translator.classesSupersFirst) {
      final cls = classInfo.cls;
      if (cls == null) continue;

      // Register any callable functions defined within this class.
      for (final member in cls.members) {
        if (!member.isDynamicSubmoduleCallable(translator.coreTypes)) continue;

        if (!member.isInstanceMember) {
          // Generate static members immediately since they are unconditionally
          // callable.
          _forEachMemberReference(member, _registerStaticCallableTarget);
          continue;
        }

        // Consider callable references invoked and therefore if they're
        // overridable include them in the runtime dispatch table.
        if (member.isDynamicSubmoduleOverridable(translator.coreTypes)) {
          _forEachMemberReference(
              member, metadata.invokedOverridableReferences.add);
        }
      }

      // Anonymous mixins' targets don't need to be registered since they aren't
      // directly allocatable.
      if (cls.isAnonymousMixin) continue;

      if (cls.isAbstract && !_isClassSubmoduleInstantiable(cls)) {
        continue;
      }

      // For each dispatch target, register the member as callable from this
      // class.
      final targets = translator.hierarchy.getDispatchTargets(cls).followedBy(
          translator.hierarchy.getDispatchTargets(cls, setters: true));
      for (final member in targets) {
        if (!member.isDynamicSubmoduleCallable(translator.coreTypes)) continue;

        _forEachMemberReference(member,
            (reference) => _registerCallableDispatchTarget(reference, cls));
      }
    }
  }

  /// If class [cls] is marked allocated then ensure we compile [target].
  ///
  /// The [cls] may be marked allocated in
  /// [_initializeSubmoduleAllocatableClasses] which (together with this) will
  /// enqueue the [target] for compilation. Otherwise the [cls] must be
  /// allocated via a constructor call in the program itself.
  void _registerCallableDispatchTarget(Reference target, Class cls) {
    final member = target.asMember;

    if (member.isExternal) {
      final isGeneratedIntrinsic = member is Procedure &&
          MemberIntrinsic.fromProcedure(translator.coreTypes, member) != null;
      if (!isGeneratedIntrinsic) return;
    }

    final classId =
        (translator.classInfo[cls]!.classId as AbsoluteClassId).value;

    metadata.callableReferenceIds[target] ??=
        metadata.callableReferenceIds.length;
    // The class must be allocated in order for the target to be live.
    translator.functions.recordClassTargetUse(classId, target);
  }

  void _registerStaticCallableTarget(Reference target) {
    final member = target.asMember;

    if (member.isExternal) {
      final isGeneratedIntrinsic = member is Procedure &&
          MemberIntrinsic.fromProcedure(translator.coreTypes, member) != null;
      if (!isGeneratedIntrinsic) return;
    }

    // Generate static members immediately since they are unconditionally
    // callable.
    metadata.callableReferenceIds[target] ??=
        metadata.callableReferenceIds.length;
    translator.functions.getFunction(target);
  }

  void _initializeSubmoduleAllocatableClasses() {
    for (final classInfo in translator.classesSupersFirst) {
      final cls = classInfo.cls;
      if (cls == null) continue;
      if (cls.isAnonymousMixin) continue;

      if (_isClassSubmoduleInstantiable(cls)) {
        translator.functions.recordClassAllocation(classInfo.classId);
      }
    }
  }

  void _initializeOverridableReferences() {
    for (final builtin in BuiltinUpdatableFunctions.values) {
      _createUpdateableFunction(builtin.index, builtin._buildType(translator),
          buildMain: (f) => builtin._buildMain(f, translator),
          buildSubmodule: (f) => builtin._buildSubmodule(f, translator),
          name: '#r_${builtin.name}');
    }

    for (final reference in metadata.invokedOverridableReferences) {
      final selector = translator.dispatchTable.selectorForTarget(reference);
      translator.functions.recordSelectorUse(selector, false);

      final mainSelector = (translator.dynamicMainModuleDispatchTable ??
              translator.dispatchTable)
          .selectorForTarget(reference);
      final signature = _getGeneralizedSignature(mainSelector);
      final buildMain = buildSelectorBranch(reference, mainSelector);
      final buildSubmodule = buildSelectorBranch(reference, mainSelector);

      _createUpdateableFunction(
          mainSelector.id + BuiltinUpdatableFunctions.values.length, signature,
          buildMain: buildMain,
          buildSubmodule: buildSubmodule,
          name: '#s${mainSelector.id}_${mainSelector.name}');
    }
  }

  void _forEachMemberReference(Member member, void Function(Reference) f) {
    void passReference(Reference reference) {
      final checkedReference =
          translator.getFunctionEntry(reference, uncheckedEntry: false);
      f(checkedReference);

      final uncheckedReference =
          translator.getFunctionEntry(reference, uncheckedEntry: true);
      if (uncheckedReference != checkedReference) {
        f(uncheckedReference);
      }
    }

    if (member is Procedure) {
      passReference(member.reference);
      // We ignore the tear-off and let each submodule generate it for itself.
    } else if (member is Field) {
      passReference(member.getterReference);
      if (member.hasSetter) {
        passReference(member.setterReference!);
      }
    } else if (member is Constructor &&
        // Skip types that don't extend Object in the wasm type hierarchy.
        // These types do not have directly invokable constructors.
        translator.classInfo[member.enclosingClass]!.struct
            .isSubtypeOf(translator.objectInfo.struct)) {
      if (!member.enclosingClass.isAnonymousMixin) {
        passReference(member.reference);
      }
      passReference(member.initializerReference);
      passReference(member.constructorBodyReference);
    }
  }

  void finishDynamicModule() {
    _registerModuleRefs(
        isSubmodule ? initFunction.body : translator.initFunction.body);

    initFunction.body.end();
  }

  void _registerModuleRefs(w.InstructionsBuilder b) {
    final numKeys = overridableFunctions.length;
    assert(numKeys < maxArrayNewFixedLength);
    final orderedFunctions = ([...overridableFunctions.entries]
          ..sort((a, b) => a.key.compareTo(b.key)))
        .map((e) => e.value);

    for (final function in orderedFunctions) {
      if (function != null) {
        b.ref_func(function);
      } else {
        b.ref_null(w.HeapType.func);
      }
    }
    b.array_new_fixed(
        translator.wasmArrayType(w.RefType.func(nullable: true), ''), numKeys);
    translator.callReference(
        translator.registerUpdateableFuncRefs.reference, b);
    b.drop();
  }

  int _createUpdateableFunction(int key, w.FunctionType type,
      {required void Function(w.FunctionBuilder function) buildMain,
      required void Function(w.FunctionBuilder function) buildSubmodule,
      bool skipSubmodule = false,
      required String name}) {
    final mapKey = key;
    final index = metadata.keyInvocationToIndex[mapKey] ??=
        metadata.keyInvocationToIndex.length;
    overridableFunctions.putIfAbsent(index, () {
      if (!isSubmodule) {
        final mainFunction = translator.mainModule.functions.define(type, name);
        translator.mainModule.functions.declare(mainFunction);
        buildMain(mainFunction);
        return mainFunction;
      }

      if (skipSubmodule) return null;

      final submoduleFunction = submodule.functions.define(type, name);
      submodule.functions.declare(submoduleFunction);
      buildSubmodule(submoduleFunction);
      return submoduleFunction;
    });

    return index;
  }

  void _callClassIdBranch(
      int key, w.InstructionsBuilder b, w.FunctionType signature,
      {required void Function(w.FunctionBuilder b) buildMainMatch,
      required void Function(w.FunctionBuilder b) buildSubmoduleMatch,
      bool skipSubmodule = false,
      required String name}) {
    // No new types declared in the submodule so the branch would always miss.
    final canSkipSubmoduleBranch = skipSubmodule ||
        translator.classIdNumbering.maxDynamicSubmoduleClassId ==
            translator.classIdNumbering.maxClassId;
    final callIndex = _createUpdateableFunction(key, signature,
        buildMain: buildMainMatch,
        buildSubmodule: buildSubmoduleMatch,
        skipSubmodule: canSkipSubmoduleBranch,
        name: name);

    translator.callReference(translator.classIdToModuleId.reference, b);
    b.i64_const(callIndex);

    // getUpdateableFuncRef allows for null entries since a submodule may not
    // implement every key. However, only keys that cannot be queried should be
    // unimplemented so it's safe to cast to a non-nullable function here.
    translator.callReference(translator.getUpdateableFuncRef.reference, b);
    translator.convertType(b, w.RefType.func(nullable: true),
        w.RefType(signature, nullable: false));
    b.call_ref(signature);
  }

  void callClassIdBranchBuiltIn(
      BuiltinUpdatableFunctions key, w.InstructionsBuilder b,
      {bool skipSubmodule = false}) {
    _callClassIdBranch(key.index, b, key._buildType(translator),
        buildMainMatch: (f) => key._buildMain(f, translator),
        buildSubmoduleMatch: (f) => key._buildSubmodule(f, translator),
        name: '#r_${key.name}',
        skipSubmodule: skipSubmodule);
  }

  w.FunctionType _getGeneralizedSignature(SelectorInfo mainSelector) {
    final signature = mainSelector.signature;

    // The shared entry point to this selector has to use 'any' because the
    // selector's signature may change between compilations.
    final generalizedSignature = translator.typesBuilder.defineFunction([
      ...signature.inputs.map((e) => const w.RefType.any(nullable: true)),
      w.NumType.i32,
      w.NumType.i32
    ], [
      ...signature.outputs.map((e) => const w.RefType.any(nullable: true))
    ]);
    return generalizedSignature;
  }

  void Function(w.FunctionBuilder) buildSelectorBranch(
      Reference interfaceTarget, SelectorInfo mainSelector) {
    return (w.FunctionBuilder function) {
      final localSelector =
          translator.dispatchTable.selectorForTarget(interfaceTarget);
      final ib = function.body;

      final uncheckedTargets = localSelector.targets(unchecked: true);
      final checkedTargets = localSelector.targets(unchecked: false);

      // Whether we use checked+unchecked (or normal) we'll have the same
      // class-id ranges - only the actual target `Reference` may be a unchecked
      // or checked one.
      assert(uncheckedTargets.targetRanges.length ==
          checkedTargets.targetRanges.length);

      // NOTE: Keep this in sync with
      // `code_generator.dart:AstCodeGenerator._virtualCall`.
      final bool noTarget = checkedTargets.targetRanges.isEmpty;
      final bool directCall = checkedTargets.targetRanges.length == 1;
      final callPolymorphicDispatcher =
          !directCall && checkedTargets.staticDispatchRanges.isNotEmpty;
      // disabled for dyn overridable selectors atm
      assert(!callPolymorphicDispatcher);

      if (noTarget) {
        ib.comment('No targets in local module for ${localSelector.name}');
        ib.unreachable();
        ib.end();
        return;
      }

      final w.FunctionType localSignature;
      final ParameterInfo localParamInfo;
      if (directCall) {
        final target = checkedTargets.targetRanges.single.target;
        localSignature = translator.signatureForDirectCall(target);
        localParamInfo = translator.paramInfoForDirectCall(target);
      } else {
        localSignature = localSelector.signature;
        localParamInfo = localSelector.paramInfo;
      }

      final generalizedMainSignature = _getGeneralizedSignature(mainSelector);
      final mainParamInfo = mainSelector.paramInfo;

      assert(mainParamInfo.takesContextOrReceiver ==
          localParamInfo.takesContextOrReceiver);

      int localsIndex = 0;
      final takesContextOrReceiver = localParamInfo.takesContextOrReceiver;
      if (takesContextOrReceiver) {
        ib.local_get(ib.locals[localsIndex]);
        translator.convertType(ib, generalizedMainSignature.inputs[localsIndex],
            localSignature.inputs[localsIndex]);
        localsIndex++;
      }

      final mainTypeParamCount = mainParamInfo.typeParamCount;
      assert(mainTypeParamCount == localParamInfo.typeParamCount);
      for (int i = 0; i < mainTypeParamCount; i++, localsIndex++) {
        ib.local_get(ib.locals[localsIndex]);
        translator.convertType(ib, generalizedMainSignature.inputs[localsIndex],
            localSignature.inputs[localsIndex]);
      }

      final localPositionalCount = localParamInfo.positional.length;
      final mainPositionalCount = mainParamInfo.positional.length;
      assert(localPositionalCount >= mainPositionalCount);

      for (int i = 0; i < localPositionalCount; i++, localsIndex++) {
        if (i < mainPositionalCount) {
          ib.local_get(ib.locals[localsIndex]);
          translator.convertType(
              ib,
              generalizedMainSignature.inputs[localsIndex],
              localSignature.inputs[localsIndex]);
          continue;
        }
        final constant = localParamInfo.positional[i]!;
        translator.constants.instantiateConstant(
            ib, constant, localSignature.inputs[localsIndex]);
      }

      final localNamedCount = localParamInfo.named.length;
      final mainNamedCount = mainParamInfo.named.length;
      assert(localNamedCount >= mainNamedCount);

      for (int i = 0; i < localNamedCount; i++, localsIndex++) {
        final name = localParamInfo.names[i];
        final mainIndex = mainParamInfo.nameIndex[name];
        if (mainIndex != null) {
          final mainLocalIndex =
              (takesContextOrReceiver ? 1 : 0) + mainTypeParamCount + mainIndex;
          ib.local_get(ib.locals[mainLocalIndex]);
          translator.convertType(
              ib,
              generalizedMainSignature.inputs[mainLocalIndex],
              localSignature.inputs[localsIndex]);
          continue;
        }
        final constant = localParamInfo.named[name]!;
        translator.constants.instantiateConstant(
            ib, constant, localSignature.inputs[localsIndex]);
      }

      if (directCall) {
        if (!localSelector.useMultipleEntryPoints) {
          final target = checkedTargets.targetRanges.single.target;
          ib.invoke(translator.directCallTarget(target));
        } else {
          final uncheckedTarget = uncheckedTargets.targetRanges.single.target;
          final checkedTarget = checkedTargets.targetRanges.single.target;
          // Check if the invocation is checked or unchecked and use the
          // appropriate offset.
          ib.local_get(ib.locals[function.type.inputs.length - 1]);
          ib.if_(localSignature.inputs, localSignature.outputs);
          ib.invoke(translator.directCallTarget(uncheckedTarget));
          ib.else_();
          ib.invoke(translator.directCallTarget(checkedTarget));
          ib.end();
        }
      } else {
        ib.local_get(ib.locals[function.type.inputs.length - 2]);
        if (isSubmodule) {
          translator.callReference(translator.scopeClassId.reference, ib);
        }

        ib.comment('Local dispatch table call to "${localSelector.name}"');
        final uncheckedOffset = uncheckedTargets.offset;
        final checkedOffset = checkedTargets.offset;
        if (!localSelector.useMultipleEntryPoints) {
          if (checkedOffset != 0) {
            ib.i32_const(checkedOffset!);
            ib.i32_add();
          }
        } else if (checkedOffset != 0 || uncheckedOffset != 0) {
          // Check if the invocation is checked or unchecked and use the
          // appropriate offset.
          ib.local_get(ib.locals[function.type.inputs.length - 1]);
          ib.if_(const [], const [w.NumType.i32]);
          if (uncheckedOffset != null) {
            ib.i32_const(uncheckedOffset);
          } else {
            ib.unreachable();
          }
          ib.else_();
          if (checkedOffset != null) {
            ib.i32_const(checkedOffset);
          } else {
            ib.unreachable();
          }
          ib.end();
          ib.i32_add();
        }
        final table = translator.dispatchTable.getWasmTable(ib.module);
        ib.call_indirect(localSignature, table);
      }
      translator.convertType(ib, localSignature.outputs.single,
          generalizedMainSignature.outputs.single);
      ib.end();
    };
  }

  void callOverridableDispatch(
      w.InstructionsBuilder b, SelectorInfo selector, Reference interfaceTarget,
      {required bool useUncheckedEntry}) {
    metadata.invokedOverridableReferences.add(interfaceTarget);

    final localSignature = selector.signature;
    // If any input is not a RefType (i.e. it's an unboxed value) then wrap it
    // so the updated signature works.
    if (localSignature.inputs.any((i) => i is! w.RefType)) {
      final receiverLocal = b.addLocal(translator.topTypeNonNullable);
      b.local_set(receiverLocal);
      final locals = <w.Local>[];
      for (final input in localSignature.inputs.reversed) {
        final local = b.addLocal(input);
        locals.add(local);
        b.local_set(local);
      }
      for (final local in locals.reversed) {
        b.local_get(local);
        translator.convertType(b, local.type, w.RefType.any(nullable: true));
      }
      b.local_get(receiverLocal);
    }

    final idLocal = b.addLocal(w.NumType.i32);
    b.loadClassId(translator, translator.topTypeNonNullable);
    b.local_tee(idLocal);
    b.i32_const(useUncheckedEntry ? 1 : 0);
    b.local_get(idLocal);

    final mainDispatchTable =
        translator.dynamicMainModuleDispatchTable ?? translator.dispatchTable;
    final mainModuleSelector =
        mainDispatchTable.selectorForTarget(interfaceTarget);
    final generalizedSignature = _getGeneralizedSignature(mainModuleSelector);

    // For consistency, always use the main module selector ID when generating
    // the key.
    final key = mainModuleSelector.id + BuiltinUpdatableFunctions.values.length;
    _callClassIdBranch(key, b, generalizedSignature,
        name: '#s${mainModuleSelector.id}_${mainModuleSelector.name}',
        buildMainMatch:
            buildSelectorBranch(interfaceTarget, mainModuleSelector),
        buildSubmoduleMatch:
            buildSelectorBranch(interfaceTarget, mainModuleSelector),
        skipSubmodule: selector.targets(unchecked: false).targetRanges.isEmpty);
    translator.convertType(
        b, generalizedSignature.outputs.single, localSignature.outputs.single);
  }
}

/// Emits code to canonicalize the provided constant value at runtime.
///
/// This canonicalizer works by generating custom equality functions for any
/// type of constant it encounters. The SDK maintains an array of canonicalized
/// objects separated by type and the equality function generated here is used
/// to identify the canonical version of a constant.
///
/// For example, for a normal Dart Object of type T, we will first construct a
/// new instance of T. Then we will fetch an array containing all instances of T
/// already canonicalized. Using an equality function which does a pairwise
/// comparison of T's fields, we will walk the array looking for an instance
/// that matches the new T. If there is one we return the canonical version,
/// otherwise we add it to the array and return the new T.
///
/// Iterables, wasm arrays and wasm builtin types all require special
/// canonicalization logic.
///
/// Only classes defined in the main module require canonicalization because
/// these are the only classes that can have identical constants instantiated in
/// different submodules. A class defined in a submodule cannot be accessed from
/// a different submodule.
class ConstantCanonicalizer extends ConstantVisitor<void> {
  final Translator translator;
  final w.InstructionsBuilder b;

  /// A local containing the value to be canonicalized.
  final w.Local valueLocal;

  ConstantCanonicalizer(this.translator, this.b, this.valueLocal);

  late final _checkerType = translator.typesBuilder.defineFunction([
    translator.topTypeNonNullable,
    translator.topTypeNonNullable,
  ], const [
    w.NumType.i32
  ]);

  late final _arrayCheckerType = translator.typesBuilder.defineFunction(const [
    w.RefType.array(nullable: false),
    w.RefType.array(nullable: false),
  ], const [
    w.NumType.i32
  ]);

  /// Wasm builtin value types that don't need canonicalization.
  late final Set<Class> _wasmValueClasses = {
    translator.wasmI32Class,
    translator.wasmI64Class,
    translator.wasmF32Class,
    translator.wasmF64Class,
    translator.wasmI16Class,
    translator.wasmI8Class,
    translator.wasmAnyRefClass,
    translator.wasmExternRefClass,
    translator.wasmI31RefClass,
    translator.wasmFuncRefClass,
    translator.wasmEqRefClass,
    translator.wasmStructRefClass,
    translator.wasmArrayRefClass,
  };

  /// Boxed values are comparable by the value they wrap.
  late final Set<Class> _boxedClasses = {
    translator.boxedIntClass,
    translator.boxedDoubleClass,
    translator.boxedBoolClass,
  };

  /// Values of these types are canonicalized by their == function.
  late final Set<Class> _equalsCheckerClasses = {
    translator.jsStringClass,
    translator.symbolClass,
    translator.closureClass,
  };

  /// These iterable classes contain lazily initialized data that should not be
  /// considered in comparisons.
  late final Set<Class> _hashingIterableConstClasses = {
    translator.immutableSetClass,
    translator.immutableMapClass,
  };

  /// Emit code that canonicalizes the instance of [cls] stored in [valueLocal].
  void _canonicalizeInstance(Class cls) {
    final classId = translator.classInfo[cls]!.classId;
    if (classId is RelativeClassId) {
      // This class is not defined in the main module so it doesn't need runtime
      // canonicalization.
      return;
    }
    if (_wasmValueClasses.contains(cls)) {
      // Wasm value types do not need canonicalization.
      return;
    }

    // Lookup the WasmCache for the value's type.
    b.local_set(valueLocal);
    b.i64_const((classId as AbsoluteClassId).value);
    translator.callReference(translator.constCacheGetter.reference, b);

    // Get the equality checker for the class. Import it into the submodule and
    // use the import if this is in a submodule.
    w.BaseFunction checker = _getCanonicalChecker(cls, b.module);

    // Declare the function so it can be used as a ref_func in a constant
    // context.
    b.module.functions.declare(checker);

    // Invoke the 'canonicalize' function with the value and checker.
    b.local_get(valueLocal);
    b.ref_func(checker);
    final valueType = translator.callReference(
        translator.constCacheCanonicalize.reference, b);

    // The canonicalizer returns an Object which may be a boxed value. Unbox it
    // if necessary.
    translator.convertType(b, valueType.single, valueLocal.type);
  }

  void _canonicalizeArray(bool mutable, DartType elementType) {
    b.local_set(valueLocal);

    final cacheField = (mutable
        ? translator.wasmArrayConstCache
        : translator.immutableWasmArrayConstCache)[elementType];

    if (cacheField == null) {
      throw StateError(
          'Unrecognized const array type (mutable: $mutable): $elementType');
    }

    translator.callReference(cacheField.getterReference, b);

    // Get the equality checker for the class. Import it into the submodule and
    // use the import if this is in a submodule.
    w.BaseFunction checker = _getCanonicalArrayChecker(
        translator.translateStorageType(elementType), mutable, b.module);

    // Declare the function so it can be used as a ref_func in a constant
    // context.
    b.module.functions.declare(checker);

    // Invoke the canonicalizer function with the value and checker.
    b.local_get(valueLocal);
    b.ref_func(checker);
    final valueType = translator.callReference(
        translator.constCacheArrayCanonicalize.reference, b);

    // The canonicalizer returns an array ref, cast it to the correct array
    // type.
    translator.convertType(b, valueType.single, valueLocal.type);
  }

  /// Get a function that will compare two instances of [cls] and return true if
  /// they canonicalize to the same value.
  w.BaseFunction _getCanonicalChecker(Class cls, w.ModuleBuilder module) {
    ClassInfo info = translator.classInfo[cls]!;

    // We create a checker for each class to ensure we check each struct field.
    return translator.dynamicModuleInfo!._constantCacheCheckers
        .putIfAbsent(info, () => {})
        .putIfAbsent(module, () {
      final checker =
          module.functions.define(_checkerType, '${info.cls} constCheck');

      final b = checker.body;
      _checkerForClass(b, info);
      b.end();
      return checker;
    });
  }

  /// Get a function that will compare two arrays with elements of type
  /// [elementType] and return true if they canonicalize to the same value.
  w.BaseFunction _getCanonicalArrayChecker(
      w.StorageType elementType, bool mutable, w.ModuleBuilder module) {
    final cache = mutable
        ? translator.dynamicModuleInfo!._mutableArrayConstantCacheCheckers
        : translator.dynamicModuleInfo!._immutableArrayConstantCacheCheckers;

    // We create a checker for each array element type.
    return cache.putIfAbsent(elementType, () => {}).putIfAbsent(module, () {
      final name = '$elementType';
      final checker = module.functions.define(_arrayCheckerType,
          '$name const${mutable ? '' : 'Immutable'}ArrayCheck');

      final arrayType =
          translator.wasmArrayType(elementType, name, mutable: mutable);
      final b = checker.body;
      _checkerForArray(b, arrayType, elementType);
      b.end();
      return checker;
    });
  }

  void _checkerForClass(w.InstructionsBuilder b, ClassInfo classInfo) {
    final cls = classInfo.cls!;

    if (_boxedClasses.contains(cls)) {
      return _checkerForBoxedClasses(b, classInfo);
    }

    final structRef = classInfo.nonNullableType;
    b.local_get(b.locals[0]);
    b.ref_cast(structRef);
    b.local_get(b.locals[1]);
    b.ref_cast(structRef);

    if (_equalsCheckerClasses.contains(cls)) {
      _checkerWithEquals(b);
    } else if (_hashingIterableConstClasses.contains(cls)) {
      _defaultChecker(b, classInfo, fieldsToInclude: {
        FieldIndex.hashBaseData,
        ...cls.typeParameters.map((t) => translator.typeParameterIndex[t]!)
      });
    } else {
      _defaultChecker(b, classInfo);
    }
  }

  /// Compare boxed entites via the values they wrap.
  void _checkerForBoxedClasses(w.InstructionsBuilder b, ClassInfo classInfo) {
    final structRef = classInfo.nonNullableType;
    b.local_get(b.locals[0]);
    b.ref_cast(structRef);
    b.struct_get(classInfo.struct, FieldIndex.boxValue);

    b.local_get(b.locals[1]);
    b.ref_cast(structRef);
    b.struct_get(classInfo.struct, FieldIndex.boxValue);

    return _equalsForValueType(
        b, translator.builtinTypes[classInfo.cls] as w.ValueType);
  }

  /// Compare values using a dispatch call to Object.==
  void _checkerWithEquals(w.InstructionsBuilder b) {
    b.local_get(b.locals[0]);
    final selector = translator.dispatchTable
        .selectorForTarget(translator.coreTypes.objectEquals.reference);
    translator.callDispatchTable(b, selector,
        interfaceTarget: translator.coreTypes.objectEquals.reference,
        useUncheckedEntry: true);
    translator.convertType(
        b, selector.signature.outputs.first, _checkerType.outputs.first);
  }

  /// Compare two normal class instances whose const identity are determined by
  /// their fields. Do a shallow comparison of the fields assuming the field
  /// values are already canonicalized.
  void _defaultChecker(w.InstructionsBuilder b, ClassInfo classInfo,
      {Set<int>? fieldsToInclude}) {
    final structType = classInfo.struct;
    final structRefType = classInfo.nonNullableType;
    final castedLocal1 = b.addLocal(structRefType);
    final castedLocal2 = b.addLocal(structRefType);
    b.local_set(castedLocal2);
    b.local_set(castedLocal1);
    final falseBlock = b.block();
    classInfo.forEachClassFieldIndex((index, fieldType) {
      if (fieldsToInclude != null && !fieldsToInclude.contains(index)) {
        return;
      }
      b.local_get(castedLocal1);
      b.struct_get(structType, index);

      b.local_get(castedLocal2);
      b.struct_get(structType, index);

      final fieldTypeUnpacked = fieldType.type;
      _equalsForValueType(b, fieldTypeUnpacked);
      b.i32_eqz();
      b.br_if(falseBlock);
    });
    b.i32_const(1);
    b.return_();
    b.end();
    b.i32_const(0);
  }

  /// Compare two arrays for equality by iterating through the elements and
  /// doing a shallow pairwise comparison. Array elements will already be
  /// canonicalized. Assumes the types and lengths of the arrays are already
  /// equivalent.
  void _checkerForArray(w.InstructionsBuilder b, w.ArrayType arrayType,
      w.StorageType elementType) {
    final arrayRefType = w.RefType(arrayType, nullable: false);
    final array1 = b.addLocal(arrayRefType);
    final array2 = b.addLocal(arrayRefType);
    final falseBlock = b.block();
    b.local_get(b.locals[0]);
    b.ref_cast(arrayRefType);
    b.local_set(array1);
    b.local_get(b.locals[1]);
    b.ref_cast(arrayRefType);
    b.local_set(array2);

    b.incrementingLoop(
        pushStart: () => b.i32_const(0),
        pushLimit: () {
          b.local_get(array1);
          b.array_len();
        },
        genBody: (loopLocal) {
          b.local_get(array1);
          b.local_get(loopLocal);
          if (elementType is w.PackedType) {
            b.array_get_u(arrayType);
          } else {
            b.array_get(arrayType);
          }
          b.local_get(array2);
          b.local_get(loopLocal);
          if (elementType is w.PackedType) {
            b.array_get_u(arrayType);
          } else {
            b.array_get(arrayType);
          }
          _equalsForValueType(b, elementType);
          b.i32_eqz();
          b.br_if(falseBlock);
        });
    b.i32_const(1);
    b.return_();
    b.end();
    b.i32_const(0);
  }

  /// Invokes the builtin equality function for [storageType].
  static void _equalsForValueType(
      w.InstructionsBuilder b, w.StorageType storageType) {
    if (storageType is w.RefType) {
      b.ref_eq();
    } else if (storageType == w.PackedType.i8 ||
        storageType == w.PackedType.i16) {
      b.i32_eq();
    } else if (storageType == w.NumType.f32) {
      b.f32_eq();
    } else if (storageType == w.NumType.f64) {
      b.f64_eq();
    } else if (storageType == w.NumType.i32) {
      b.i32_eq();
    } else if (storageType == w.NumType.i64) {
      b.i64_eq();
    } else {
      throw UnsupportedError('Could not find eq for $storageType');
    }
  }

  @override
  Never visitAuxiliaryConstant(AuxiliaryConstant node) {
    throw UnsupportedError('Cannot canonicalize auxiliary constants.');
  }

  @override
  void visitBoolConstant(BoolConstant node) {
    _canonicalizeInstance(translator.boxedBoolClass);
  }

  @override
  void visitConstructorTearOffConstant(ConstructorTearOffConstant node) {
    _canonicalizeInstance(translator.closureClass);
  }

  @override
  void visitDoubleConstant(DoubleConstant node) {
    _canonicalizeInstance(translator.boxedDoubleClass);
  }

  @override
  void visitInstanceConstant(InstanceConstant node) {
    if (node.classNode == translator.wasmArrayClass) {
      final dartElementType = node.typeArguments.single;
      _canonicalizeArray(true, dartElementType);
    } else if (node.classNode == translator.immutableWasmArrayClass) {
      final dartElementType = node.typeArguments.single;
      _canonicalizeArray(false, dartElementType);
    } else {
      _canonicalizeInstance(node.classNode);
    }
  }

  @override
  void visitInstantiationConstant(InstantiationConstant node) {
    _canonicalizeInstance(translator.closureClass);
  }

  @override
  void visitIntConstant(IntConstant node) {
    _canonicalizeInstance(translator.boxedIntClass);
  }

  @override
  void visitListConstant(ListConstant node) {
    _canonicalizeInstance(translator.immutableListClass);
  }

  @override
  void visitMapConstant(MapConstant node) {
    _canonicalizeInstance(translator.immutableMapClass);
  }

  @override
  void visitNullConstant(NullConstant node) {}

  @override
  void visitRecordConstant(RecordConstant node) {
    _canonicalizeInstance(translator.coreTypes.recordClass);
  }

  @override
  void visitRedirectingFactoryTearOffConstant(
      RedirectingFactoryTearOffConstant node) {
    _canonicalizeInstance(translator.closureClass);
  }

  @override
  void visitSetConstant(SetConstant node) {
    _canonicalizeInstance(translator.immutableSetClass);
  }

  @override
  void visitStaticTearOffConstant(StaticTearOffConstant node) {
    _canonicalizeInstance(translator.closureClass);
  }

  @override
  void visitStringConstant(StringConstant node) {
    _canonicalizeInstance(translator.jsStringClass);
  }

  @override
  void visitSymbolConstant(SymbolConstant node) {
    return _canonicalizeInstance(translator.symbolClass);
  }

  @override
  void visitTypeLiteralConstant(TypeLiteralConstant node) {
    _canonicalizeInstance(translator.typeClass);
  }

  @override
  Never visitTypedefTearOffConstant(TypedefTearOffConstant node) {
    throw UnsupportedError('Cannot canonicalize typedef tearoff constants.');
  }

  @override
  Never visitUnevaluatedConstant(UnevaluatedConstant node) {
    throw UnsupportedError('Cannot canonicalize unevaluated constants.');
  }
}

/// Populates [DirectCallMetadata] for a visited component.
class _Devirtualization extends CHADevirtualization {
  final CoreTypes coreTypes;

  _Devirtualization(
      this.coreTypes,
      Component component,
      ClosedWorldClassHierarchy hierarchy,
      ClassHierarchySubtypes hierarchySubtype)
      : super(coreTypes, component, hierarchy, hierarchySubtype);

  @override
  void makeDirectCall(
      TreeNode node, Member? target, DirectCallMetadata directCall) {
    if (target != null && target.isDynamicSubmoduleOverridable(coreTypes)) {
      return;
    }
    super.makeDirectCall(node, target, directCall);
  }
}
