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

/// This library defines individual world impacts.
///
/// We call these building blocks `uses`. Each `use` is a single impact of the
/// world. Some example uses are:
///
///  * an invocation of a top level function
///  * a call to the `foo()` method on an unknown class.
///  * an instantiation of class T
///
/// The different compiler stages combine these uses into `WorldImpact` objects,
/// which are later used to construct a closed-world understanding of the
/// program.
library dart2js.universe.use;

import '../common.dart';
import '../constants/values.dart';
import '../elements/types.dart';
import '../elements/entities.dart';
import '../js_model/closure.dart';
import '../util/util.dart' show equalElements, Hashing;
import 'call_structure.dart' show CallStructure;
import 'selector.dart' show Selector;
import 'world_builder.dart' show StrongModeConstraint;

enum DynamicUseKind {
  INVOKE,
  GET,
  SET,
}

/// The use of a dynamic property. [selector] defined the name and kind of the
/// property and [receiverConstraint] defines the known constraint for the
/// object on which the property is accessed.
class DynamicUse {
  final Selector selector;

  DynamicUse(this.selector);

  /// Short textual representation use for testing.
  String get shortText {
    StringBuffer sb = new StringBuffer();
    if (receiverConstraint != null) {
      var constraint = receiverConstraint;
      if (constraint is StrongModeConstraint) {
        if (constraint.isThis) {
          sb.write('this:');
        } else if (constraint.isExact) {
          sb.write('exact:');
        }
        sb.write(constraint.cls.name);
      } else {
        sb.write(constraint);
      }
      sb.write('.');
    }
    sb.write(selector.name);
    if (typeArguments != null && typeArguments.isNotEmpty) {
      sb.write('<');
      sb.write(typeArguments.join(','));
      sb.write('>');
    }
    if (selector.isCall) {
      sb.write(selector.callStructure.shortText);
    } else if (selector.isSetter) {
      sb.write('=');
    }
    return sb.toString();
  }

  Object get receiverConstraint => null;

  DynamicUseKind get kind {
    if (selector.isGetter) {
      return DynamicUseKind.GET;
    } else if (selector.isSetter) {
      return DynamicUseKind.SET;
    } else {
      return DynamicUseKind.INVOKE;
    }
  }

  List<DartType> get typeArguments => const <DartType>[];

  @override
  int get hashCode => Hashing.listHash(
      typeArguments, Hashing.objectsHash(selector, receiverConstraint));

  @override
  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is! DynamicUse) return false;
    return selector == other.selector &&
        receiverConstraint == other.receiverConstraint &&
        equalElements(typeArguments, other.typeArguments);
  }

  @override
  String toString() => '$selector,$receiverConstraint';
}

class GenericDynamicUse extends DynamicUse {
  final List<DartType> _typeArguments;

  GenericDynamicUse(Selector selector, [this._typeArguments])
      : super(selector) {
    assert(
        selector.callStructure.typeArgumentCount ==
            (_typeArguments?.length ?? 0),
        "Type argument count mismatch. Selector has "
        "${selector.callStructure.typeArgumentCount} but "
        "${typeArguments?.length ?? 0} were passed.");
  }

  @override
  List<DartType> get typeArguments => _typeArguments ?? const <DartType>[];
}

/// A dynamic use with a receiver constraint.
///
/// This is used in the codegen phase where receivers are constrained to a
/// type mask or similar.
class ConstrainedDynamicUse extends DynamicUse {
  @override
  final Object receiverConstraint;
  final List<DartType> _typeArguments;

  ConstrainedDynamicUse(
      Selector selector, this.receiverConstraint, this._typeArguments)
      : super(selector) {
    assert(
        selector.callStructure.typeArgumentCount ==
            (_typeArguments?.length ?? 0),
        "Type argument count mismatch. Selector has "
        "${selector.callStructure.typeArgumentCount} but "
        "${_typeArguments?.length ?? 0} were passed.");
  }

  @override
  List<DartType> get typeArguments => _typeArguments ?? const <DartType>[];
}

enum StaticUseKind {
  STATIC_TEAR_OFF,
  SUPER_TEAR_OFF,
  SUPER_FIELD_SET,
  SUPER_GET,
  SUPER_SETTER_SET,
  SUPER_INVOKE,
  INSTANCE_FIELD_GET,
  INSTANCE_FIELD_SET,
  CLOSURE,
  CLOSURE_CALL,
  CALL_METHOD,
  CONSTRUCTOR_INVOKE,
  CONST_CONSTRUCTOR_INVOKE,
  DIRECT_INVOKE,
  INLINING,
  STATIC_INVOKE,
  STATIC_GET,
  STATIC_SET,
  FIELD_INIT,
  FIELD_CONSTANT_INIT,
}

