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

library universe;

import '../elements/elements.dart';
import '../dart2jslib.dart';
import '../dart_types.dart';
import '../types/types.dart';
import '../tree/tree.dart';
import '../util/util.dart';

part 'function_set.dart';
part 'side_effects.dart';

class Universe {
  /// The set of all directly instantiated classes, that is, classes with a
  /// generative constructor that has been called directly and not only through
  /// a super-call.
  ///
  /// Invariant: Elements are declaration elements.
  // TODO(johnniwinther): [_directlyInstantiatedClasses] and
  // [_instantiatedTypes] sets should be merged.
  final Set<ClassElement> _directlyInstantiatedClasses =
      new Set<ClassElement>();

  /// The set of all directly instantiated types, that is, the types of the
  /// directly instantiated classes.
  ///
  /// See [_directlyInstantiatedClasses].
  final Set<DartType> _instantiatedTypes = new Set<DartType>();

  /// The set of all instantiated classes, either directly, as superclasses or
  /// as supertypes.
  ///
  /// Invariant: Elements are declaration elements.
  final Set<ClassElement> _allInstantiatedClasses = new Set<ClassElement>();

  /**
   * Documentation wanted -- johnniwinther
   *
   * Invariant: Elements are declaration elements.
   */
  final Set<FunctionElement> staticFunctionsNeedingGetter =
      new Set<FunctionElement>();
  final Set<FunctionElement> methodsNeedingSuperGetter =
      new Set<FunctionElement>();
  final Map<String, Set<Selector>> invokedNames =
      new Map<String, Set<Selector>>();
  final Map<String, Set<Selector>> invokedGetters =
      new Map<String, Set<Selector>>();
  final Map<String, Set<Selector>> invokedSetters =
      new Map<String, Set<Selector>>();

  /**
   * Fields accessed. Currently only the codegen knows this
   * information. The resolver is too conservative when seeing a
   * getter and only registers an invoked getter.
   */
  final Set<Element> fieldGetters = new Set<Element>();

  /**
   * Fields set. See comment in [fieldGetters].
   */
  final Set<Element> fieldSetters = new Set<Element>();
  final Set<DartType> isChecks = new Set<DartType>();

  /**
   * Set of (live) [:call:] methods whose signatures reference type variables.
   *
   * A live [:call:] method is one whose enclosing class has been instantiated.
   */
  final Set<Element> callMethodsWithFreeTypeVariables = new Set<Element>();

  /**
   * Set of (live) local functions (closures) whose signatures reference type
   * variables.
   *
   * A live function is one whose enclosing member function has been enqueued.
   */
  final Set<Element> closuresWithFreeTypeVariables = new Set<Element>();

  /**
   * Set of all closures in the program. Used by the mirror tracking system
   * to find all live closure instances.
   */
  final Set<LocalFunctionElement> allClosures = new Set<LocalFunctionElement>();

  /**
   * Set of methods in instantiated classes that are potentially
   * closurized.
   */
  final Set<Element> closurizedMembers = new Set<Element>();

  /// All directly instantiated classes, that is, classes with a generative
  /// constructor that has been called directly and not only through a
  /// super-call.
  // TODO(johnniwinther): Improve semantic precision.
  Iterable<ClassElement> get directlyInstantiatedClasses {
    return _directlyInstantiatedClasses;
  }

  /// All instantiated classes, either directly, as superclasses or as
  /// supertypes.
  // TODO(johnniwinther): Improve semantic precision.
  Iterable<ClassElement> get allInstantiatedClasses {
    return _allInstantiatedClasses;
  }

  /// All directly instantiated types, that is, the types of the directly
  /// instantiated classes.
  ///
  /// See [directlyInstantiatedClasses].
  // TODO(johnniwinther): Improve semantic precision.
  Iterable<DartType> get instantiatedTypes => _instantiatedTypes;

  /// Returns `true` if [cls] is considered to be instantiated, either directly,
  /// through subclasses or throught subtypes.
  // TODO(johnniwinther): Improve semantic precision.
  bool isInstantiated(ClassElement cls) {
    return _allInstantiatedClasses.contains(cls);
  }

