// TODO(sigmund): rename universe => world
/// Describes individual features that may be seen in a program. Most features
/// can be described only by name using the [Feature] enum, some features are
/// expressed including details on how they are used. For example, whether a
/// list literal was constant or empty.
///
/// The use of these features is typically discovered in an early phase of the
/// compilation pipeline, for example during resolution.
library compiler.universe.feature;

import '../elements/types.dart';
import '../util/util.dart';

/// A language feature that may be seen in the program.
// TODO(johnniwinther): Should mirror usage be part of this?
enum Feature {
  /// Invocation of a generative construction on an abstract class.
  ABSTRACT_CLASS_INSTANTIATION,

  /// An assert statement with no message.
  ASSERT,

  /// An assert statement with a message.
  ASSERT_WITH_MESSAGE,

  /// A method with an `async` body modifier.
  ASYNC,

  /// An asynchronous for in statement like `await for (var e in i) {}`.
  ASYNC_FOR_IN,

  /// A method with an `async*` body modifier.
  ASYNC_STAR,

  /// A catch statement.
  CATCH_STATEMENT,

  /// A compile time error.
  COMPILE_TIME_ERROR,

  /// A fall through in a switch case.
  FALL_THROUGH_ERROR,

  /// A field without an initializer.
  FIELD_WITHOUT_INITIALIZER,

  /// A field whose initialization is not a constant.
  LAZY_FIELD,

  /// A local variable without an initializer.
  LOCAL_WITHOUT_INITIALIZER,

  /// Access to `loadLibrary` on a deferred import.
  LOAD_LIBRARY,

  /// A catch clause with a variable for the stack trace.
  STACK_TRACE_IN_CATCH,

  /// String interpolation.
  STRING_INTERPOLATION,

  /// String juxtaposition.
  STRING_JUXTAPOSITION,

  /// An implicit call to `super.noSuchMethod`, like calling an unresolved
  /// super method.
  SUPER_NO_SUCH_METHOD,

  /// A redirection to the `Symbol` constructor.
  SYMBOL_CONSTRUCTOR,

  /// An synchronous for in statement, like `for (var e in i) {}`.
  SYNC_FOR_IN,

  /// A method with a `sync*` body modifier.
  SYNC_STAR,

  /// A throw expression.
  THROW_EXPRESSION,

  /// An implicit throw of a `NoSuchMethodError`, like calling an unresolved
  /// static method.
  THROW_NO_SUCH_METHOD,

  /// An implicit throw of a runtime error, like in a runtime type check.
  THROW_RUNTIME_ERROR,

  /// An implicit throw of a `UnsupportedError`, like calling `new
  /// bool.fromEnvironment`.
  THROW_UNSUPPORTED_ERROR,

  /// The need for a type variable bound check, like instantiation of a generic
  /// type whose type variable have non-trivial bounds.
  TYPE_VARIABLE_BOUNDS_CHECK,
}

/// Describes a use of a map literal in the program.
class MapLiteralUse {
  final InterfaceType type;
  final bool isConstant;
  final bool isEmpty;

  MapLiteralUse(this.type, {this.isConstant: false, this.isEmpty: false});

  int get hashCode {
    return type.hashCode * 13 +
        isConstant.hashCode * 17 +
        isEmpty.hashCode * 19;
  }

  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is! MapLiteralUse) return false;
    return type == other.type &&
        isConstant == other.isConstant &&
        isEmpty == other.isEmpty;
  }

  String toString() {
    return 'MapLiteralUse($type,isConstant:$isConstant,isEmpty:$isEmpty)';
  }
}

/// Describes the use of a list literal in the program.
class ListLiteralUse {
  final InterfaceType type;
  final bool isConstant;
  final bool isEmpty;

  ListLiteralUse(this.type, {this.isConstant: false, this.isEmpty: false});

  int get hashCode {
    return type.hashCode * 13 +
        isConstant.hashCode * 17 +
        isEmpty.hashCode * 19;
  }

  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is! ListLiteralUse) return false;
    return type == other.type &&
        isConstant == other.isConstant &&
        isEmpty == other.isEmpty;
  }

  String toString() {
    return 'ListLiteralUse($type,isConstant:$isConstant,isEmpty:$isEmpty)';
  }
}

/// Enum for recognized use kinds of `Object.runtimeType`.
enum RuntimeTypeUseKind {
  /// Unknown use of `Object.runtimeType`. This is the fallback value if the
  /// usage didn't match any of the recogized patterns.
  unknown,

  /// `Object.runtimeType` used in a pattern like
  /// `a.runtimeType == b.runtimeType`.
  equals,

  /// `Object.runtimeType` used in a pattern like `'${e.runtimeType}'` or
  /// `e.runtimeType.toString()`.
  string,
}

/// A use of `Object.runtimeType`.
class RuntimeTypeUse {
  /// The use kind of `Object.runtimeType`.
  final RuntimeTypeUseKind kind;

  /// The static type of the receiver.
  final DartType receiverType;

  /// The static type of the argument if [kind] is `RuntimeTypeUseKind.equals`.
  final DartType argumentType;

  RuntimeTypeUse(this.kind, this.receiverType, this.argumentType);

  int get hashCode =>
      kind.hashCode * 13 +
      receiverType.hashCode * 17 +
      argumentType.hashCode * 19;

  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is! RuntimeTypeUse) return false;
    return kind == other.kind &&
        receiverType == other.receiverType &&
        argumentType == other.argumentType;
  }

  /// Short textual representation use for testing.
  String get shortText {
    StringBuffer sb = new StringBuffer();
    switch (kind) {
      case RuntimeTypeUseKind.string:
        sb.write('string:');
        sb.write(receiverType);
        break;
      case RuntimeTypeUseKind.equals:
        sb.write('equals:');
        sb.write(receiverType);
        sb.write('/');
        sb.write(argumentType);
        break;
      case RuntimeTypeUseKind.unknown:
        sb.write('unknown:');
        sb.write(receiverType);
        break;
    }
    return sb.toString();
  }

  String toString() => 'RuntimeTypeUse(kind=$kind,receiver=$receiverType'
      ',argument=$argumentType)';
}

/// A generic instantiation of an expression of type [functionType] with the
/// given [typeArguments].
class GenericInstantiation {
  /// The static type of the instantiated expression.
  final DartType functionType;

  /// The type arguments of the instantiation.
  final List<DartType> typeArguments;

  GenericInstantiation(this.functionType, this.typeArguments);

  /// Short textual representation use for testing.
  String get shortText => '<${typeArguments.join(',')}>';

  int get hashCode =>
      Hashing.listHash(typeArguments, Hashing.objectHash(functionType));

  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is! GenericInstantiation) return false;
    return functionType == other.functionType &&
        equalElements(typeArguments, other.typeArguments);
  }

  String toString() {
    return 'GenericInstantiation(functionType:$functionType,'
        'typeArguments:$typeArguments)';
  }
}