/// Statically known use of an [Entity].
// TODO(johnniwinther): Create backend-specific implementations with better
// invariants.
class StaticUse {
  final Entity element;
  final StaticUseKind kind;
  @override
  final int hashCode;
  final InterfaceType type;
  final CallStructure callStructure;
  final ImportEntity deferredImport;
  final ConstantValue constant;

  StaticUse.internal(Entity element, this.kind,
      {this.type,
      this.callStructure,
      this.deferredImport,
      typeArgumentsHash: 0,
      this.constant})
      : this.element = element,
        this.hashCode = Hashing.listHash([
          element,
          kind,
          type,
          typeArgumentsHash,
          callStructure,
          deferredImport,
          constant
        ]);

  /// Short textual representation use for testing.
  String get shortText {
    StringBuffer sb = new StringBuffer();
    switch (kind) {
      case StaticUseKind.INSTANCE_FIELD_SET:
      case StaticUseKind.SUPER_FIELD_SET:
      case StaticUseKind.SUPER_SETTER_SET:
      case StaticUseKind.STATIC_SET:
        sb.write('set:');
        break;
      case StaticUseKind.FIELD_INIT:
        sb.write('init:');
        break;
      case StaticUseKind.CLOSURE:
        sb.write('def:');
        break;
      default:
    }
    if (element is MemberEntity) {
      MemberEntity member = element;
      if (member.enclosingClass != null) {
        sb.write(member.enclosingClass.name);
        sb.write('.');
      }
    }
    if (element.name == null) {
      sb.write('<anonymous>');
    } else {
      sb.write(element.name);
    }
    if (typeArguments != null && typeArguments.isNotEmpty) {
      sb.write('<');
      sb.write(typeArguments.join(','));
      sb.write('>');
    }
    if (callStructure != null) {
      sb.write('(');
      sb.write(callStructure.positionalArgumentCount);
      if (callStructure.namedArgumentCount > 0) {
        sb.write(',');
        sb.write(callStructure.getOrderedNamedArguments().join(','));
      }
      sb.write(')');
    }
    if (deferredImport != null) {
      sb.write('{');
      sb.write(deferredImport.name);
      sb.write('}');
    }
    if (constant != null) {
      sb.write('=');
      sb.write(constant.toStructuredText());
    }
    return sb.toString();
  }

  List<DartType> get typeArguments => null;

  /// Invocation of a static or top-level [element] with the given
  /// [callStructure].
  factory StaticUse.staticInvoke(
      FunctionEntity element, CallStructure callStructure,
      [List<DartType> typeArguments, ImportEntity deferredImport]) {
    assert(
        element.isStatic || element.isTopLevel,
        failedAt(
            element,
            "Static invoke element $element must be a top-level "
            "or static method."));
    assert(element.isFunction,
        failedAt(element, "Static get element $element must be a function."));
    assert(
        callStructure != null,
        failedAt(element,
            "Not CallStructure for static invocation of element $element."));

    return new GenericStaticUse(element, StaticUseKind.STATIC_INVOKE,
        callStructure, typeArguments, deferredImport);
  }

  /// Closurization of a static or top-level function [element].
  factory StaticUse.staticTearOff(FunctionEntity element,
      [ImportEntity deferredImport]) {
    assert(
        element.isStatic || element.isTopLevel,
        failedAt(
            element,
            "Static tear-off element $element must be a top-level "
            "or static method."));
    assert(element.isFunction,
        failedAt(element, "Static get element $element must be a function."));
    return new StaticUse.internal(element, StaticUseKind.STATIC_TEAR_OFF,
        deferredImport: deferredImport);
  }

  /// Read access of a static or top-level field or getter [element].
  factory StaticUse.staticGet(MemberEntity element,
      [ImportEntity deferredImport]) {
    assert(
        element.isStatic || element.isTopLevel,
        failedAt(
            element,
            "Static get element $element must be a top-level "
            "or static field or getter."));
    assert(
        element.isField || element.isGetter,
        failedAt(element,
            "Static get element $element must be a field or a getter."));
    return new StaticUse.internal(element, StaticUseKind.STATIC_GET,
        deferredImport: deferredImport);
  }