  /// Register [type] as (directly) instantiated.
  ///
  /// If [byMirrors] is `true`, the instantiation is through mirrors.
  // TODO(johnniwinther): Fully enforce the separation between exact, through
  // subclass and through subtype instantiated types/classes.
  // TODO(johnniwinther): Support unknown type arguments for generic types.
  void registerTypeInstantiation(InterfaceType type,
                                 {bool byMirrors: false}) {
    _instantiatedTypes.add(type);
    ClassElement cls = type.element;
    if (!cls.isAbstract
        // We can't use the closed-world assumption with native abstract
        // classes; a native abstract class may have non-abstract subclasses
        // not declared to the program.  Instances of these classes are
        // indistinguishable from the abstract class.
        || cls.isNative
        // Likewise, if this registration comes from the mirror system,
        // all bets are off.
        // TODO(herhut): Track classes required by mirrors seperately.
        || byMirrors) {
      _directlyInstantiatedClasses.add(cls);
    }

    // TODO(johnniwinther): Replace this by separate more specific mappings.
    if (!_allInstantiatedClasses.add(cls)) return;
    cls.allSupertypes.forEach((InterfaceType supertype) {
      _allInstantiatedClasses.add(supertype.element);
    });
  }

  bool hasMatchingSelector(Set<Selector> selectors,
                           Element member,
                           World world) {
    if (selectors == null) return false;
    for (Selector selector in selectors) {
      if (selector.appliesUnnamed(member, world)) return true;
    }
    return false;
  }

  bool hasInvocation(Element member, World world) {
    return hasMatchingSelector(invokedNames[member.name], member, world);
  }

  bool hasInvokedGetter(Element member, World world) {
    return hasMatchingSelector(invokedGetters[member.name], member, world);
  }

  bool hasInvokedSetter(Element member, World world) {
    return hasMatchingSelector(invokedSetters[member.name], member, world);
  }

  DartType registerIsCheck(DartType type, Compiler compiler) {
    type = type.unalias(compiler);
    // 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.
    isChecks.add(type);
    return type;
  }

  void forgetElement(Element element, Compiler compiler) {
    allClosures.remove(element);
    slowDirectlyNestedClosures(element).forEach(compiler.forgetElement);
    closurizedMembers.remove(element);
    fieldSetters.remove(element);
    fieldGetters.remove(element);
    _directlyInstantiatedClasses.remove(element);
    _allInstantiatedClasses.remove(element);
    if (element is ClassElement) {
      assert(invariant(
          element, element.thisType.isRaw,
          message: 'Generic classes not supported (${element.thisType}).'));
      _instantiatedTypes
          ..remove(element.rawType)
          ..remove(element.thisType);
    }
  }

  // TODO(ahe): Replace this method with something that is O(1), for example,
  // by using a map.
  List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) {
    // Return new list to guard against concurrent modifications.
    return new List<LocalFunctionElement>.from(
        allClosures.where((LocalFunctionElement closure) {
          return closure.executableContext == element;
        }));
  }
}

class SelectorKind {
  final String name;
  final int hashCode;
  const SelectorKind(this.name, this.hashCode);

  static const SelectorKind GETTER = const SelectorKind('getter', 0);
  static const SelectorKind SETTER = const SelectorKind('setter', 1);
  static const SelectorKind CALL = const SelectorKind('call', 2);
  static const SelectorKind OPERATOR = const SelectorKind('operator', 3);
  static const SelectorKind INDEX = const SelectorKind('index', 4);

  String toString() => name;
}

class Selector {
  final SelectorKind kind;
  final String name;
  final LibraryElement library; // Library is null for non-private selectors.

  // The numbers of arguments of the selector. Includes named arguments.
  final int argumentCount;
  final List<String> namedArguments;
  final List<String> _orderedNamedArguments;
  final int hashCode;

  static const String INDEX_NAME ="[]";
  static const String INDEX_SET_NAME = "[]=";
  static const String CALL_NAME = Compiler.CALL_OPERATOR_NAME;

