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

part of world_builder;

/// [ResolutionEnqueuerWorldBuilder] based on the [Element] model.
class ElementResolutionWorldBuilder extends ResolutionWorldBuilderBase {
  /// Used for testing the new more precise computation of instantiated types
  /// and classes.
  static bool useInstantiationMap = false;

  final Resolution _resolution;

  ElementResolutionWorldBuilder(
      JavaScriptBackend backend,
      this._resolution,
      NativeBasicData nativeBasicData,
      NativeDataBuilder nativeDataBuilder,
      InterceptorDataBuilder interceptorDataBuilder,
      BackendUsageBuilder backendUsageBuilder,
      RuntimeTypesNeedBuilder rtiNeedBuilder,
      NativeResolutionEnqueuer nativeResolutionEnqueuer,
      NoSuchMethodRegistry noSuchMethodRegistry,
      SelectorConstraintsStrategy selectorConstraintsStrategy,
      ClassHierarchyBuilder classHierarchyBuilder,
      ClassQueries classQueries)
      : super(
            backend.compiler.options,
            _resolution.elementEnvironment,
            _resolution.types,
            _resolution.commonElements,
            backend.constantSystem,
            nativeBasicData,
            nativeDataBuilder,
            interceptorDataBuilder,
            backendUsageBuilder,
            rtiNeedBuilder,
            nativeResolutionEnqueuer,
            noSuchMethodRegistry,
            selectorConstraintsStrategy,
            classHierarchyBuilder,
            classQueries);

  bool isImplemented(ClassElement cls) {
    return super.isImplemented(cls.declaration);
  }

  void registerTypeInstantiation(
      InterfaceType type, ClassUsedCallback classUsed,
      {ConstructorEntity constructor,
      bool byMirrors: false,
      bool isRedirection: false}) {
    ClassElement cls = type.element;
    cls.ensureResolved(_resolution);
    super.registerTypeInstantiation(type, classUsed,
        constructor: constructor,
        byMirrors: byMirrors,
        isRedirection: isRedirection);
  }

  /// Returns the instantiation map used for computing the closed world.
  ///
  /// If [useInstantiationMap] is `true`, redirections are removed and
  /// redirecting factories are converted to their effective target and type.
  Map<ClassEntity, InstantiationInfo> getInstantiationMap() {
    if (!useInstantiationMap) return _instantiationInfo;

    Map<ClassEntity, InstantiationInfo> instantiationMap =
        <ClassEntity, InstantiationInfo>{};

    InstantiationInfo infoFor(ClassEntity cls) {
      return instantiationMap.putIfAbsent(cls, () => new InstantiationInfo());
    }

    _instantiationInfo.forEach((cls, info) {
      if (info.instantiationMap != null) {
        info.instantiationMap.forEach((_constructor, Set<Instance> set) {
          ConstructorElement constructor = _constructor;
          for (Instance instance in set) {
            if (instance.isRedirection) {
              continue;
            }
            if (constructor == null || !constructor.isRedirectingFactory) {
              infoFor(cls)
                  .addInstantiation(constructor, instance.type, instance.kind);
            } else {
              ConstructorElement target = constructor.effectiveTarget;
              ResolutionDartType targetType =
                  constructor.computeEffectiveTargetType(instance.type);
              ClassElement cls = target.enclosingClass;
              bool isNative = _nativeBasicData.isNativeClass(cls);
              Instantiation kind;
              if (isNative) {
                kind = Instantiation.ABSTRACTLY_INSTANTIATED;
              } else if (cls.isAbstract) {
                kind = Instantiation.UNINSTANTIATED;
              } else {
                kind = Instantiation.DIRECTLY_INSTANTIATED;
              }
              if (targetType is ResolutionInterfaceType) {
                infoFor(targetType.element)
                    .addInstantiation(target, targetType, kind);
              }
            }
          }
        });
      }
    });
    return instantiationMap;
  }

  void registerIsCheck(ResolutionDartType type) {
    type.computeUnaliased(_resolution);
    type = type.unaliased;
    // Even in checked mode, type annotations for return type and argument
    // types do not imply type checks, so there should never be a check
    // against the type variable of a typedef.
    assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef);
    super.registerIsCheck(type);
  }

  void registerStaticUse(StaticUse staticUse, MemberUsedCallback memberUsed) {
    Element element = staticUse.element;
    assert(element.isDeclaration,
        failedAt(element, "Element ${element} is not the declaration."));
    super.registerStaticUse(staticUse, memberUsed);
  }

  _ClassUsage _createClassUsage(ClassElement cls) {
    cls.ensureResolved(_resolution);
    _resolution.ensureClassMembers(cls);
    return super._createClassUsage(cls);
  }

  void _processInstantiatedClassMember(
      ClassEntity cls, MemberElement member, MemberUsedCallback memberUsed) {
    assert(member.isDeclaration, failedAt(member));
    member.computeType(_resolution);
    super._processInstantiatedClassMember(cls, member, memberUsed);
  }

  ClosedWorld closeWorld() {
    Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses =
        populateHierarchyNodes();
    _closed = true;

    return _closedWorldCache = new ClosedWorldImpl(
        options: _options,
        elementEnvironment: _elementEnvironment,
        dartTypes: _dartTypes,
        commonElements: _commonElements,
        constantSystem: _constantSystem,
        nativeData: _nativeDataBuilder.close(),
        interceptorData: _interceptorDataBuilder.close(),
        backendUsage: _backendUsageBuilder.close(),
        noSuchMethodData: _noSuchMethodRegistry.close(),
        resolutionWorldBuilder: this,
        rtiNeedBuilder: _rtiNeedBuilder,
        implementedClasses: _implementedClasses,
        liveNativeClasses: _nativeResolutionEnqueuer.liveNativeClasses,
        liveInstanceMembers: _liveInstanceMembers,
        assignedInstanceMembers: computeAssignedInstanceMembers(),
        processedMembers: _processedMembers,
        allTypedefs: _allTypedefs,
        mixinUses: classHierarchyBuilder.mixinUses,
        typesImplementedBySubclasses: typesImplementedBySubclasses,
        classHierarchyNodes: classHierarchyBuilder.classHierarchyNodes,
        classSets: classHierarchyBuilder.classSets);
  }

  @override
  void forEachLocalFunction(void f(MemberEntity member, Local localFunction)) {
    for (LocalFunctionElement local in localFunctions) {
      f(local.memberContext, local);
    }
  }
}