  /// Write access of a static or top-level field or setter [element].
  factory StaticUse.staticSet(MemberEntity element,
      [ImportEntity deferredImport]) {
    assert(
        element.isStatic || element.isTopLevel,
        failedAt(
            element,
            "Static set element $element "
            "must be a top-level or static method."));
    assert(
        (element.isField && element.isAssignable) || element.isSetter,
        failedAt(element,
            "Static set element $element must be a field or a setter."));
    return new StaticUse.internal(element, StaticUseKind.STATIC_SET,
        deferredImport: deferredImport);
  }

  /// Invocation of the lazy initializer for a static or top-level field
  /// [element].
  factory StaticUse.staticInit(FieldEntity element) {
    assert(
        element.isStatic || element.isTopLevel,
        failedAt(
            element,
            "Static init element $element must be a top-level "
            "or static method."));
    assert(element.isField,
        failedAt(element, "Static init element $element must be a field."));
    return new StaticUse.internal(element, StaticUseKind.FIELD_INIT);
  }

  /// Invocation of a super method [element] with the given [callStructure].
  factory StaticUse.superInvoke(
      FunctionEntity element, CallStructure callStructure,
      [List<DartType> typeArguments]) {
    assert(
        element.isInstanceMember,
        failedAt(element,
            "Super invoke element $element must be an instance method."));
    assert(
        callStructure != null,
        failedAt(element,
            "Not CallStructure for super invocation of element $element."));
    return new GenericStaticUse(
        element, StaticUseKind.SUPER_INVOKE, callStructure, typeArguments);
  }

  /// Read access of a super field or getter [element].
  factory StaticUse.superGet(MemberEntity element) {
    assert(
        element.isInstanceMember,
        failedAt(
            element, "Super get element $element must be an instance method."));
    assert(
        element.isField || element.isGetter,
        failedAt(element,
            "Super get element $element must be a field or a getter."));
    return new StaticUse.internal(element, StaticUseKind.SUPER_GET);
  }

  /// Write access of a super field [element].
  factory StaticUse.superFieldSet(FieldEntity element) {
    assert(
        element.isInstanceMember,
        failedAt(
            element, "Super set element $element must be an instance method."));
    assert(element.isField,
        failedAt(element, "Super set element $element must be a field."));
    return new StaticUse.internal(element, StaticUseKind.SUPER_FIELD_SET);
  }

  /// Write access of a super setter [element].
  factory StaticUse.superSetterSet(FunctionEntity element) {
    assert(
        element.isInstanceMember,
        failedAt(
            element, "Super set element $element must be an instance method."));
    assert(element.isSetter,
        failedAt(element, "Super set element $element must be a setter."));
    return new StaticUse.internal(element, StaticUseKind.SUPER_SETTER_SET);
  }

  /// Closurization of a super method [element].
  factory StaticUse.superTearOff(FunctionEntity element) {
    assert(
        element.isInstanceMember && element.isFunction,
        failedAt(element,
            "Super invoke element $element must be an instance method."));
    return new StaticUse.internal(element, StaticUseKind.SUPER_TEAR_OFF);
  }

  /// Invocation of a constructor [element] through a this or super
  /// constructor call with the given [callStructure].
  factory StaticUse.superConstructorInvoke(
      ConstructorEntity element, CallStructure callStructure) {
    assert(
        element.isGenerativeConstructor,
        failedAt(
            element,
            "Constructor invoke element $element must be a "
            "generative constructor."));
    assert(
        callStructure != null,
        failedAt(
            element,
            "Not CallStructure for super constructor invocation of element "
            "$element."));
    return new StaticUse.internal(element, StaticUseKind.STATIC_INVOKE,
        callStructure: callStructure);
  }

  /// Invocation of a constructor (body) [element] through a this or super
  /// constructor call with the given [callStructure].
  factory StaticUse.constructorBodyInvoke(
      ConstructorBodyEntity element, CallStructure callStructure) {
    assert(
        callStructure != null,
        failedAt(
            element,
            "Not CallStructure for constructor body invocation of element "
            "$element."));
    return new StaticUse.internal(element, StaticUseKind.STATIC_INVOKE,
        callStructure: callStructure);
  }

  /// Direct invocation of a generator (body) [element], as a static call or
  /// through a this or super constructor call.
  factory StaticUse.generatorBodyInvoke(FunctionEntity element) {
    return new StaticUse.internal(element, StaticUseKind.STATIC_INVOKE,
        callStructure: CallStructure.NO_ARGS);
  }