  Selector.internal(this.kind,
                    this.name,
                    this.library,
                    this.argumentCount,
                    this.namedArguments,
                    this._orderedNamedArguments,
                    this.hashCode) {
    assert(kind == SelectorKind.INDEX
           || (name != INDEX_NAME && name != INDEX_SET_NAME));
    assert(kind == SelectorKind.OPERATOR
           || kind == SelectorKind.INDEX
           || !Elements.isOperatorName(name));
    assert(kind == SelectorKind.CALL
           || kind == SelectorKind.GETTER
           || kind == SelectorKind.SETTER
           || Elements.isOperatorName(name));
    assert(!isPrivateName(name) || library != null);
  }

  static Map<int, List<Selector>> canonicalizedValues =
      new Map<int, List<Selector>>();

  factory Selector(SelectorKind kind,
                   String name,
                   LibraryElement library,
                   int argumentCount,
                   [List<String> namedArguments]) {
    if (!isPrivateName(name)) library = null;
    if (namedArguments == null) namedArguments = const <String>[];
    int hashCode = computeHashCode(
        kind, name, library, argumentCount, namedArguments);
    List<Selector> list = canonicalizedValues.putIfAbsent(hashCode,
        () => <Selector>[]);
    for (int i = 0; i < list.length; i++) {
      Selector existing = list[i];
      if (existing.match(kind, name, library, argumentCount, namedArguments)) {
        assert(existing.hashCode == hashCode);
        assert(existing.mask == null);
        return existing;
      }
    }
    List<String> orderedNamedArguments = namedArguments.isEmpty
        ? const <String>[]
        : <String>[];
    Selector result = new Selector.internal(
        kind, name, library, argumentCount,
        namedArguments, orderedNamedArguments,
        hashCode);
    list.add(result);
    return result;
  }

  factory Selector.fromElement(Element element) {
    String name = element.name;
    if (element.isFunction) {
      if (name == '[]') {
        return new Selector.index();
      } else if (name == '[]=') {
        return new Selector.indexSet();
      }
      FunctionSignature signature =
          element.asFunctionElement().functionSignature;
      int arity = signature.parameterCount;
      List<String> namedArguments = null;
      if (signature.optionalParametersAreNamed) {
        namedArguments =
            signature.orderedOptionalParameters.map((e) => e.name).toList();
      }
      if (element.isOperator) {
        // Operators cannot have named arguments, however, that doesn't prevent
        // a user from declaring such an operator.
        return new Selector(
            SelectorKind.OPERATOR, name, null, arity, namedArguments);
      } else {
        return new Selector.call(
            name, element.library, arity, namedArguments);
      }
    } else if (element.isSetter) {
      return new Selector.setter(name, element.library);
    } else if (element.isGetter) {
      return new Selector.getter(name, element.library);
    } else if (element.isField) {
      return new Selector.getter(name, element.library);
    } else {
      throw new SpannableAssertionFailure(
          element, "Can't get selector from $element");
    }
  }

  factory Selector.getter(String name, LibraryElement library)
      => new Selector(SelectorKind.GETTER, name, library, 0);

  factory Selector.getterFrom(Selector selector)
      => new Selector(SelectorKind.GETTER, selector.name, selector.library, 0);

  factory Selector.setter(String name, LibraryElement library)
      => new Selector(SelectorKind.SETTER, name, library, 1);

  factory Selector.unaryOperator(String name)
      => new Selector(SelectorKind.OPERATOR,
                      Elements.constructOperatorName(name, true),
                      null, 0);

  factory Selector.binaryOperator(String name)
      => new Selector(SelectorKind.OPERATOR,
                      Elements.constructOperatorName(name, false),
                      null, 1);

  factory Selector.index()
      => new Selector(SelectorKind.INDEX,
                      Elements.constructOperatorName(INDEX_NAME, false),
                      null, 1);

  factory Selector.indexSet()
      => new Selector(SelectorKind.INDEX,
                      Elements.constructOperatorName(INDEX_SET_NAME, false),
                      null, 2);

  factory Selector.call(String name,
                        LibraryElement library,
                        int arity,
                        [List<String> namedArguments])
      => new Selector(SelectorKind.CALL, name, library, arity, namedArguments);

