// Copyright (c) 2014, 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.

library dart2js.js_emitter.type_test_registry;

import '../common.dart';
import '../common_elements.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
import '../js_backend/runtime_types.dart'
    show
        RuntimeTypesChecks,
        RuntimeTypesChecksBuilder,
        RuntimeTypesSubstitutions,
        TypeChecks;
import '../js_backend/mirrors_data.dart';
import '../universe/world_builder.dart';
import '../world.dart' show ClosedWorld;

class TypeTestRegistry {
  final ElementEnvironment _elementEnvironment;

  /**
   * Raw ClassElement symbols occurring in is-checks and type assertions.  If the
   * program contains parameterized checks `x is Set<int>` and
   * `x is Set<String>` then the ClassElement `Set` will occur once in
   * [checkedClasses].
   */
  Set<ClassEntity> checkedClasses;

  /**
   * The set of function types that checked, both explicitly through tests of
   * typedefs and implicitly through type annotations in checked mode.
   */
  Set<FunctionType> checkedFunctionTypes;

  /// After [computeNeededClasses] this set only contains classes that are only
  /// used for RTI.
  Set<ClassEntity> _rtiNeededClasses;

  Iterable<ClassEntity> cachedClassesUsingTypeVariableTests;

  Iterable<ClassEntity> get classesUsingTypeVariableTests {
    if (cachedClassesUsingTypeVariableTests == null) {
      cachedClassesUsingTypeVariableTests = _codegenWorldBuilder.isChecks
          .where((DartType t) =>
              t is TypeVariableType && t.element.typeDeclaration is ClassEntity)
          .map<ClassEntity>((DartType _v) {
        TypeVariableType v = _v;
        return v.element.typeDeclaration;
      }).toList();
    }
    return cachedClassesUsingTypeVariableTests;
  }

  final CodegenWorldBuilder _codegenWorldBuilder;
  final ClosedWorld _closedWorld;

  RuntimeTypesChecks _rtiChecks;

  TypeTestRegistry(
      this._codegenWorldBuilder, this._closedWorld, this._elementEnvironment);

  RuntimeTypesChecks get rtiChecks {
    assert(
        _rtiChecks != null,
        failedAt(NO_LOCATION_SPANNABLE,
            "RuntimeTypesChecks has not been computed yet."));
    return _rtiChecks;
  }

  Iterable<ClassEntity> get rtiNeededClasses {
    assert(
        _rtiNeededClasses != null,
        failedAt(NO_LOCATION_SPANNABLE,
            "rtiNeededClasses has not been computed yet."));
    return _rtiNeededClasses;
  }

  /**
   * Returns the classes with constructors used as a 'holder' in
   * [emitRuntimeTypeSupport].
   * TODO(9556): Some cases will go away when the class objects are created as
   * complete.  Not all classes will go away while constructors are referenced
   * from type substitutions.
   */
  Set<ClassEntity> computeClassesModifiedByEmitRuntimeTypeSupport() {
    TypeChecks typeChecks = rtiChecks.requiredChecks;
    Set<ClassEntity> result = new Set<ClassEntity>();
    for (ClassEntity cls in typeChecks.classes) {
      if (typeChecks[cls].isNotEmpty) result.add(cls);
    }
    return result;
  }

  void computeRtiNeededClasses(RuntimeTypesSubstitutions rtiSubstitutions,
      MirrorsData mirrorsData, Iterable<MemberEntity> liveMembers) {
    _rtiNeededClasses = new Set<ClassEntity>();

    void addClassWithSuperclasses(ClassEntity cls) {
      _rtiNeededClasses.add(cls);
      for (ClassEntity superclass = _elementEnvironment.getSuperClass(cls);
          superclass != null;
          superclass = _elementEnvironment.getSuperClass(superclass)) {
        _rtiNeededClasses.add(superclass);
      }
    }

    void addClassesWithSuperclasses(Iterable<ClassEntity> classes) {
      for (ClassEntity cls in classes) {
        addClassWithSuperclasses(cls);
      }
    }

    // 1.  Add classes that are referenced by type arguments or substitutions in
    //     argument checks.
    // TODO(karlklose): merge this case with 2 when unifying argument and
    // object checks.
    rtiChecks
        .getRequiredArgumentClasses()
        .forEach((e) => addClassWithSuperclasses(e));

    // 2.  Add classes that are referenced by substitutions in object checks and
    //     their superclasses.
    TypeChecks requiredChecks =
        rtiSubstitutions.computeChecks(rtiNeededClasses, checkedClasses);
    Set<ClassEntity> classesUsedInSubstitutions =
        rtiSubstitutions.getClassesUsedInSubstitutions(requiredChecks);
    addClassesWithSuperclasses(classesUsedInSubstitutions);

    // 3.  Add classes that contain checked generic function types. These are
    //     needed to store the signature encoding.
    for (FunctionType type in checkedFunctionTypes) {
      ClassEntity contextClass = DartTypes.getClassContext(type);
      if (contextClass != null) {
        _rtiNeededClasses.add(contextClass);
      }
    }

    bool canTearOff(MemberEntity function) {
      if (!function.isFunction ||
          function.isConstructor ||
          function.isGetter ||
          function.isSetter) {
        return false;
      } else if (function.isInstanceMember) {
        if (!function.enclosingClass.isClosure) {
          return _codegenWorldBuilder.hasInvokedGetter(function, _closedWorld);
        }
      }
      return false;
    }

    bool canBeReflectedAsFunction(MemberEntity element) {
      return !element.isField;
    }

    bool canBeReified(MemberEntity element) {
      return (canTearOff(element) ||
          mirrorsData.isMemberAccessibleByReflection(element));
    }

    // Find all types referenced from the types of elements that can be
    // reflected on 'as functions'.
    liveMembers.where((MemberEntity element) {
      return canBeReflectedAsFunction(element) && canBeReified(element);
    }).forEach((_function) {
      FunctionEntity function = _function;
      FunctionType type = _elementEnvironment.getFunctionType(function);
      for (ClassEntity cls in _rtiChecks.getReferencedClasses(type)) {
        while (cls != null) {
          _rtiNeededClasses.add(cls);
          cls = _elementEnvironment.getSuperClass(cls);
        }
      }
    });
  }

  void computeRequiredTypeChecks(RuntimeTypesChecksBuilder rtiChecksBuilder) {
    assert(checkedClasses == null && checkedFunctionTypes == null);

    rtiChecksBuilder.registerImplicitChecks(
        _codegenWorldBuilder, classesUsingTypeVariableTests);
    _rtiChecks = rtiChecksBuilder.computeRequiredChecks(_codegenWorldBuilder);

    checkedClasses = new Set<ClassEntity>();
    checkedFunctionTypes = new Set<FunctionType>();
    _codegenWorldBuilder.isChecks.forEach((DartType t) {
      if (t is InterfaceType) {
        checkedClasses.add(t.element);
      } else if (t is FunctionType) {
        checkedFunctionTypes.add(t);
      }
    });
  }
}