  /// Direct invocation of a method [element] with the given [callStructure].
  factory StaticUse.directInvoke(FunctionEntity element,
      CallStructure callStructure, List<DartType> typeArguments) {
    assert(
        element.isInstanceMember,
        failedAt(element,
            "Direct invoke element $element must be an instance member."));
    assert(element.isFunction,
        failedAt(element, "Direct invoke element $element must be a method."));
    return new GenericStaticUse(
        element, StaticUseKind.DIRECT_INVOKE, callStructure, typeArguments);
  }

  /// Direct read access of a field or getter [element].
  factory StaticUse.directGet(MemberEntity element) {
    assert(
        element.isInstanceMember,
        failedAt(element,
            "Direct get element $element must be an instance member."));
    assert(
        element.isField || element.isGetter,
        failedAt(element,
            "Direct get element $element must be a field or a getter."));
    return new StaticUse.internal(element, StaticUseKind.STATIC_GET);
  }

  /// Direct write access of a field [element].
  factory StaticUse.directSet(FieldEntity element) {
    assert(
        element.isInstanceMember,
        failedAt(element,
            "Direct set element $element must be an instance member."));
    assert(element.isField,
        failedAt(element, "Direct set element $element must be a field."));
    return new StaticUse.internal(element, StaticUseKind.STATIC_SET);
  }

  /// Constructor invocation of [element] with the given [callStructure].
  factory StaticUse.constructorInvoke(
      ConstructorEntity element, CallStructure callStructure) {
    assert(
        element.isConstructor,
        failedAt(element,
            "Constructor invocation element $element must be a constructor."));
    assert(
        callStructure != null,
        failedAt(
            element,
            "Not CallStructure for constructor invocation of element "
            "$element."));
    return new StaticUse.internal(element, StaticUseKind.STATIC_INVOKE,
        callStructure: callStructure);
  }

  /// Constructor invocation of [element] with the given [callStructure] on
  /// [type].
  factory StaticUse.typedConstructorInvoke(
      ConstructorEntity element,
      CallStructure callStructure,
      InterfaceType type,
      ImportEntity deferredImport) {
    assert(type != null,
        failedAt(element, "No type provided for constructor invocation."));
    assert(
        element.isConstructor,
        failedAt(
            element,
            "Typed constructor invocation element $element "
            "must be a constructor."));
    return new StaticUse.internal(element, StaticUseKind.CONSTRUCTOR_INVOKE,
        type: type,
        callStructure: callStructure,
        deferredImport: deferredImport);
  }

  /// Constant constructor invocation of [element] with the given
  /// [callStructure] on [type].
  factory StaticUse.constConstructorInvoke(
      ConstructorEntity element,
      CallStructure callStructure,
      InterfaceType type,
      ImportEntity deferredImport) {
    assert(type != null,
        failedAt(element, "No type provided for constructor invocation."));
    assert(
        element.isConstructor,
        failedAt(
            element,
            "Const constructor invocation element $element "
            "must be a constructor."));
    return new StaticUse.internal(
        element, StaticUseKind.CONST_CONSTRUCTOR_INVOKE,
        type: type,
        callStructure: callStructure,
        deferredImport: deferredImport);
  }

  /// Initialization of an instance field [element].
  factory StaticUse.fieldInit(FieldEntity element) {
    assert(
        element.isInstanceMember,
        failedAt(
            element, "Field init element $element must be an instance field."));
    return new StaticUse.internal(element, StaticUseKind.FIELD_INIT);
  }

  /// Constant initialization of an instance field [element].
  factory StaticUse.fieldConstantInit(
      FieldEntity element, ConstantValue constant) {
    assert(
        element.isInstanceMember,
        failedAt(
            element, "Field init element $element must be an instance field."));
    return new StaticUse.internal(element, StaticUseKind.FIELD_CONSTANT_INIT,
        constant: constant);
  }

  /// Read access of an instance field or boxed field [element].
  factory StaticUse.fieldGet(FieldEntity element) {
    assert(
        element.isInstanceMember || element is JRecordField,
        failedAt(element,
            "Field init element $element must be an instance or boxed field."));
    return new StaticUse.internal(element, StaticUseKind.INSTANCE_FIELD_GET);
  }

  /// Write access of an instance field or boxed field [element].
  factory StaticUse.fieldSet(FieldEntity element) {
    assert(
        element.isInstanceMember || element is JRecordField,
        failedAt(element,
            "Field init element $element must be an instance or boxed field."));
    return new StaticUse.internal(element, StaticUseKind.INSTANCE_FIELD_SET);
  }