  factory Selector.callClosure(int arity, [List<String> namedArguments])
      => new Selector(SelectorKind.CALL, CALL_NAME, null,
                      arity, namedArguments);

  factory Selector.callClosureFrom(Selector selector)
      => new Selector(SelectorKind.CALL, CALL_NAME, null,
                      selector.argumentCount, selector.namedArguments);

  factory Selector.callConstructor(String name, LibraryElement library,
                                   [int arity = 0,
                                    List<String> namedArguments])
      => new Selector(SelectorKind.CALL, name, library,
                      arity, namedArguments);

  factory Selector.callDefaultConstructor(LibraryElement library)
      => new Selector(SelectorKind.CALL, "", library, 0);

  bool get isGetter => identical(kind, SelectorKind.GETTER);
  bool get isSetter => identical(kind, SelectorKind.SETTER);
  bool get isCall => identical(kind, SelectorKind.CALL);
  bool get isClosureCall {
    String callName = Compiler.CALL_OPERATOR_NAME;
    return isCall && name == callName;
  }

  bool get isIndex => identical(kind, SelectorKind.INDEX) && argumentCount == 1;
  bool get isIndexSet => identical(kind, SelectorKind.INDEX) && argumentCount == 2;

  bool get isOperator => identical(kind, SelectorKind.OPERATOR);
  bool get isUnaryOperator => isOperator && argumentCount == 0;

  /** Check whether this is a call to 'assert'. */
  bool get isAssert => isCall && identical(name, "assert");

  int get namedArgumentCount => namedArguments.length;
  int get positionalArgumentCount => argumentCount - namedArgumentCount;

  bool get hasExactMask => false;
  TypeMask get mask => null;
  Selector get asUntyped => this;

  /**
   * The member name for invocation mirrors created from this selector.
   */
  String get invocationMirrorMemberName =>
      isSetter ? '$name=' : name;

  int get invocationMirrorKind {
    const int METHOD = 0;
    const int GETTER = 1;
    const int SETTER = 2;
    int kind = METHOD;
    if (isGetter) {
      kind = GETTER;
    } else if (isSetter) {
      kind = SETTER;
    }
    return kind;
  }

  bool appliesUnnamed(Element element, World world) {
    assert(sameNameHack(element, world));
    return appliesUntyped(element, world);
  }

  bool appliesUntyped(Element element, World world) {
    assert(sameNameHack(element, world));
    if (Elements.isUnresolved(element)) return false;
    if (isPrivateName(name) && library != element.library) return false;
    if (world.isForeign(element)) return true;
    if (element.isSetter) return isSetter;
    if (element.isGetter) return isGetter || isCall;
    if (element.isField) {
      return isSetter
          ? !element.isFinal && !element.isConst
          : isGetter || isCall;
    }
    if (isGetter) return true;
    if (isSetter) return false;
    return signatureApplies(element);
  }

  bool signatureApplies(FunctionElement function) {
    FunctionSignature parameters = function.functionSignature;
    if (argumentCount > parameters.parameterCount) return false;
    int requiredParameterCount = parameters.requiredParameterCount;
    int optionalParameterCount = parameters.optionalParameterCount;
    if (positionalArgumentCount < requiredParameterCount) return false;

    if (!parameters.optionalParametersAreNamed) {
      // We have already checked that the number of arguments are
      // not greater than the number of parameters. Therefore the
      // number of positional arguments are not greater than the
      // number of parameters.
      assert(positionalArgumentCount <= parameters.parameterCount);
      return namedArguments.isEmpty;
    } else {
      if (positionalArgumentCount > requiredParameterCount) return false;
      assert(positionalArgumentCount == requiredParameterCount);
      if (namedArgumentCount > optionalParameterCount) return false;
      Set<String> nameSet = new Set<String>();
      parameters.optionalParameters.forEach((Element element) {
        nameSet.add(element.name);
      });
      for (String name in namedArguments) {
        if (!nameSet.contains(name)) return false;
        // TODO(5213): By removing from the set we are checking
        // that we are not passing the name twice. We should have this
        // check in the resolver also.
        nameSet.remove(name);
      }
      return true;
    }
  }