  /// Read of a local function [element].
  factory StaticUse.closure(Local element) {
    return new StaticUse.internal(element, StaticUseKind.CLOSURE);
  }

  /// An invocation of a local function [element] with the provided
  /// [callStructure] and [typeArguments].
  factory StaticUse.closureCall(Local element, CallStructure callStructure,
      List<DartType> typeArguments) {
    return new GenericStaticUse(
        element, StaticUseKind.CLOSURE_CALL, callStructure, typeArguments);
  }

  /// Read of a call [method] on a closureClass.
  factory StaticUse.callMethod(FunctionEntity method) {
    return new StaticUse.internal(method, StaticUseKind.CALL_METHOD);
  }

  /// Implicit method/constructor invocation of [element] created by the
  /// backend.
  factory StaticUse.implicitInvoke(FunctionEntity element) {
    return new StaticUse.internal(element, StaticUseKind.STATIC_INVOKE,
        callStructure: element.parameterStructure.callStructure);
  }

  /// Inlining of [element].
  factory StaticUse.constructorInlining(
      ConstructorEntity element, InterfaceType instanceType) {
    return new StaticUse.internal(element, StaticUseKind.INLINING,
        type: instanceType);
  }

  /// Inlining of [element].
  factory StaticUse.methodInlining(
      FunctionEntity element, List<DartType> typeArguments) {
    return new GenericStaticUse.methodInlining(element, typeArguments);
  }

  @override
  bool operator ==(other) {
    if (identical(this, other)) return true;
    return other is StaticUse &&
        element == other.element &&
        kind == other.kind &&
        type == other.type &&
        callStructure == other.callStructure &&
        equalElements(typeArguments, other.typeArguments) &&
        deferredImport == other.deferredImport &&
        constant == other.constant;
  }

  @override
  String toString() =>
      'StaticUse($element,$kind,$type,$typeArguments,$callStructure)';
}

class GenericStaticUse extends StaticUse {
  @override
  final List<DartType> typeArguments;

  GenericStaticUse(Entity entity, StaticUseKind kind,
      CallStructure callStructure, this.typeArguments,
      [ImportEntity deferredImport])
      : super.internal(entity, kind,
            callStructure: callStructure,
            deferredImport: deferredImport,
            typeArgumentsHash: Hashing.listHash(typeArguments)) {
    assert(
        (callStructure?.typeArgumentCount ?? 0) == (typeArguments?.length ?? 0),
        failedAt(
            element,
            "Type argument count mismatch. Call structure has "
            "${callStructure?.typeArgumentCount ?? 0} but "
            "${typeArguments?.length ?? 0} were passed in $this."));
  }

  GenericStaticUse.methodInlining(FunctionEntity entity, this.typeArguments)
      : super.internal(entity, StaticUseKind.INLINING,
            typeArgumentsHash: Hashing.listHash(typeArguments));
}

enum TypeUseKind {
  IS_CHECK,
  AS_CAST,
  CATCH_TYPE,
  TYPE_LITERAL,
  INSTANTIATION,
  NATIVE_INSTANTIATION,
  CONST_INSTANTIATION,
  IMPLICIT_CAST,
  PARAMETER_CHECK,
  RTI_VALUE,
  TYPE_ARGUMENT,
}

/// Use of a [DartType].
class TypeUse {
  final DartType type;
  final TypeUseKind kind;
  @override
  final int hashCode;
  final ImportEntity deferredImport;

  TypeUse.internal(DartType type, TypeUseKind kind, [this.deferredImport])
      : this.type = type,
        this.kind = kind,
        this.hashCode = Hashing.objectsHash(type, kind, deferredImport);

  /// Short textual representation use for testing.
  String get shortText {
    StringBuffer sb = new StringBuffer();
    switch (kind) {
      case TypeUseKind.IS_CHECK:
        sb.write('is:');
        break;
      case TypeUseKind.AS_CAST:
        sb.write('as:');
        break;
      case TypeUseKind.CATCH_TYPE:
        sb.write('catch:');
        break;
      case TypeUseKind.TYPE_LITERAL:
        sb.write('lit:');
        break;
      case TypeUseKind.INSTANTIATION:
        sb.write('inst:');
        break;
      case TypeUseKind.CONST_INSTANTIATION:
        sb.write('const:');
        break;
      case TypeUseKind.NATIVE_INSTANTIATION:
        sb.write('native:');
        break;
      case TypeUseKind.IMPLICIT_CAST:
        sb.write('impl:');
        break;
      case TypeUseKind.PARAMETER_CHECK:
        sb.write('param:');
        break;
      case TypeUseKind.RTI_VALUE:
        sb.write('rti:');
        break;
      case TypeUseKind.TYPE_ARGUMENT:
        sb.write('typeArg:');
        break;
    }
    sb.write(type);
    if (deferredImport != null) {
      sb.write('{');
      sb.write(deferredImport.name);
      sb.write('}');
    }
    return sb.toString();
  }