  bool sameNameHack(Element element, World world) {
    // TODO(ngeoffray): Remove workaround checks.
    return element.isConstructor ||
           name == element.name ||
           name == 'assert' && world.isAssertMethod(element);
  }

  bool applies(Element element, World world) {
    if (!sameNameHack(element, world)) return false;
    return appliesUnnamed(element, world);
  }

  /**
   * Returns a `List` with the evaluated arguments in the normalized order.
   *
   * [compileDefaultValue] is a function that returns a compiled constant
   * of an optional argument that is not in [compiledArguments].
   *
   * Precondition: `this.applies(element, world)`.
   *
   * Invariant: [element] must be the implementation element.
   */
  /*<S, T>*/ List/*<T>*/ makeArgumentsList(
        FunctionElement element,
        List/*<T>*/ compiledArguments,
        /*T*/ compileDefaultValue(ParameterElement element)) {
    assert(invariant(element, element.isImplementation));
    List/*<T>*/ result = new List();
    FunctionSignature parameters = element.functionSignature;
    int i = 0;
    parameters.forEachRequiredParameter((ParameterElement element) {
      result.add(compiledArguments[i]);
      ++i;
    });

    if (!parameters.optionalParametersAreNamed) {
      parameters.forEachOptionalParameter((ParameterElement element) {
        if (i < compiledArguments.length) {
          result.add(compiledArguments[i]);
          ++i;
        } else {
          result.add(compileDefaultValue(element));
        }
      });
    } else {
      int offset = i;
      // Iterate over the optional parameters of the signature, and try to
      // find them in [compiledNamedArguments]. If found, we use the
      // value in the temporary list, otherwise the default value.
      parameters.orderedOptionalParameters
          .forEach((ParameterElement element) {
        int foundIndex = namedArguments.indexOf(element.name);
        if (foundIndex != -1) {
          result.add(compiledArguments[offset + foundIndex]);
        } else {
          result.add(compileDefaultValue(element));
        }
      });
    }
    return result;
  }

  /// This is a version of [makeArgumentsList] that works for a `Link`
  /// representation of arguments.
  /*<T>*/ List/*<T>*/ makeArgumentsList2(
      Link<Node> arguments,
      FunctionElement element,
      /*T*/ compileArgument(Node argument),
      /*T*/ compileDefaultValue(ParameterElement element)) {
    assert(invariant(element, element.isImplementation));
    List/*<T>*/ result = new List();

    FunctionSignature parameters = element.functionSignature;
    parameters.forEachRequiredParameter((ParameterElement element) {
      result.add(compileArgument(arguments.head));
      arguments = arguments.tail;
    });

    if (!parameters.optionalParametersAreNamed) {
      parameters.forEachOptionalParameter((ParameterElement element) {
        if (!arguments.isEmpty) {
          result.add(compileArgument(arguments.head));
          arguments = arguments.tail;
        } else {
          result.add(compileDefaultValue(element));
        }
      });
    } else {
      // Visit named arguments and add them into a temporary list.
      List compiledNamedArguments = [];
      for (; !arguments.isEmpty; arguments = arguments.tail) {
        NamedArgument namedArgument = arguments.head;
        compiledNamedArguments.add(compileArgument(namedArgument.expression));
      }
      // Iterate over the optional parameters of the signature, and try to
      // find them in [compiledNamedArguments]. If found, we use the
      // value in the temporary list, otherwise the default value.
      parameters.orderedOptionalParameters.forEach((ParameterElement element) {
        int foundIndex = namedArguments.indexOf(element.name);
        if (foundIndex != -1) {
          result.add(compiledNamedArguments[foundIndex]);
        } else {
          result.add(compileDefaultValue(element));
        }
      });
    }
    return result;
  }


  /**
   * Fills [list] with the arguments in the order expected by
   * [callee], and where [caller] is a synthesized element
   *
   * [compileArgument] is a function that returns a compiled version
   * of a parameter of [callee].
   *
   * [compileConstant] is a function that returns a compiled constant
   * of an optional argument that is not in the parameters of [callee].
   *
   * Returns [:true:] if the signature of the [caller] matches the
   * signature of the [callee], [:false:] otherwise.
   */
  static bool addForwardingElementArgumentsToList(
      FunctionElement caller,
      List list,
      FunctionElement callee,
      compileArgument(Element element),
      compileConstant(Element element),
      World world) {

    FunctionSignature signature = caller.functionSignature;
    Map mapping = new Map();

    // TODO(ngeoffray): This is a hack that fakes up AST nodes, so
    // that we can call [addArgumentsToList].
    Link computeCallNodesFromParameters() {
      LinkBuilder builder = new LinkBuilder();
      signature.forEachRequiredParameter((ParameterElement element) {
        Node node = element.node;
        mapping[node] = element;
        builder.addLast(node);
      });
      if (signature.optionalParametersAreNamed) {
        signature.forEachOptionalParameter((ParameterElement element) {
          mapping[element.initializer] = element;
          builder.addLast(new NamedArgument(null, null, element.initializer));
        });
      } else {
        signature.forEachOptionalParameter((ParameterElement element) {
          Node node = element.node;
          mapping[node] = element;
          builder.addLast(node);
        });
      }
      return builder.toLink();
    }

    internalCompileArgument(Node node) {
      return compileArgument(mapping[node]);
    }

    Link<Node> nodes = computeCallNodesFromParameters();

    // Synthesize a selector for the call.
    // TODO(ngeoffray): Should the resolver do it instead?
    List<String> namedParameters;
    if (signature.optionalParametersAreNamed) {
      namedParameters =
          signature.optionalParameters.mapToList((e) => e.name);
    }
    Selector selector = new Selector.call(callee.name,
                                          caller.library,
                                          signature.parameterCount,
                                          namedParameters);

    if (!selector.applies(callee, world)) return false;
    list.addAll(selector.makeArgumentsList2(nodes,
                                            callee,
                                            internalCompileArgument,
                                            compileConstant));

    return true;
  }

  static bool sameNames(List<String> first, List<String> second) {
    for (int i = 0; i < first.length; i++) {
      if (first[i] != second[i]) return false;
    }
    return true;
  }

  bool match(SelectorKind kind,
             String name,
             LibraryElement library,
             int argumentCount,
             List<String> namedArguments) {
    return this.kind == kind
        && this.name == name
        && identical(this.library, library)
        && this.argumentCount == argumentCount
        && this.namedArguments.length == namedArguments.length
        && sameNames(this.namedArguments, namedArguments);
  }

  static int computeHashCode(SelectorKind kind,
                             String name,
                             LibraryElement library,
                             int argumentCount,
                             List<String> namedArguments) {
    // Add bits from name and kind.
    int hash = mixHashCodeBits(name.hashCode, kind.hashCode);
    // Add bits from the library.
    if (library != null) hash = mixHashCodeBits(hash, library.hashCode);
    // Add bits from the unnamed arguments.
    hash = mixHashCodeBits(hash, argumentCount);
    // Add bits from the named arguments.
    int named = namedArguments.length;
    hash = mixHashCodeBits(hash, named);
    for (int i = 0; i < named; i++) {
      hash = mixHashCodeBits(hash, namedArguments[i].hashCode);
    }
    return hash;
  }

  // TODO(kasperl): Move this out so it becomes useful in other places too?
  static int mixHashCodeBits(int existing, int value) {
    // Spread the bits of value. Try to stay in the 30-bit range to
    // avoid overflowing into a more expensive integer representation.
    int h = value & 0x1fffffff;
    h += ((h & 0x3fff) << 15) ^ 0x1fffcd7d;
    h ^= (h >> 10);
    h += ((h & 0x3ffffff) << 3);
    h ^= (h >> 6);
    h += ((h & 0x7ffffff) << 2) + ((h & 0x7fff) << 14);
    h ^= (h >> 16);
    // Combine the two hash values.
    int high = existing >> 15;
    int low = existing & 0x7fff;
    return ((high * 13) ^ (low * 997) ^ h) & SMI_MASK;
  }