  /// [type] used in an is check, like `e is T` or `e is! T`.
  factory TypeUse.isCheck(DartType type) {
    return new TypeUse.internal(type, TypeUseKind.IS_CHECK);
  }

  /// [type] used in an as cast, like `e as T`.
  factory TypeUse.asCast(DartType type) {
    return new TypeUse.internal(type, TypeUseKind.AS_CAST);
  }

  /// [type] used as a parameter type or field type in Dart 2, like `T` in:
  ///
  ///    method(T t) {}
  ///    T field;
  ///
  factory TypeUse.parameterCheck(DartType type) {
    return new TypeUse.internal(type, TypeUseKind.PARAMETER_CHECK);
  }

  /// [type] used in an implicit cast in Dart 2, like `T` in
  ///
  ///    dynamic foo = new Object();
  ///    T bar = foo; // Implicitly `T bar = foo as T`.
  ///
  factory TypeUse.implicitCast(DartType type) {
    return new TypeUse.internal(type, TypeUseKind.IMPLICIT_CAST);
  }

  /// [type] used in a on type catch clause, like `try {} on T catch (e) {}`.
  factory TypeUse.catchType(DartType type) {
    return new TypeUse.internal(type, TypeUseKind.CATCH_TYPE);
  }

  /// [type] used as a type literal, like `foo() => T;`.
  factory TypeUse.typeLiteral(DartType type, ImportEntity deferredImport) {
    return new TypeUse.internal(type, TypeUseKind.TYPE_LITERAL, deferredImport);
  }

  /// [type] used in an instantiation, like `new T();`.
  factory TypeUse.instantiation(InterfaceType type) {
    return new TypeUse.internal(type, TypeUseKind.INSTANTIATION);
  }

  /// [type] used in a constant instantiation, like `const T();`.
  factory TypeUse.constInstantiation(
      InterfaceType type, ImportEntity deferredImport) {
    return new TypeUse.internal(
        type, TypeUseKind.CONST_INSTANTIATION, deferredImport);
  }

  /// [type] used in a native instantiation.
  factory TypeUse.nativeInstantiation(InterfaceType type) {
    return new TypeUse.internal(type, TypeUseKind.NATIVE_INSTANTIATION);
  }

  /// [type] used as a direct RTI value.
  factory TypeUse.constTypeLiteral(DartType type) {
    return new TypeUse.internal(type, TypeUseKind.RTI_VALUE);
  }

  /// [type] used in a `instanceof` check.
  factory TypeUse.instanceConstructor(DartType type) {
    // TODO(johnniwinther,sra): Use a separate use kind if constructors is no
    // longer used for RTI.
    return new TypeUse.internal(type, TypeUseKind.RTI_VALUE);
  }

  /// [type] used directly as a type argument.
  ///
  /// The happens during optimization where a type variable can be replaced by
  /// an invariable type argument derived from a constant receiver.
  factory TypeUse.typeArgument(DartType type) {
    return new TypeUse.internal(type, TypeUseKind.TYPE_ARGUMENT);
  }

  @override
  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is! TypeUse) return false;
    return type == other.type && kind == other.kind;
  }

  @override
  String toString() => 'TypeUse($type,$kind)';
}

/// Use of a [ConstantValue].
class ConstantUse {
  final ConstantValue value;

  ConstantUse._(this.value);

  /// Short textual representation use for testing.
  String get shortText {
    return value.toDartText();
  }

  /// Constant used as the initial value of a field.
  ConstantUse.init(ConstantValue value) : this._(value);

  /// Type constant used for registration of custom elements.
  ConstantUse.customElements(TypeConstantValue value) : this._(value);

  /// Constant literal used on code.
  ConstantUse.literal(ConstantValue value) : this._(value);

  @override
  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is! ConstantUse) return false;
    return value == other.value;
  }

  @override
  int get hashCode => value.hashCode;

  @override
  String toString() => 'ConstantUse(${value.toStructuredText()})';
}