  List<String> getOrderedNamedArguments() {
    if (namedArguments.isEmpty) return namedArguments;
    if (!_orderedNamedArguments.isEmpty) return _orderedNamedArguments;

    _orderedNamedArguments.addAll(namedArguments);
    _orderedNamedArguments.sort((String first, String second) {
      return first.compareTo(second);
    });
    return _orderedNamedArguments;
  }

  String namedArgumentsToString() {
    if (namedArgumentCount > 0) {
      StringBuffer result = new StringBuffer();
      for (int i = 0; i < namedArgumentCount; i++) {
        if (i != 0) result.write(', ');
        result.write(namedArguments[i]);
      }
      return "[$result]";
    }
    return '';
  }

  String toString() {
    String named = '';
    String type = '';
    if (namedArgumentCount > 0) named = ', named=${namedArgumentsToString()}';
    if (mask != null) type = ', mask=$mask';
    return 'Selector($kind, $name, '
           'arity=$argumentCount$named$type)';
  }

  Selector extendIfReachesAll(Compiler compiler) {
    return new TypedSelector(
        compiler.typesTask.dynamicType, this, compiler.world);
  }

  Selector toCallSelector() => new Selector.callClosureFrom(this);
}

class TypedSelector extends Selector {
  final Selector asUntyped;
  final TypeMask mask;

  TypedSelector.internal(this.mask, Selector selector, int hashCode)
      : asUntyped = selector,
        super.internal(selector.kind,
                       selector.name,
                       selector.library,
                       selector.argumentCount,
                       selector.namedArguments,
                       selector._orderedNamedArguments,
                       hashCode) {
    assert(mask != null);
    assert(asUntyped.mask == null);
  }


  factory TypedSelector(TypeMask mask, Selector selector, World world) {
    if (!world.hasClosedWorldAssumption) {
      // TODO(johnniwinther): Improve use of TypedSelector in an open world.
      bool isNullable = mask.isNullable;
      mask = world.compiler.typesTask.dynamicType;
      if (isNullable) {
        mask = mask.nullable();
      }
    }
    // TODO(johnniwinther): Allow more TypeSelector kinds during resoluton.
    assert(world.isClosed || mask.isExact);
    if (selector.mask == mask) return selector;
    Selector untyped = selector.asUntyped;
    Map<TypeMask, TypedSelector> map = world.canonicalizedValues
        .putIfAbsent(untyped, () => new Map<TypeMask, TypedSelector>());
    TypedSelector result = map[mask];
    if (result == null) {
      int hashCode = Selector.mixHashCodeBits(untyped.hashCode, mask.hashCode);
      result = map[mask] = new TypedSelector.internal(mask, untyped, hashCode);
    }
    return result;
  }

  factory TypedSelector.exact(
      ClassElement base, Selector selector, World world)
          => new TypedSelector(new TypeMask.exact(base, world), selector,
              world);

  factory TypedSelector.subclass(
      ClassElement base, Selector selector, World world)
          => new TypedSelector(new TypeMask.subclass(base, world),
                               selector, world);

  factory TypedSelector.subtype(
      ClassElement base, Selector selector, World world)
          => new TypedSelector(new TypeMask.subtype(base, world),
                               selector, world);

  bool appliesUnnamed(Element element, World world) {
    assert(sameNameHack(element, world));
    // [TypedSelector] are only used after resolution.
    if (!element.isClassMember) return false;

    // A closure can be called through any typed selector:
    // class A {
    //   get foo => () => 42;
    //   bar() => foo(); // The call to 'foo' is a typed selector.
    // }
    if (element.enclosingClass.isClosure) {
      return appliesUntyped(element, world);
    }

    if (!mask.canHit(element, this, world)) return false;
    return appliesUntyped(element, world);
  }

  Selector extendIfReachesAll(Compiler compiler) {
    bool canReachAll = compiler.enabledInvokeOn
        && mask.needsNoSuchMethodHandling(this, compiler.world);
    return canReachAll
        ? new TypedSelector(
            compiler.typesTask.dynamicType, this, compiler.world)
        : this;
  }
}
