// Copyright (c) 2013, 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 elements.modelx;

import 'elements.dart';
import '../constants/expressions.dart';
import '../helpers/helpers.dart';  // Included for debug helpers.
import '../tree/tree.dart';
import '../util/util.dart';
import '../resolution/resolution.dart';
import '../resolution/class_members.dart' show ClassMemberMixin;

import '../dart2jslib.dart' show invariant,
                                 InterfaceType,
                                 DartType,
                                 TypeVariableType,
                                 TypedefType,
                                 DualKind,
                                 MessageKind,
                                 DiagnosticListener,
                                 Script,
                                 FunctionType,
                                 Selector,
                                 Constant,
                                 Compiler,
                                 Backend,
                                 isPrivateName;

import '../dart_types.dart';

import '../scanner/scannerlib.dart' show
    EOF_TOKEN,
    ErrorToken,
    Token;

import '../ordered_typeset.dart' show OrderedTypeSet;

import 'visitor.dart' show ElementVisitor;

abstract class DeclarationSite {
}

abstract class ElementX extends Element {
  static int elementHashCode = 0;

  final String name;
  final ElementKind kind;
  final Element enclosingElement;
  final int hashCode = ++elementHashCode;
  Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>();

  ElementX(this.name, this.kind, this.enclosingElement) {
    assert(isErroneous || implementationLibrary != null);
  }

  Modifiers get modifiers => Modifiers.EMPTY;

  Node parseNode(DiagnosticListener listener) {
    listener.internalError(this,
        'parseNode not implemented on $this.');
    return null;
  }

  DartType computeType(Compiler compiler) {
    compiler.internalError(this,
        "computeType not implemented on $this.");
    return null;
  }

  void addMetadata(MetadataAnnotationX annotation) {
    assert(annotation.annotatedElement == null);
    annotation.annotatedElement = this;
    addMetadataInternal(annotation);
  }

  void addMetadataInternal(MetadataAnnotation annotation) {
    metadata = metadata.prepend(annotation);
  }

  bool get isClosure => false;
  bool get isClassMember {
    // Check that this element is defined in the scope of a Class.
    return enclosingElement != null && enclosingElement.isClass;
  }
  bool get isInstanceMember => false;
  bool get isDeferredLoaderGetter => false;

  bool get isFactoryConstructor => modifiers.isFactory;
  bool get isConst => modifiers.isConst;
  bool get isFinal => modifiers.isFinal;
  bool get isStatic => modifiers.isStatic;
  bool get isOperator => Elements.isOperatorName(name);
  bool get impliesType => (kind.category & ElementCategory.IMPLIES_TYPE) != 0;

  bool get isPatched => false;

  bool get isPatch => false;

  bool get isImplementation => true;

  bool get isDeclaration => true;

  bool get isInjected => !isPatch && implementationLibrary.isPatch;

  Element get implementation => this;

  Element get declaration => this;

  Element get patch {
    throw new UnsupportedError('patch is not supported on $this');
  }

  Element get origin {
    throw new UnsupportedError('origin is not supported on $this');
  }

  bool get isSynthesized => false;

  bool get isForwardingConstructor => false;

  bool get isMixinApplication => false;

  bool get isLocal => false;

  // TODO(johnniwinther): This breaks for libraries (for which enclosing
  // elements are null) and is invalid for top level variable declarations for
  // which the enclosing element is a VariableDeclarations and not a compilation
  // unit.
  bool get isTopLevel {
    return enclosingElement != null && enclosingElement.isCompilationUnit;
  }

  bool get isAssignable {
    if (isFinal || isConst) return false;
    if (isFunction || isGenerativeConstructor) return false;
    return true;
  }

  Token get position => null;

  Token findMyName(Token token) {
    return findNameToken(token, isConstructor, name, enclosingElement.name);
  }

  static Token findNameToken(Token token, bool isConstructor, String name,
                             String enclosingClassName) {
    // We search for the token that has the name of this element.
    // For constructors, that doesn't work because they may have
    // named formed out of multiple tokens (named constructors) so
    // for those we search for the class name instead.
    String needle = isConstructor ? enclosingClassName : name;
    // The unary '-' operator has a special element name (specified).
    if (needle == 'unary-') needle = '-';
    for (Token t = token; EOF_TOKEN != t.kind; t = t.next) {
      if (t is !ErrorToken && needle == t.value) return t;
    }
    return token;
  }

  CompilationUnitElement get compilationUnit {
    Element element = this;
    while (!element.isCompilationUnit) {
      element = element.enclosingElement;
    }
    return element;
  }

  LibraryElement get library => enclosingElement.library;

  LibraryElement get implementationLibrary {
    Element element = this;
    while (!identical(element.kind, ElementKind.LIBRARY)) {
      element = element.enclosingElement;
    }
    return element;
  }

  ClassElement get enclosingClass {
    for (Element e = this; e != null; e = e.enclosingElement) {
      if (e.isClass) return e;
    }
    return null;
  }

  Element get enclosingClassOrCompilationUnit {
   for (Element e = this; e != null; e = e.enclosingElement) {
      if (e.isClass || e.isCompilationUnit) return e;
    }
    return null;
  }

  Element get outermostEnclosingMemberOrTopLevel {
    // TODO(lrn): Why is this called "Outermost"?
    // TODO(johnniwinther): Clean up this method: This method does not return
    // the outermost for elements in closure classses, but some call-sites rely
    // on that behavior.
    for (Element e = this; e != null; e = e.enclosingElement) {
      if (e.isClassMember || e.isTopLevel) {
        return e;
      }
    }
    return null;
  }

  ClassElement get contextClass {
    ClassElement cls;
    for (Element e = this; e != null; e = e.enclosingElement) {
      if (e.isClass) {
        // Record [e] instead of returning it directly. We need the last class
        // in the chain since the first classes might be closure classes.
        cls = e.declaration;
      }
    }
    return cls;
  }

  /**
   * Creates the scope for this element.
   */
  Scope buildScope() => enclosingElement.buildScope();

  String toString() {
    // TODO(johnniwinther): Test for nullness of name, or make non-nullness an
    // invariant for all element types?
    var nameText = name != null ? name : '?';
    if (enclosingElement != null && !isTopLevel) {
      String holderName = enclosingElement.name != null
          ? enclosingElement.name
          : '${enclosingElement.kind}?';
      return '$kind($holderName#${nameText})';
    } else {
      return '$kind(${nameText})';
    }
  }

  String _fixedBackendName = null;
  bool _isNative = false;
  bool get isNative => _isNative;
  bool get hasFixedBackendName => _fixedBackendName != null;
  String get fixedBackendName => _fixedBackendName;
  // Marks this element as a native element.
  void setNative(String name) {
    _isNative = true;
    _fixedBackendName = name;
  }
  void setFixedBackendName(String name) {
    _fixedBackendName = name;
  }

  FunctionElement asFunctionElement() => null;

  bool get isAbstract => modifiers.isAbstract;
  bool isForeign(Backend backend) => backend.isForeign(this);

  void diagnose(Element context, DiagnosticListener listener) {}

  bool get hasTreeElements => analyzableElement.hasTreeElements;

  TreeElements get treeElements => analyzableElement.treeElements;

  AnalyzableElement get analyzableElement {
    Element element = outermostEnclosingMemberOrTopLevel;
    if (element.isAbstractField || element.isPrefix) return element.library;
    return element;
  }

  DeclarationSite get declarationSite => null;
}

class ErroneousElementX extends ElementX implements ErroneousElement {
  final MessageKind messageKind;
  final Map messageArguments;

  ErroneousElementX(this.messageKind, this.messageArguments,
                    String name, Element enclosing)
      : super(name, ElementKind.ERROR, enclosing);

  bool get isTopLevel => false;

  bool get isSynthesized => true;

  AbstractFieldElement abstractField;

  unsupported() {
    throw 'unsupported operation on erroneous element';
  }

  Link<MetadataAnnotation> get metadata => unsupported();
  bool get hasNode => false;
  get node => unsupported();
  get hasResolvedAst => false;
  get resolvedAst => unsupported();
  get type => unsupported();
  get cachedNode => unsupported();
  get functionSignature => unsupported();
  get patch => null;
  get origin => this;
  get immediateRedirectionTarget => unsupported();
  get nestedClosures => unsupported();
  get memberContext => unsupported();
  get executableContext => unsupported();

  bool get isRedirectingFactory => unsupported();

  computeSignature(compiler) => unsupported();

  bool get hasFunctionSignature => false;

  get effectiveTarget => this;

  computeEffectiveTargetType(InterfaceType newType) => unsupported();

  get definingConstructor => null;

  FunctionElement asFunctionElement() => this;

  String get message => '${messageKind.message(messageArguments)}';

  String toString() => '<$name: $message>';

  accept(ElementVisitor visitor) => visitor.visitErroneousElement(this);
}

/// A message attached to a [WarnOnUseElementX].
class WrappedMessage {
  /// The message position. If [:null:] the position of the reference to the
  /// [WarnOnUseElementX] is used.
  final Spannable spannable;

  /**
   * The message to report on resolving a wrapped element.
   */
  final MessageKind messageKind;

  /**
   * The message arguments to report on resolving a wrapped element.
   */
  final Map messageArguments;

  WrappedMessage(this.spannable, this.messageKind, this.messageArguments);
}

class WarnOnUseElementX extends ElementX implements WarnOnUseElement {
  /// Warning to report on resolving this element.
  final WrappedMessage warning;

  /// Info to report on resolving this element.
  final WrappedMessage info;

  /// The element whose usage cause a warning.
  final Element wrappedElement;

  WarnOnUseElementX(WrappedMessage this.warning, WrappedMessage this.info,
                    Element enclosingElement, Element wrappedElement)
      : this.wrappedElement = wrappedElement,
        super(wrappedElement.name, ElementKind.WARN_ON_USE, enclosingElement);

  Element unwrap(DiagnosticListener listener, Spannable usageSpannable) {
    var unwrapped = wrappedElement;
    if (warning != null) {
      Spannable spannable = warning.spannable;
      if (spannable == null) spannable = usageSpannable;
      listener.reportWarning(
          spannable, warning.messageKind, warning.messageArguments);
    }
    if (info != null) {
      Spannable spannable = info.spannable;
      if (spannable == null) spannable = usageSpannable;
      listener.reportInfo(
          spannable, info.messageKind, info.messageArguments);
    }
    if (unwrapped.isWarnOnUse) {
      unwrapped = unwrapped.unwrap(listener, usageSpannable);
    }
    return unwrapped;
  }

  accept(ElementVisitor visitor) => visitor.visitWarnOnUseElement(this);
}

class AmbiguousElementX extends ElementX implements AmbiguousElement {
  /**
   * The message to report on resolving this element.
   */
  final MessageKind messageKind;

  /**
   * The message arguments to report on resolving this element.
   */
  final Map messageArguments;

  /**
   * The first element that this ambiguous element might refer to.
   */
  final Element existingElement;

  /**
   * The second element that this ambiguous element might refer to.
   */
  final Element newElement;

  AmbiguousElementX(this.messageKind, this.messageArguments,
      Element enclosingElement, Element existingElement, Element newElement)
      : this.existingElement = existingElement,
        this.newElement = newElement,
        super(existingElement.name, ElementKind.AMBIGUOUS, enclosingElement);

  Setlet flatten() {
    Element element = this;
    var set = new Setlet();
    while (element.isAmbiguous) {
      AmbiguousElement ambiguous = element;
      set.add(ambiguous.newElement);
      element = ambiguous.existingElement;
    }
    set.add(element);
    return set;
  }

  void diagnose(Element context, DiagnosticListener listener) {
    Setlet ambiguousElements = flatten();
    MessageKind code = (ambiguousElements.length == 1)
        ? MessageKind.AMBIGUOUS_REEXPORT : MessageKind.AMBIGUOUS_LOCATION;
    LibraryElementX importer = context.library;
    for (Element element in ambiguousElements) {
      var arguments = {'name': element.name};
      listener.reportInfo(element, code, arguments);
      Link<Import> importers = importer.importers.getImports(element);
      listener.withCurrentElement(importer, () {
        for (; !importers.isEmpty; importers = importers.tail) {
          listener.reportInfo(
              importers.head, MessageKind.IMPORTED_HERE, arguments);
        }
      });
    }
  }

  accept(ElementVisitor visitor) => visitor.visitAmbiguousElement(this);

  bool get isTopLevel => false;
}

class ScopeX {
  final Map<String, Element> contents = new Map<String, Element>();

  bool get isEmpty => contents.isEmpty;
  Iterable<Element> get values => contents.values;

  Element lookup(String name) {
    return contents[name];
  }

  void add(Element element, DiagnosticListener listener) {
    String name = element.name;
    if (element.isAccessor) {
      addAccessor(element, contents[name], listener);
    } else {
      Element existing = contents.putIfAbsent(name, () => element);
      if (!identical(existing, element)) {
        listener.reportError(
            element, MessageKind.DUPLICATE_DEFINITION, {'name': name});
        listener.reportInfo(existing,
            MessageKind.EXISTING_DEFINITION, {'name': name});
      }
    }
  }

  /**
   * Adds a definition for an [accessor] (getter or setter) to a scope.
   * The definition binds to an abstract field that can hold both a getter
   * and a setter.
   *
   * The abstract field is added once, for the first getter or setter, and
   * reused if the other one is also added.
   * The abstract field should not be treated as a proper member of the
   * container, it's simply a way to return two results for one lookup.
   * That is, the getter or setter does not have the abstract field as enclosing
   * element, they are enclosed by the class or compilation unit, as is the
   * abstract field.
   */
  void addAccessor(FunctionElementX accessor,
                   Element existing,
                   DiagnosticListener listener) {
    void reportError(Element other) {
      listener.reportError(accessor,
                           MessageKind.DUPLICATE_DEFINITION,
                           {'name': accessor.name});
      // TODO(johnniwinther): Make this an info instead of a fatal error.
      listener.reportFatalError(other,
                                MessageKind.EXISTING_DEFINITION,
                                {'name': accessor.name});
    }

    if (existing != null) {
      if (!identical(existing.kind, ElementKind.ABSTRACT_FIELD)) {
        reportError(existing);
      } else {
        AbstractFieldElementX field = existing;
        accessor.abstractField = field;
        if (accessor.isGetter) {
          if (field.getter != null && field.getter != accessor) {
            reportError(field.getter);
          }
          field.getter = accessor;
        } else {
          assert(accessor.isSetter);
          if (field.setter != null && field.setter != accessor) {
            reportError(field.setter);
          }
          field.setter = accessor;
        }
      }
    } else {
      Element container = accessor.enclosingClassOrCompilationUnit;
      AbstractFieldElementX field =
          new AbstractFieldElementX(accessor.name, container);
      accessor.abstractField = field;
      if (accessor.isGetter) {
        field.getter = accessor;
      } else {
        field.setter = accessor;
      }
      add(field, listener);
    }
  }
}

class CompilationUnitElementX extends ElementX
    implements CompilationUnitElement {
  final Script script;
  PartOf partTag;
  Link<Element> localMembers = const Link<Element>();

  CompilationUnitElementX(Script script, LibraryElement library)
    : this.script = script,
      super(script.name,
            ElementKind.COMPILATION_UNIT,
            library) {
    library.addCompilationUnit(this);
  }

  void forEachLocalMember(f(Element element)) {
    localMembers.forEach(f);
  }

  void addMember(Element element, DiagnosticListener listener) {
    // Keep a list of top level members.
    localMembers = localMembers.prepend(element);
    // Provide the member to the library to build scope.
    if (enclosingElement.isPatch) {
      implementationLibrary.addMember(element, listener);
    } else {
      library.addMember(element, listener);
    }
  }

  void setPartOf(PartOf tag, DiagnosticListener listener) {
    LibraryElementX library = enclosingElement;
    if (library.entryCompilationUnit == this) {
      listener.reportError(tag, MessageKind.ILLEGAL_DIRECTIVE);
      return;
    }
    if (!localMembers.isEmpty) {
      listener.reportError(tag, MessageKind.BEFORE_TOP_LEVEL);
      return;
    }
    if (partTag != null) {
      listener.reportWarning(tag, MessageKind.DUPLICATED_PART_OF);
      return;
    }
    partTag = tag;
    LibraryName libraryTag = library.libraryTag;
    String actualName = tag.name.toString();
    if (libraryTag != null) {
      String expectedName = libraryTag.name.toString();
      if (expectedName != actualName) {
        listener.reportWarning(tag.name,
            MessageKind.LIBRARY_NAME_MISMATCH,
            {'libraryName': expectedName});
      }
    } else {
      listener.reportWarning(library,
          MessageKind.MISSING_LIBRARY_NAME,
          {'libraryName': actualName});
      listener.reportInfo(tag.name,
          MessageKind.THIS_IS_THE_PART_OF_TAG);
    }
  }

  bool get hasMembers => !localMembers.isEmpty;

  int compareTo(CompilationUnitElement other) {
    if (this == other) return 0;
    return '${script.readableUri}'.compareTo('${other.script.readableUri}');
  }

  Element get analyzableElement => library;

  accept(ElementVisitor visitor) => visitor.visitCompilationUnitElement(this);
}

class Importers {
  Map<Element, Link<Import>> importers = new Map<Element, Link<Import>>();

  Link<Import> getImports(Element element) {
    Link<Import> imports = importers[element];
    return imports != null ? imports : const Link<Import>();
  }

  Import getImport(Element element) => getImports(element).head;

  void registerImport(Element element, Import import) {
    if (import == null) return;

    importers[element] =
        importers.putIfAbsent(element, () => const Link<Import>())
          .prepend(import);
  }
}

class ImportScope {
  /**
   * Map for elements imported through import declarations.
   *
   * Addition to the map is performed by [addImport]. Lookup is done trough
   * [find].
   */
  final Map<String, Element> importScope =
      new Map<String, Element>();

  /**
   * Adds [element] to the import scope of this library.
   *
   * If an element by the same name is already in the imported scope, an
   * [ErroneousElement] will be put in the imported scope, allowing for
   * detection of ambiguous uses of imported names.
   */
  void addImport(Element enclosingElement,
                 Element element,
                 Import import,
                 DiagnosticListener listener) {
    LibraryElementX library = enclosingElement.library;
    Importers importers = library.importers;

    String name = element.name;

    // The loadLibrary function always shadows existing bindings to that name.
    if (element.isDeferredLoaderGetter) {
      importScope.remove(name);
      // TODO(sigurdm): Print a hint.
    }
    Element existing = importScope.putIfAbsent(name, () => element);
    importers.registerImport(element, import);

    void registerWarnOnUseElement(Import import,
                                  MessageKind messageKind,
                                  Element hidingElement,
                                  Element hiddenElement) {
      Uri hiddenUri = hiddenElement.library.canonicalUri;
      Uri hidingUri = hidingElement.library.canonicalUri;
      Element element = new WarnOnUseElementX(
          new WrappedMessage(
              null, // Report on reference to [hidingElement].
              messageKind,
              {'name': name, 'hiddenUri': hiddenUri, 'hidingUri': hidingUri}),
          new WrappedMessage(
              listener.spanFromSpannable(import),
              MessageKind.IMPORTED_HERE,
              {'name': name}),
          enclosingElement, hidingElement);
      importScope[name] = element;
      importers.registerImport(element, import);
    }

    if (existing != element) {
      Import existingImport = importers.getImport(existing);
      Element newElement;
      if (existing.library.isPlatformLibrary &&
          !element.library.isPlatformLibrary) {
        // [existing] is implicitly hidden.
        registerWarnOnUseElement(
            import, MessageKind.HIDDEN_IMPORT, element, existing);
      } else if (!existing.library.isPlatformLibrary &&
                 element.library.isPlatformLibrary) {
        // [element] is implicitly hidden.
        if (import == null) {
          // [element] is imported implicitly (probably through dart:core).
          registerWarnOnUseElement(
              existingImport, MessageKind.HIDDEN_IMPLICIT_IMPORT,
              existing, element);
        } else {
          registerWarnOnUseElement(
              import, MessageKind.HIDDEN_IMPORT, existing, element);
        }
      } else {
        Element ambiguousElement = new AmbiguousElementX(
            MessageKind.DUPLICATE_IMPORT, {'name': name},
            enclosingElement, existing, element);
        importScope[name] = ambiguousElement;
        importers.registerImport(ambiguousElement, import);
        importers.registerImport(ambiguousElement, existingImport);
      }
    }
  }

  Element operator [](String name) => importScope[name];
}

class LibraryElementX
    extends ElementX with AnalyzableElementX, PatchMixin<LibraryElementX>
    implements LibraryElement {
  final Uri canonicalUri;
  CompilationUnitElement entryCompilationUnit;
  Link<CompilationUnitElement> compilationUnits =
      const Link<CompilationUnitElement>();
  LinkBuilder<LibraryTag> tagsBuilder = new LinkBuilder<LibraryTag>();
  List<LibraryTag> tagsCache;
  LibraryName libraryTag;
  bool canUseNative = false;
  Link<Element> localMembers = const Link<Element>();
  final ScopeX localScope = new ScopeX();
  final ImportScope importScope = new ImportScope();

  /// A mapping from an imported element to the "import" tag.
  final Importers importers = new Importers();

  /**
   * Link for elements exported either through export declarations or through
   * declaration. This field should not be accessed directly but instead through
   * the [exports] getter.
   *
   * [LibraryDependencyHandler] sets this field through [setExports] when the
   * library is loaded.
   */
  Link<Element> slotForExports;

  final Map<LibraryDependency, LibraryElement> tagMapping =
      new Map<LibraryDependency, LibraryElement>();

  LibraryElementX(Script script,
                  [Uri canonicalUri, LibraryElementX origin])
    : this.canonicalUri =
          ((canonicalUri == null) ? script.readableUri : canonicalUri),
      super(script.name, ElementKind.LIBRARY, null) {
    entryCompilationUnit = new CompilationUnitElementX(script, this);
    if (origin != null) {
      origin.applyPatch(this);
    }
  }

  bool get isDartCore => canonicalUri == Compiler.DART_CORE;

  Link<MetadataAnnotation> get metadata {
    return (libraryTag == null) ? super.metadata : libraryTag.metadata;
  }

  set metadata(value) {
    // The metadata is stored on [libraryTag].
    throw new SpannableAssertionFailure(this, 'Cannot set metadata on Library');
  }

  CompilationUnitElement get compilationUnit => entryCompilationUnit;

  Element get analyzableElement => this;

  void addCompilationUnit(CompilationUnitElement element) {
    compilationUnits = compilationUnits.prepend(element);
  }

  void addTag(LibraryTag tag, DiagnosticListener listener) {
    if (tagsCache != null) {
      listener.internalError(tag,
          "Library tags for $this have already been computed.");
    }
    tagsBuilder.addLast(tag);
  }

  Iterable<LibraryTag> get tags {
    if (tagsCache == null) {
      tagsCache = tagsBuilder.toList();
      tagsBuilder = null;
    }
    return tagsCache;
  }

  void recordResolvedTag(LibraryDependency tag, LibraryElement library) {
    assert(tagMapping[tag] == null);
    tagMapping[tag] = library;
  }

  LibraryElement getLibraryFromTag(LibraryDependency tag) => tagMapping[tag];

  /**
   * Adds [element] to the import scope of this library.
   *
   * If an element by the same name is already in the imported scope, an
   * [ErroneousElement] will be put in the imported scope, allowing for
   * detection of ambiguous uses of imported names.
   */
  void addImport(Element element, Import import, DiagnosticListener listener) {
    importScope.addImport(this, element, import, listener);
  }

  void addMember(Element element, DiagnosticListener listener) {
    localMembers = localMembers.prepend(element);
    addToScope(element, listener);
  }

  void addToScope(Element element, DiagnosticListener listener) {
    localScope.add(element, listener);
  }

  Element localLookup(String elementName) {
    Element result = localScope.lookup(elementName);
    if (result == null && isPatch) {
      result = origin.localLookup(elementName);
    }
    return result;
  }

  /**
   * Returns [:true:] if the export scope has already been computed for this
   * library.
   */
  bool get exportsHandled => slotForExports != null;

  Link<Element> get exports {
    assert(invariant(this, exportsHandled,
                     message: 'Exports not handled on $this'));
    return slotForExports;
  }

  /**
   * Sets the export scope of this library. This method can only be called once.
   */
  void setExports(Iterable<Element> exportedElements) {
    assert(invariant(this, !exportsHandled,
        message: 'Exports already set to $slotForExports on $this'));
    assert(invariant(this, exportedElements != null));
    var builder = new LinkBuilder<Element>();
    for (Element export in exportedElements) {
      builder.addLast(export);
    }
    slotForExports = builder.toLink();
  }

  LibraryElement get library => isPatch ? origin : this;

  /**
   * Look up a top-level element in this library. The element could
   * potentially have been imported from another library. Returns
   * null if no such element exist and an [ErroneousElement] if multiple
   * elements have been imported.
   */
  Element find(String elementName) {
    Element result = localScope.lookup(elementName);
    if (result != null) return result;
    if (origin != null) {
      result = origin.localScope.lookup(elementName);
      if (result != null) return result;
    }
    result = importScope[elementName];
    if (result != null) return result;
    if (origin != null) {
      result = origin.importScope[elementName];
      if (result != null) return result;
    }
    return null;
  }

  /** Look up a top-level element in this library, but only look for
    * non-imported elements. Returns null if no such element exist. */
  Element findLocal(String elementName) {
    // TODO(johnniwinther): How to handle injected elements in the patch
    // library?
    Element result = localScope.lookup(elementName);
    if (result == null || result.library != this) return null;
    return result;
  }

  Element findExported(String elementName) {
    for (Link link = exports; !link.isEmpty; link = link.tail) {
      Element element = link.head;
      if (element.name == elementName) return element;
    }
    return null;
  }

  void forEachExport(f(Element element)) {
    exports.forEach((Element e) => f(e));
  }

  Link<Import> getImportsFor(Element element) => importers.getImports(element);

  void forEachLocalMember(f(Element element)) {
    if (isPatch) {
      // Patch libraries traverse both origin and injected members.
      origin.localMembers.forEach(f);

      void filterPatch(Element element) {
        if (!element.isPatch) {
          // Do not traverse the patch members.
          f(element);
        }
      }
      localMembers.forEach(filterPatch);
    } else {
      localMembers.forEach(f);
    }
  }

  Iterable<Element> getNonPrivateElementsInScope() {
    return localScope.values.where((Element element) {
      // At this point [localScope] only contains members so we don't need
      // to check for foreign or prefix elements.
      return !isPrivateName(element.name);
    });
  }

  bool hasLibraryName() => libraryTag != null;

  /**
   * Returns the library name, which is either the name given in the library tag
   * or the empty string if there is no library tag.
   */
  String getLibraryName() {
    if (libraryTag == null) return '';
    return libraryTag.name.toString();
  }

  /**
   * Returns the library name (as defined by the library tag) or for script
   * (which have no library tag) the script file name. The latter case is used
   * to private 'library name' for scripts to use for instance in dartdoc.
   *
   * Note: the returned filename will still be escaped ("a%20b.dart" instead of
   * "a b.dart").
   */
  String getLibraryOrScriptName() {
    if (libraryTag != null) {
      return libraryTag.name.toString();
    } else {
      // Use the file name as script name.
      String path = canonicalUri.path;
      return path.substring(path.lastIndexOf('/') + 1);
    }
  }

  Scope buildScope() => new LibraryScope(this);

  bool get isPlatformLibrary => canonicalUri.scheme == 'dart';

  bool get isPackageLibrary => canonicalUri.scheme == 'package';

  bool get isInternalLibrary =>
      isPlatformLibrary && canonicalUri.path.startsWith('_');

  String toString() {
    if (origin != null) {
      return 'patch library(${canonicalUri})';
    } else if (patch != null) {
      return 'origin library(${canonicalUri})';
    } else {
      return 'library(${canonicalUri})';
    }
  }

  int compareTo(LibraryElement other) {
    if (this == other) return 0;
    return getLibraryOrScriptName().compareTo(other.getLibraryOrScriptName());
  }

  accept(ElementVisitor visitor) => visitor.visitLibraryElement(this);

  // TODO(johnniwinther): Remove these when issue 18630 is fixed.
  LibraryElementX get patch => super.patch;
  LibraryElementX get origin => super.origin;
}

class PrefixElementX extends ElementX implements PrefixElement {
  Token firstPosition;

  final ImportScope importScope = new ImportScope();

  bool get isDeferred => _deferredImport != null;

  // Only needed for deferred imports.
  Import _deferredImport;
  Import get deferredImport => _deferredImport;

  PrefixElementX(String prefix, Element enclosing, this.firstPosition)
      : super(prefix, ElementKind.PREFIX, enclosing);

  bool get isTopLevel => false;

  Element lookupLocalMember(String memberName) => importScope[memberName];

  DartType computeType(Compiler compiler) => const DynamicType();

  Token get position => firstPosition;

  void addImport(Element element, Import import, DiagnosticListener listener) {
    importScope.addImport(this, element, import, listener);
  }

  accept(ElementVisitor visitor) => visitor.visitPrefixElement(this);

  void markAsDeferred(Import deferredImport) {
    _deferredImport = deferredImport;
  }
}

class TypedefElementX extends ElementX
    with AstElementMixin,
         AnalyzableElementX,
         TypeDeclarationElementX<TypedefType>
    implements TypedefElement {
  Typedef cachedNode;

  /**
   * The type annotation which defines this typedef.
   */
  DartType alias;

  /// [:true:] if the typedef has been checked for cyclic reference.
  bool hasBeenCheckedForCycles = false;

  int resolutionState = STATE_NOT_STARTED;

  TypedefElementX(String name, Element enclosing)
      : super(name, ElementKind.TYPEDEF, enclosing);

  bool get hasNode => cachedNode != null;

  Typedef get node {
    assert(invariant(this, cachedNode != null,
        message: "Node has not been computed for $this."));
    return cachedNode;
  }

  /**
   * Function signature for a typedef of a function type. The signature is
   * kept to provide full information about parameter names through the mirror
   * system.
   *
   * The [functionSignature] is not available until the typedef element has been
   * resolved.
   */
  FunctionSignature functionSignature;

  TypedefType computeType(Compiler compiler) {
    if (thisTypeCache != null) return thisTypeCache;
    Typedef node = parseNode(compiler);
    setThisAndRawTypes(compiler, createTypeVariables(node.typeParameters));
    ensureResolved(compiler);
    return thisTypeCache;
  }

  void ensureResolved(Compiler compiler) {
    if (resolutionState == STATE_NOT_STARTED) {
      compiler.resolver.resolve(this);
    }
  }

  TypedefType createType(List<DartType> typeArguments) {
    return new TypedefType(this, typeArguments);
  }

  Scope buildScope() {
    return new TypeDeclarationScope(enclosingElement.buildScope(), this);
  }

  void checkCyclicReference(Compiler compiler) {
    if (hasBeenCheckedForCycles) return;
    var visitor = new TypedefCyclicVisitor(compiler, this);
    computeType(compiler).accept(visitor, null);
    hasBeenCheckedForCycles = true;
  }

  accept(ElementVisitor visitor) => visitor.visitTypedefElement(this);

  // A typedef cannot be patched therefore defines itself.
  AstElement get definingElement => this;
}

// This class holds common information for a list of variable or field
// declarations. It contains the node, and the type. A [VariableElementX]
// forwards its [computeType] and [parseNode] methods to this class.
class VariableList implements DeclarationSite {
  VariableDefinitions definitions;
  DartType type;
  final Modifiers modifiers;
  Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>();

  VariableList(Modifiers this.modifiers);

  VariableList.node(VariableDefinitions node, this.type)
      : this.definitions = node,
        this.modifiers = node.modifiers {
    assert(modifiers != null);
  }

  VariableDefinitions parseNode(Element element, DiagnosticListener listener) {
    return definitions;
  }

  DartType computeType(Element element, Compiler compiler) => type;
}

abstract class VariableElementX extends ElementX with AstElementMixin
    implements VariableElement {
  final Token token;
  final VariableList variables;
  VariableDefinitions definitionsCache;
  Expression initializerCache;

  Modifiers get modifiers => variables.modifiers;

  VariableElementX(String name,
                   ElementKind kind,
                   Element enclosingElement,
                   VariableList variables,
                   this.token)
    : this.variables = variables,
      super(name, kind, enclosingElement);

  // TODO(johnniwinther): Ensure that the [TreeElements] for this variable hold
  // the mappings for all its metadata.
  Link<MetadataAnnotation> get metadata => variables.metadata;

  void addMetadataInternal(MetadataAnnotation annotation) {
    variables.metadata = variables.metadata.prepend(annotation);
  }

  // A variable cannot be patched therefore defines itself.
  AstElement get definingElement => this;

  bool get hasNode => definitionsCache != null;

  VariableDefinitions get node {
    assert(invariant(this, definitionsCache != null,
        message: "Node has not been computed for $this."));
    return definitionsCache;
  }

  Expression get initializer {
    assert(invariant(this, definitionsCache != null,
        message: "Initializer has not been computed for $this."));
    return initializerCache;
  }

  Node parseNode(DiagnosticListener listener) {
    if (definitionsCache != null) return definitionsCache;

    VariableDefinitions definitions = variables.parseNode(this, listener);
    createDefinitions(definitions);
    return definitionsCache;
  }

  void createDefinitions(VariableDefinitions definitions) {
    assert(invariant(this, definitionsCache == null,
        message: "VariableDefinitions has already been computed for $this."));
    Expression node;
    int count = 0;
    for (Link<Node> link = definitions.definitions.nodes;
         !link.isEmpty; link = link.tail) {
      Expression initializedIdentifier = link.head;
      Identifier identifier = initializedIdentifier.asIdentifier();
      if (identifier == null) {
        SendSet sendSet = initializedIdentifier.asSendSet();
        identifier = sendSet.selector.asIdentifier();
        if (identical(name, identifier.source)) {
          node = initializedIdentifier;
          initializerCache = sendSet.arguments.first;
        }
      } else if (identical(name, identifier.source)) {
        node = initializedIdentifier;
      }
      count++;
    }
    invariant(definitions, node != null, message: "Could not find '$name'.");
    if (count == 1) {
      definitionsCache = definitions;
    } else {
      // Create a [VariableDefinitions] node for the single definition of
      // [node].
      definitionsCache = new VariableDefinitions(definitions.type,
          definitions.modifiers, new NodeList(
              definitions.definitions.beginToken,
              const Link<Node>().prepend(node),
              definitions.definitions.endToken));
    }
  }

  DartType computeType(Compiler compiler) {
    if (variables.type != null) return variables.type;
    // Call [parseNode] to ensure that [definitionsCache] and [initializerCache]
    // are set as a consequence of calling [computeType].
    return compiler.withCurrentElement(this, () {
      parseNode(compiler);
      return variables.computeType(this, compiler);
    });
  }

  DartType get type {
    assert(invariant(this, variables.type != null,
        message: "Type has not been computed for $this."));
    return variables.type;
  }

  bool get isInstanceMember => isClassMember && !isStatic;

  // Note: cachedNode.beginToken will not be correct in all
  // cases, for example, for function typed parameters.
  Token get position => token;

  accept(ElementVisitor visitor) => visitor.visitVariableElement(this);

  DeclarationSite get declarationSite => variables;
}

class LocalVariableElementX extends VariableElementX
    implements LocalVariableElement {
  LocalVariableElementX(String name,
                        ExecutableElement enclosingElement,
                        VariableList variables,
                        Token token)
      : super(name, ElementKind.VARIABLE, enclosingElement, variables, token) {
    createDefinitions(variables.definitions);
  }

  // TODO(johnniwinther): Remove this when the dart `backend_ast` does not need
  // [Element] for entities.
  LocalVariableElementX.synthetic(String name,
                                  ExecutableElement enclosingElement,
                                  VariableList variables)
      : super(name, ElementKind.VARIABLE, enclosingElement, variables, null);

  ExecutableElement get executableContext => enclosingElement;

  ExecutableElement get memberContext => executableContext.memberContext;

  bool get isLocal => true;
}

class FieldElementX extends VariableElementX
    with AnalyzableElementX implements FieldElement {
  List<FunctionElement> nestedClosures = new List<FunctionElement>();

  FieldElementX(Identifier name,
                Element enclosingElement,
                VariableList variables)
    : super(name.source, ElementKind.FIELD, enclosingElement,
            variables, name.token);

  accept(ElementVisitor visitor) => visitor.visitFieldElement(this);

  MemberElement get memberContext => this;

  void reuseElement() {
    super.reuseElement();
    nestedClosures.clear();
  }
}

/// [Element] for a parameter-like element.
class FormalElementX extends ElementX
    with AstElementMixin
    implements FormalElement {
  final VariableDefinitions definitions;
  final Identifier identifier;
  DartType typeCache;

  /**
   * Function signature for a variable with a function type. The signature is
   * kept to provide full information about parameter names through the mirror
   * system.
   */
  FunctionSignature functionSignatureCache;

  FormalElementX(ElementKind elementKind,
                 FunctionTypedElement enclosingElement,
                 this.definitions,
                 Identifier identifier)
      : this.identifier = identifier,
        super(identifier.source, elementKind, enclosingElement);

  FunctionTypedElement get functionDeclaration => enclosingElement;

  Modifiers get modifiers => definitions.modifiers;

  Token get position => identifier.getBeginToken();

  Node parseNode(DiagnosticListener listener) => definitions;

  DartType computeType(Compiler compiler) {
    assert(invariant(this, type != null,
        message: "Parameter type has not been set for $this."));
    return type;
  }

  DartType get type {
    assert(invariant(this, typeCache != null,
            message: "Parameter type has not been set for $this."));
        return typeCache;
  }

  FunctionSignature get functionSignature {
    assert(invariant(this, typeCache != null,
            message: "Parameter signature has not been set for $this."));
    return functionSignatureCache;
  }

  bool get hasNode => true;

  VariableDefinitions get node => definitions;

  FunctionType get functionType => type;

  accept(ElementVisitor visitor) => visitor.visitFormalElement(this);

  // A parameter is defined by the declaration element.
  AstElement get definingElement => declaration;
}

/// [Element] for a formal parameter.
///
/// A [ParameterElementX] can be patched. A parameter of an external method is
/// patched with the corresponding parameter of the patch method. This is done
/// to ensure that default values on parameters are computed once (on the
/// origin parameter) but can be found through both the origin and the patch.
abstract class ParameterElementX extends FormalElementX
  with PatchMixin<ParameterElement> implements ParameterElement {
  final Expression initializer;

  ParameterElementX(ElementKind elementKind,
                    FunctionElement functionDeclaration,
                    VariableDefinitions definitions,
                    Identifier identifier,
                    this.initializer)
      : super(elementKind, functionDeclaration, definitions, identifier);

  FunctionElement get functionDeclaration => enclosingElement;

  ExecutableElement get executableContext => enclosingElement;

  MemberElement get memberContext => executableContext.memberContext;

  accept(ElementVisitor visitor) => visitor.visitParameterElement(this);

  bool get isLocal => true;
}

class LocalParameterElementX extends ParameterElementX
    implements LocalParameterElement {
  LocalParameterElementX(FunctionElement functionDeclaration,
                         VariableDefinitions definitions,
                         Identifier identifier,
                         Expression initializer)
      : super(ElementKind.PARAMETER, functionDeclaration,
              definitions, identifier, initializer);
}

/// Parameters in constructors that directly initialize fields. For example:
/// `A(this.field)`.
class InitializingFormalElementX extends ParameterElementX
    implements InitializingFormalElement {
  FieldElement fieldElement;

  InitializingFormalElementX(ConstructorElement constructorDeclaration,
                             VariableDefinitions variables,
                             Identifier identifier,
                             Expression initializer,
                             this.fieldElement)
      : super(ElementKind.INITIALIZING_FORMAL, constructorDeclaration,
              variables, identifier, initializer);

  accept(ElementVisitor visitor) => visitor.visitFieldParameterElement(this);

  MemberElement get memberContext => enclosingElement;

  bool get isLocal => false;
}


class AbstractFieldElementX extends ElementX implements AbstractFieldElement {
  FunctionElementX getter;
  FunctionElementX setter;

  AbstractFieldElementX(String name, Element enclosing)
      : super(name, ElementKind.ABSTRACT_FIELD, enclosing);

  DartType computeType(Compiler compiler) {
    throw "internal error: AbstractFieldElement has no type";
  }

  Node parseNode(DiagnosticListener listener) {
    throw "internal error: AbstractFieldElement has no node";
  }

  Token get position {
    // The getter and setter may be defined in two different
    // compilation units.  However, we know that one of them is
    // non-null and defined in the same compilation unit as the
    // abstract element.
    // TODO(lrn): No we don't know that if the element from the same
    // compilation unit is patched.
    //
    // We need to make sure that the position returned is relative to
    // the compilation unit of the abstract element.
    if (getter != null
        && identical(getter.compilationUnit, compilationUnit)) {
      return getter.position;
    } else {
      return setter.position;
    }
  }

  Modifiers get modifiers {
    // The resolver ensures that the flags match (ignoring abstract).
    if (getter != null) {
      return new Modifiers.withFlags(
          getter.modifiers.nodes,
          getter.modifiers.flags | Modifiers.FLAG_ABSTRACT);
    } else {
      return new Modifiers.withFlags(
          setter.modifiers.nodes,
          setter.modifiers.flags | Modifiers.FLAG_ABSTRACT);
    }
  }

  bool get isInstanceMember {
    return isClassMember && !isStatic;
  }

  accept(ElementVisitor visitor) => visitor.visitAbstractFieldElement(this);

  bool get isAbstract {
    return getter != null && getter.isAbstract
        || setter != null && setter.isAbstract;
  }
}

// TODO(johnniwinther): [FunctionSignature] should be merged with
// [FunctionType].
// TODO(karlklose): all these lists should have element type [FormalElement].
class FunctionSignatureX implements FunctionSignature {
  final Link<Element> requiredParameters;
  final Link<Element> optionalParameters;
  final int requiredParameterCount;
  final int optionalParameterCount;
  final bool optionalParametersAreNamed;
  final List<Element> orderedOptionalParameters;
  final FunctionType type;
  final bool hasOptionalParameters;

  FunctionSignatureX(this.requiredParameters,
                     Link<Element> optionalParameters,
                     this.requiredParameterCount,
                     this.optionalParameterCount,
                     this.optionalParametersAreNamed,
                     this.orderedOptionalParameters,
                     this.type)
      : optionalParameters = optionalParameters,
        hasOptionalParameters = !optionalParameters.isEmpty;

  void forEachRequiredParameter(void function(Element parameter)) {
    for (Link<Element> link = requiredParameters;
         !link.isEmpty;
         link = link.tail) {
      function(link.head);
    }
  }

  void forEachOptionalParameter(void function(Element parameter)) {
    for (Link<Element> link = optionalParameters;
         !link.isEmpty;
         link = link.tail) {
      function(link.head);
    }
  }

  Element get firstOptionalParameter => optionalParameters.head;

  void forEachParameter(void function(Element parameter)) {
    forEachRequiredParameter(function);
    forEachOptionalParameter(function);
  }

  void orderedForEachParameter(void function(Element parameter)) {
    forEachRequiredParameter(function);
    orderedOptionalParameters.forEach(function);
  }

  int get parameterCount => requiredParameterCount + optionalParameterCount;

  /**
   * Check whether a function with this signature can be used instead of a
   * function with signature [signature] without causing a `noSuchMethod`
   * exception/call.
   */
  bool isCompatibleWith(FunctionSignature signature) {
    if (optionalParametersAreNamed) {
      if (!signature.optionalParametersAreNamed) {
        return requiredParameterCount == signature.parameterCount;
      }
      // If both signatures have named parameters, then they must have
      // the same number of required parameters, and the names in
      // [signature] must all be in [:this:].
      if (requiredParameterCount != signature.requiredParameterCount) {
        return false;
      }
      Set<String> names = optionalParameters.mapToSet(
          (Element element) => element.name);
      for (Element namedParameter in signature.optionalParameters) {
        if (!names.contains(namedParameter.name)) {
          return false;
        }
      }
    } else {
      if (signature.optionalParametersAreNamed) return false;
      // There must be at least as many arguments as in the other signature, but
      // this signature must not have more required parameters.  Having more
      // optional parameters is not a problem, they simply are never provided
      // by call sites of a call to a method with the other signature.
      int otherTotalCount = signature.parameterCount;
      return requiredParameterCount <= otherTotalCount
          && parameterCount >= otherTotalCount;
    }
    return true;
  }
}

abstract class BaseFunctionElementX
    extends ElementX with PatchMixin<FunctionElement>, AstElementMixin
    implements FunctionElement {
  DartType typeCache;
  final Modifiers modifiers;

  List<FunctionElement> nestedClosures = new List<FunctionElement>();

  FunctionSignature functionSignatureCache;

  final bool _hasNoBody;

  AbstractFieldElement abstractField;

  BaseFunctionElementX(String name,
                       ElementKind kind,
                       Modifiers this.modifiers,
                       Element enclosing,
                       bool hasNoBody)
      : super(name, kind, enclosing),
        _hasNoBody = hasNoBody {
    assert(modifiers != null);
  }

  bool get isInstanceMember {
    return isClassMember
           && !isConstructor
           && !isStatic;
  }

  bool get hasFunctionSignature => functionSignatureCache != null;

  FunctionSignature computeSignature(Compiler compiler) {
    if (functionSignatureCache != null) return functionSignatureCache;
    compiler.withCurrentElement(this, () {
      functionSignatureCache = compiler.resolver.resolveSignature(this);
    });
    return functionSignatureCache;
  }

  FunctionSignature get functionSignature {
    assert(invariant(this, functionSignatureCache != null,
        message: "Function signature has not been computed for $this."));
    return functionSignatureCache;
  }

  FunctionType computeType(Compiler compiler) {
    if (typeCache != null) return typeCache;
    typeCache = computeSignature(compiler).type;
    return typeCache;
  }

  FunctionType get type {
    assert(invariant(this, typeCache != null,
        message: "Type has not been computed for $this."));
    return typeCache;
  }

  FunctionElement asFunctionElement() => this;

  String toString() {
    if (isPatch) {
      return 'patch ${super.toString()}';
    } else if (isPatched) {
      return 'origin ${super.toString()}';
    } else {
      return super.toString();
    }
  }

  bool get isAbstract {
    return !modifiers.isExternal &&
           (isFunction || isAccessor) &&
           _hasNoBody;
  }

  accept(ElementVisitor visitor) => visitor.visitFunctionElement(this);

  // A function is defined by the implementation element.
  AstElement get definingElement => implementation;
}

abstract class FunctionElementX extends BaseFunctionElementX
    with AnalyzableElementX implements MemberElement {
  FunctionElementX(String name,
                   ElementKind kind,
                   Modifiers modifiers,
                   Element enclosing,
                   bool hasNoBody)
      : super(name, kind, modifiers, enclosing, hasNoBody);

  MemberElement get memberContext => this;

  void reuseElement() {
    super.reuseElement();
    nestedClosures.clear();
    functionSignatureCache = null;
    typeCache = null;
  }
}

class LocalFunctionElementX extends BaseFunctionElementX
    implements LocalFunctionElement {
  final FunctionExpression node;

  LocalFunctionElementX(String name,
                        FunctionExpression this.node,
                        ElementKind kind,
                        Modifiers modifiers,
                        ExecutableElement enclosing)
      : super(name, kind, modifiers, enclosing, false);

  ExecutableElement get executableContext => enclosingElement;

  MemberElement get memberContext => executableContext.memberContext;

  bool get hasNode => true;

  FunctionExpression parseNode(DiagnosticListener listener) => node;

  Token get position {
    // Use the name as position if this is not an unnamed closure.
    if (node.name != null) {
      return node.name.getBeginToken();
    } else {
      return node.getBeginToken();
    }
  }

  bool get isLocal => true;
}

abstract class ConstructorElementX extends FunctionElementX
    implements ConstructorElement {

  ConstructorElementX(String name,
                      ElementKind kind,
                      Modifiers modifiers,
                      Element enclosing)
        : super(name, kind, modifiers, enclosing, false);

  FunctionElement immediateRedirectionTarget;

  bool get isRedirectingFactory => immediateRedirectionTarget != null;

  /// This field is set by the post process queue when checking for cycles.
  ConstructorElement internalEffectiveTarget;
  DartType effectiveTargetType;

  void set effectiveTarget(ConstructorElement constructor) {
    assert(constructor != null && internalEffectiveTarget == null);
    internalEffectiveTarget = constructor;
  }

  ConstructorElement get effectiveTarget {
    if (Elements.isErroneousElement(immediateRedirectionTarget)) {
      return immediateRedirectionTarget;
    }
    assert(!isRedirectingFactory || internalEffectiveTarget != null);
    return isRedirectingFactory ? internalEffectiveTarget : this;
  }

  InterfaceType computeEffectiveTargetType(InterfaceType newType) {
    if (!isRedirectingFactory) return newType;
    assert(invariant(this, effectiveTargetType != null,
        message: 'Redirection target type has not yet been computed for '
                 '$this.'));
    return effectiveTargetType.substByContext(newType);
  }

  ConstructorElement get definingConstructor => null;

  ClassElement get enclosingClass => enclosingElement;
}

class DeferredLoaderGetterElementX extends FunctionElementX {
  final PrefixElement prefix;

  DeferredLoaderGetterElementX(PrefixElement prefix)
      : this.prefix = prefix,
        super("loadLibrary",
              ElementKind.FUNCTION,
              Modifiers.EMPTY,
              prefix, true);

  FunctionSignature computeSignature(Compiler compiler) {
    if (functionSignatureCache != null) return functionSignature;
    compiler.withCurrentElement(this, () {
      DartType inner = new FunctionType(this);
      functionSignatureCache = new FunctionSignatureX(const Link(),
          const Link(), 0, 0, false, [], inner);
    });
    return functionSignatureCache;
  }

  bool get isClassMember => false;

  bool isForeign(Backend backend) => true;

  bool get isSynthesized => true;

  bool get isFunction => false;

  bool get isDeferredLoaderGetter => true;

  bool get isGetter => true;

  bool get isTopLevel => true;
  // By having position null, the enclosing elements location is printed in
  // error messages.
  Token get position => null;

  FunctionExpression parseNode(DiagnosticListener listener) => null;

  bool get hasNode => false;

  FunctionExpression get node => null;
}

class ConstructorBodyElementX extends BaseFunctionElementX
    implements ConstructorBodyElement {
  ConstructorElement constructor;

  ConstructorBodyElementX(FunctionElement constructor)
      : this.constructor = constructor,
        super(constructor.name,
              ElementKind.GENERATIVE_CONSTRUCTOR_BODY,
              Modifiers.EMPTY,
              constructor.enclosingElement, false) {
    functionSignatureCache = constructor.functionSignature;
  }

  bool get hasNode => constructor.hasNode;

  FunctionExpression get node => constructor.node;

  bool get isInstanceMember => true;

  FunctionType computeType(Compiler compiler) {
    compiler.internalError(this, '$this.computeType.');
    return null;
  }

  Token get position => constructor.position;

  Element get outermostEnclosingMemberOrTopLevel => constructor;

  Element get analyzableElement => constructor.analyzableElement;

  accept(ElementVisitor visitor) => visitor.visitConstructorBodyElement(this);

  MemberElement get memberContext => constructor;
}

/**
 * A constructor that is not defined in the source code but rather implied by
 * the language semantics.
 *
 * This class is used to represent default constructors and forwarding
 * constructors for mixin applications.
 */
class SynthesizedConstructorElementX extends ConstructorElementX {
  final ConstructorElement definingConstructor;
  final bool isDefaultConstructor;

  SynthesizedConstructorElementX(String name,
                                 this.definingConstructor,
                                 Element enclosing,
                                 this.isDefaultConstructor)
      : super(name,
              ElementKind.GENERATIVE_CONSTRUCTOR,
              Modifiers.EMPTY,
              enclosing);

  SynthesizedConstructorElementX.forDefault(superMember, Element enclosing)
      : this('', superMember, enclosing, true);

  FunctionExpression parseNode(DiagnosticListener listener) => null;

  bool get hasNode => false;

  FunctionExpression get node => null;

  Token get position => enclosingElement.position;

  bool get isSynthesized => true;

  FunctionSignature computeSignature(compiler) {
    if (functionSignatureCache != null) return functionSignatureCache;
    if (isDefaultConstructor) {
      return functionSignatureCache = new FunctionSignatureX(
          const Link<Element>(), const Link<Element>(), 0, 0, false,
          const <Element>[],
          new FunctionType(this, enclosingClass.thisType));
    }
    if (definingConstructor.isErroneous) {
      return functionSignatureCache =
          compiler.objectClass.localLookup('').computeSignature(compiler);
    }
    // TODO(johnniwinther): Ensure that the function signature (and with it the
    // function type) substitutes type variables correctly.
    return functionSignatureCache =
        definingConstructor.computeSignature(compiler);
  }

  accept(ElementVisitor visitor) {
    return visitor.visitFunctionElement(this);
  }
}

abstract class TypeDeclarationElementX<T extends GenericType>
    implements TypeDeclarationElement {
  /**
   * The `this type` for this type declaration.
   *
   * The type of [:this:] is the generic type based on this element in which
   * the type arguments are the declared type variables. For instance,
   * [:List<E>:] for [:List:] and [:Map<K,V>:] for [:Map:].
   *
   * For a class declaration this is the type of [:this:].
   *
   * This type is computed in [computeType].
   */
  T thisTypeCache;

  /**
   * The raw type for this type declaration.
   *
   * The raw type is the generic type base on this element in which the type
   * arguments are all [dynamic]. For instance [:List<dynamic>:] for [:List:]
   * and [:Map<dynamic,dynamic>:] for [:Map:]. For non-generic classes [rawType]
   * is the same as [thisType].
   *
   * The [rawType] field is a canonicalization of the raw type and should be
   * used to distinguish explicit and implicit uses of the [dynamic]
   * type arguments. For instance should [:List:] be the [rawType] of the
   * [:List:] class element whereas [:List<dynamic>:] should be its own
   * instantiation of [InterfaceType] with [:dynamic:] as type argument. Using
   * this distinction, we can print the raw type with type arguments only when
   * the input source has used explicit type arguments.
   *
   * This type is computed together with [thisType] in [computeType].
   */
  T rawTypeCache;

  T get thisType {
    assert(invariant(this, thisTypeCache != null,
                     message: 'This type has not been computed for $this'));
    return thisTypeCache;
  }

  T get rawType {
    assert(invariant(this, rawTypeCache != null,
                     message: 'Raw type has not been computed for $this'));
    return rawTypeCache;
  }

  T createType(List<DartType> typeArguments);

  void setThisAndRawTypes(Compiler compiler, List<DartType> typeParameters) {
    assert(invariant(this, thisTypeCache == null,
        message: "This type has already been set on $this."));
    assert(invariant(this, rawTypeCache == null,
        message: "Raw type has already been set on $this."));
    thisTypeCache = createType(typeParameters);
    if (typeParameters.isEmpty) {
      rawTypeCache = thisTypeCache;
    } else {
      List<DartType> dynamicParameters =
          new List.filled(typeParameters.length, const DynamicType());
      rawTypeCache = createType(dynamicParameters);
    }
  }

  List<DartType> get typeVariables => thisType.typeArguments;

  /**
   * Creates the type variables, their type and corresponding element, for the
   * type variables declared in [parameter] on [element]. The bounds of the type
   * variables are not set until [element] has been resolved.
   */
  List<DartType> createTypeVariables(NodeList parameters) {
    if (parameters == null) return const <DartType>[];

    // Create types and elements for type variable.
    Link<Node> nodes = parameters.nodes;
    List<DartType> arguments =
        new List.generate(nodes.slowLength(), (_) {
      TypeVariable node = nodes.head;
      String variableName = node.name.source;
      nodes = nodes.tail;
      TypeVariableElementX variableElement =
          new TypeVariableElementX(variableName, this, node);
      TypeVariableType variableType = new TypeVariableType(variableElement);
      variableElement.typeCache = variableType;
      return variableType;
    }, growable: false);
    return arguments;
  }

  bool get isResolved => resolutionState == STATE_DONE;
}

abstract class BaseClassElementX extends ElementX
    with AstElementMixin,
         AnalyzableElementX,
         TypeDeclarationElementX<InterfaceType>,
         PatchMixin<ClassElement>,
         ClassMemberMixin
    implements ClassElement {
  final int id;

  DartType supertype;
  Link<DartType> interfaces;
  String nativeTagInfo;
  int supertypeLoadState;
  int resolutionState;
  bool isProxy = false;
  bool hasIncompleteHierarchy = false;

  // backendMembers are members that have been added by the backend to simplify
  // compilation. They don't have any user-side counter-part.
  Link<Element> backendMembers = const Link<Element>();

  OrderedTypeSet allSupertypesAndSelf;

  Link<DartType> get allSupertypes => allSupertypesAndSelf.supertypes;

  int get hierarchyDepth => allSupertypesAndSelf.maxDepth;

  BaseClassElementX(String name,
                    Element enclosing,
                    this.id,
                    int initialState)
      : supertypeLoadState = initialState,
        resolutionState = initialState,
        super(name, ElementKind.CLASS, enclosing);

  int get hashCode => id;

  bool get hasBackendMembers => !backendMembers.isEmpty;

  bool get isUnnamedMixinApplication => false;

  InterfaceType computeType(Compiler compiler) {
    if (thisTypeCache == null) {
      computeThisAndRawType(compiler, computeTypeParameters(compiler));
    }
    return thisTypeCache;
  }

  void computeThisAndRawType(Compiler compiler, List<DartType> typeVariables) {
    if (thisTypeCache == null) {
      if (origin == null) {
        setThisAndRawTypes(compiler, typeVariables);
      } else {
        thisTypeCache = origin.computeType(compiler);
        rawTypeCache = origin.rawType;
      }
    }
  }

  InterfaceType createType(List<DartType> typeArguments) {
    return new InterfaceType(this, typeArguments);
  }

  List<DartType> computeTypeParameters(Compiler compiler);

  InterfaceType asInstanceOf(ClassElement cls) {
    if (cls == this) return thisType;
    return allSupertypesAndSelf.asInstanceOf(cls);
  }

  bool get isObject {
    assert(invariant(this, isResolved,
        message: "isObject has not been computed for $this."));
    return supertype == null;
  }

  void ensureResolved(Compiler compiler) {
    if (resolutionState == STATE_NOT_STARTED) {
      compiler.resolver.resolveClass(this);
    }
  }

  void setDefaultConstructor(FunctionElement constructor, Compiler compiler);

  void addBackendMember(Element member) {
    // TODO(ngeoffray): Deprecate this method.
    assert(member.isGenerativeConstructorBody);
    backendMembers = backendMembers.prepend(member);
  }

  void reverseBackendMembers() {
    backendMembers = backendMembers.reverse();
  }

  /**
   * Lookup local members in the class. This will ignore constructors.
   */
  Element lookupLocalMember(String memberName) {
    var result = localLookup(memberName);
    if (result != null && result.isConstructor) return null;
    return result;
  }

  /// Lookup a synthetic element created by the backend.
  Element lookupBackendMember(String memberName) {
    for (Element element in backendMembers) {
      if (element.name == memberName) {
        return element;
      }
    }
    return null;
  }
  /**
   * Lookup super members for the class. This will ignore constructors.
   */
  Element lookupSuperMember(String memberName) {
    return lookupSuperMemberInLibrary(memberName, library);
  }

  /**
   * Lookup super members for the class that is accessible in [library].
   * This will ignore constructors.
   */
  Element lookupSuperMemberInLibrary(String memberName,
                                     LibraryElement library) {
    bool isPrivate = isPrivateName(memberName);
    for (ClassElement s = superclass; s != null; s = s.superclass) {
      // Private members from a different library are not visible.
      if (isPrivate && !identical(library, s.library)) continue;
      Element e = s.lookupLocalMember(memberName);
      if (e == null) continue;
      // Static members are not inherited.
      if (e.isStatic) continue;
      return e;
    }
    return null;
  }

  /**
   * Find the first member in the class chain with the given [selector].
   *
   * This method is NOT to be used for resolving
   * unqualified sends because it does not implement the scoping
   * rules, where library scope comes before superclass scope.
   *
   * When called on the implementation element both members declared in the
   * origin and the patch class are returned.
   */
  Element lookupSelector(Selector selector) {
    return internalLookupSelector(selector, false);
  }

  Element lookupSuperSelector(Selector selector) {
    return internalLookupSelector(selector, true);
  }

  Element internalLookupSelector(Selector selector,
                                 bool isSuperLookup) {
    String name = selector.name;
    bool isPrivate = isPrivateName(name);
    LibraryElement library = selector.library;
    for (ClassElement current = isSuperLookup ? superclass : this;
         current != null;
         current = current.superclass) {
      Element member = current.lookupLocalMember(name);
      if (member == null && current.isPatched) {
        // Doing lookups on selectors is done after resolution, so it
        // is safe to look in the patch class.
        member = current.patch.lookupLocalMember(name);
      }
      if (member == null) continue;
      // Private members from a different library are not visible.
      if (isPrivate && !identical(library, member.library)) continue;
      // Static members are not inherited.
      if (member.isStatic && !identical(this, current)) continue;
      // If we find an abstract field we have to make sure that it has
      // the getter or setter part we're actually looking
      // for. Otherwise, we continue up the superclass chain.
      if (member.isAbstractField) {
        AbstractFieldElement field = member;
        FunctionElement getter = field.getter;
        FunctionElement setter = field.setter;
        if (selector.isSetter) {
          // Abstract members can be defined in a super class.
          if (setter != null && !setter.isAbstract) return setter;
        } else {
          assert(selector.isGetter || selector.isCall);
          if (getter != null && !getter.isAbstract) return getter;
        }
      // Abstract members can be defined in a super class.
      } else if (!member.isAbstract) {
        return member;
      }
    }
    return null;
  }

  /**
   * Find the first member in the class chain with the given
   * [memberName]. This method is NOT to be used for resolving
   * unqualified sends because it does not implement the scoping
   * rules, where library scope comes before superclass scope.
   */
  Element lookupMember(String memberName) {
    Element localMember = lookupLocalMember(memberName);
    return localMember == null ? lookupSuperMember(memberName) : localMember;
  }

  /**
   * Returns true if the [fieldMember] shadows another field.  The given
   * [fieldMember] must be a member of this class, i.e. if there is a field of
   * the same name in the superclass chain.
   *
   * This method also works if the [fieldMember] is private.
   */
  bool hasFieldShadowedBy(Element fieldMember) {
    assert(fieldMember.isField);
    String fieldName = fieldMember.name;
    bool isPrivate = isPrivateName(fieldName);
    LibraryElement memberLibrary = fieldMember.library;
    ClassElement lookupClass = this.superclass;
    while (lookupClass != null) {
      Element foundMember = lookupClass.lookupLocalMember(fieldName);
      if (foundMember != null) {
        if (foundMember.isField) {
          if (!isPrivate || memberLibrary == foundMember.library) {
            // Private fields can only be shadowed by a field declared in the
            // same library.
            return true;
          }
        }
      }
      lookupClass = lookupClass.superclass;
    }
    return false;
  }

  Element validateConstructorLookupResults(Selector selector,
                                           Element result,
                                           Element noMatch(Element)) {
    if (result == null
        || !result.isConstructor
        || (isPrivateName(selector.name)
            && result.library != selector.library)) {
      result = noMatch != null ? noMatch(result) : null;
    }
    return result;
  }

  // TODO(aprelev@gmail.com): Peter believes that it would be great to
  // make noMatch a required argument. Peter's suspicion is that most
  // callers of this method would benefit from using the noMatch method.
  Element lookupConstructor(Selector selector, [Element noMatch(Element)]) {
    Element result = localLookup(selector.name);
    return validateConstructorLookupResults(selector, result, noMatch);
  }

  Link<Element> get constructors {
    // TODO(ajohnsen): See if we can avoid this method at some point.
    Link<Element> result = const Link<Element>();
    // TODO(johnniwinther): Should we include injected constructors?
    forEachMember((_, Element member) {
      if (member.isConstructor) result = result.prepend(member);
    });
    return result;
  }

  /**
   * Returns the super class, if any.
   *
   * The returned element may not be resolved yet.
   */
  ClassElement get superclass {
    assert(supertypeLoadState == STATE_DONE);
    return supertype == null ? null : supertype.element;
  }

  /**
   * Runs through all members of this class.
   *
   * The enclosing class is passed to the callback. This is useful when
   * [includeSuperAndInjectedMembers] is [:true:].
   *
   * When called on an implementation element both the members in the origin
   * and patch class are included.
   */
  // TODO(johnniwinther): Clean up lookup to get rid of the include predicates.
  void forEachMember(void f(ClassElement enclosingClass, Element member),
                     {includeBackendMembers: false,
                      includeSuperAndInjectedMembers: false}) {
    bool includeInjectedMembers = includeSuperAndInjectedMembers || isPatch;
    ClassElement classElement = declaration;
    do {
      // Iterate through the members in textual order, which requires
      // to reverse the data structure [localMembers] we created.
      // Textual order may be important for certain operations, for
      // example when emitting the initializers of fields.
      classElement.forEachLocalMember((e) => f(classElement, e));
      if (includeBackendMembers) {
        classElement.forEachBackendMember((e) => f(classElement, e));
      }
      if (includeInjectedMembers) {
        if (classElement.patch != null) {
          classElement.patch.forEachLocalMember((e) {
            if (!e.isPatch) f(classElement, e);
          });
        }
      }
      classElement = includeSuperAndInjectedMembers
          ? classElement.superclass
          : null;
    } while (classElement != null);
  }

  /**
   * Runs through all instance-field members of this class.
   *
   * The enclosing class is passed to the callback. This is useful when
   * [includeSuperAndInjectedMembers] is [:true:].
   *
   * When called on the implementation element both the fields declared in the
   * origin and in the patch are included.
   */
  void forEachInstanceField(void f(ClassElement enclosingClass,
                                   FieldElement field),
                            {bool includeSuperAndInjectedMembers: false}) {
    // Filters so that [f] is only invoked with instance fields.
    void fieldFilter(ClassElement enclosingClass, Element member) {
      if (member.isInstanceMember && member.kind == ElementKind.FIELD) {
        f(enclosingClass, member);
      }
    }

    forEachMember(fieldFilter,
        includeSuperAndInjectedMembers: includeSuperAndInjectedMembers);
  }

  /// Similar to [forEachInstanceField] but visits static fields.
  void forEachStaticField(void f(ClassElement enclosingClass, Element field)) {
    // Filters so that [f] is only invoked with static fields.
    void fieldFilter(ClassElement enclosingClass, Element member) {
      if (!member.isInstanceMember && member.kind == ElementKind.FIELD) {
        f(enclosingClass, member);
      }
    }

    forEachMember(fieldFilter);
  }

  void forEachBackendMember(void f(Element member)) {
    backendMembers.forEach(f);
  }

  bool implementsInterface(ClassElement intrface) {
    for (DartType implementedInterfaceType in allSupertypes) {
      ClassElement implementedInterface = implementedInterfaceType.element;
      if (identical(implementedInterface, intrface)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Returns true if [this] is a subclass of [cls].
   *
   * This method is not to be used for checking type hierarchy and
   * assignments, because it does not take parameterized types into
   * account.
   */
  bool isSubclassOf(ClassElement cls) {
    // Use [declaration] for both [this] and [cls], because
    // declaration classes hold the superclass hierarchy.
    cls = cls.declaration;
    for (ClassElement s = declaration; s != null; s = s.superclass) {
      if (identical(s, cls)) return true;
    }
    return false;
  }

  bool get isNative => nativeTagInfo != null;

  void setNative(String name) {
    // TODO(johnniwinther): Assert that this is only called once. The memory
    // compiler copies pre-processed elements into a new compiler through
    // [Compiler.onLibraryScanned] and thereby causes multiple calls to this
    // method.
    assert(invariant(this, nativeTagInfo == null || nativeTagInfo == name,
        message: "Native tag info set inconsistently on $this: "
                 "Existing name '$nativeTagInfo', new name '$name'."));
    nativeTagInfo = name;
  }

  FunctionType get callType {
    MemberSignature member =
        lookupInterfaceMember(const PublicName(Compiler.CALL_OPERATOR_NAME));
    return member != null && member.isMethod ? member.type : null;
  }

  // TODO(johnniwinther): Remove these when issue 18630 is fixed.
  ClassElement get patch => super.patch;
  ClassElement get origin => super.origin;

  // A class declaration is defined by the declaration element.
  AstElement get definingElement => declaration;
}

abstract class ClassElementX extends BaseClassElementX {
  Link<Element> localMembersReversed = const Link<Element>();
  final ScopeX localScope = new ScopeX();

  Link<Element> localMembersCache;

  Link<Element> get localMembers {
    if (localMembersCache == null) {
      localMembersCache = localMembersReversed.reverse();
    }
    return localMembersCache;
  }

  ClassElementX(String name, Element enclosing, int id, int initialState)
      : super(name, enclosing, id, initialState);

  ClassNode parseNode(Compiler compiler);

  bool get isMixinApplication => false;
  bool get hasLocalScopeMembers => !localScope.isEmpty;

  void addMember(Element element, DiagnosticListener listener) {
    localMembersCache = null;
    localMembersReversed = localMembersReversed.prepend(element);
    addToScope(element, listener);
  }

  void addToScope(Element element, DiagnosticListener listener) {
    if (element.isField && element.name == name) {
      listener.reportError(element, MessageKind.MEMBER_USES_CLASS_NAME);
    }
    localScope.add(element, listener);
  }

  Element localLookup(String elementName) {
    Element result = localScope.lookup(elementName);
    if (result == null && isPatch) {
      result = origin.localLookup(elementName);
    }
    return result;
  }

  void forEachLocalMember(void f(Element member)) {
    localMembers.forEach(f);
  }

  bool get hasConstructor {
    // Search in scope to be sure we search patched constructors.
    for (var element in localScope.values) {
      if (element.isConstructor) return true;
    }
    return false;
  }

  void setDefaultConstructor(FunctionElement constructor, Compiler compiler) {
    // The default constructor, although synthetic, is part of a class' API.
    addMember(constructor, compiler);
  }

  List<DartType> computeTypeParameters(Compiler compiler) {
    ClassNode node = parseNode(compiler);
    return createTypeVariables(node.typeParameters);
  }

  Scope buildScope() => new ClassScope(enclosingElement.buildScope(), this);

  String toString() {
    if (origin != null) {
      return 'patch ${super.toString()}';
    } else if (patch != null) {
      return 'origin ${super.toString()}';
    } else {
      return super.toString();
    }
  }
}

class MixinApplicationElementX extends BaseClassElementX
    implements MixinApplicationElement {
  final Node node;
  final Modifiers modifiers;

  Link<FunctionElement> constructors = new Link<FunctionElement>();

  InterfaceType mixinType;

  MixinApplicationElementX(String name, Element enclosing, int id,
                           this.node, this.modifiers)
      : super(name, enclosing, id, STATE_NOT_STARTED);

  ClassElement get mixin => mixinType != null ? mixinType.element : null;

  bool get isMixinApplication => true;
  bool get isUnnamedMixinApplication => node is! NamedMixinApplication;
  bool get hasConstructor => !constructors.isEmpty;
  bool get hasLocalScopeMembers => !constructors.isEmpty;

  get patch => null;
  get origin => null;

  bool get hasNode => true;

  Token get position => node.getBeginToken();

  Node parseNode(DiagnosticListener listener) => node;

  FunctionElement lookupLocalConstructor(String name) {
    for (Link<Element> link = constructors;
         !link.isEmpty;
         link = link.tail) {
      if (link.head.name == name) return link.head;
    }
    return null;
  }

  Element localLookup(String name) {
    Element constructor = lookupLocalConstructor(name);
    if (constructor != null) return constructor;
    if (mixin == null) return null;
    Element mixedInElement = mixin.localLookup(name);
    if (mixedInElement == null) return null;
    return mixedInElement.isInstanceMember ? mixedInElement : null;
  }

  void forEachLocalMember(void f(Element member)) {
    constructors.forEach(f);
    if (mixin != null) mixin.forEachLocalMember((Element mixedInElement) {
      if (mixedInElement.isInstanceMember) f(mixedInElement);
    });
  }

  void addMember(Element element, DiagnosticListener listener) {
    throw new UnsupportedError("Cannot add member to $this.");
  }

  void addToScope(Element element, DiagnosticListener listener) {
    listener.internalError(this, 'Cannot add to scope of $this.');
  }

  void addConstructor(FunctionElement constructor) {
    constructors = constructors.prepend(constructor);
  }

  void setDefaultConstructor(FunctionElement constructor, Compiler compiler) {
    assert(!hasConstructor);
    addConstructor(constructor);
  }

  List<DartType> computeTypeParameters(Compiler compiler) {
    NamedMixinApplication named = node.asNamedMixinApplication();
    if (named == null) {
      throw new SpannableAssertionFailure(node,
          "Type variables on unnamed mixin applications must be set on "
          "creation.");
    }
    return createTypeVariables(named.typeParameters);
  }

  accept(ElementVisitor visitor) => visitor.visitMixinApplicationElement(this);
}

class LabelDefinitionX implements LabelDefinition {
  final Label label;
  final String labelName;
  final JumpTarget target;
  bool isBreakTarget = false;
  bool isContinueTarget = false;

  LabelDefinitionX(Label label, String labelName, this.target)
      : this.label = label,
        this.labelName = labelName;

  // In case of a synthetic label, just use [labelName] for identifying the
  // label.
  String get name => label == null ? labelName : label.identifier.source;

  void setBreakTarget() {
    isBreakTarget = true;
    target.isBreakTarget = true;
  }

  void setContinueTarget() {
    isContinueTarget = true;
    target.isContinueTarget = true;
  }

  bool get isTarget => isBreakTarget || isContinueTarget;

  String toString() => 'Label:${name}';
}

class JumpTargetX implements JumpTarget {
  final ExecutableElement executableContext;
  final Node statement;
  final int nestingLevel;
  Link<LabelDefinition> labels = const Link<LabelDefinition>();
  bool isBreakTarget = false;
  bool isContinueTarget = false;

  JumpTargetX(this.statement, this.nestingLevel, this.executableContext);

  String get name => "target";

  bool get isTarget => isBreakTarget || isContinueTarget;

  LabelDefinition addLabel(Label label, String labelName) {
    LabelDefinition result = new LabelDefinitionX(label, labelName, this);
    labels = labels.prepend(result);
    return result;
  }

  bool get isSwitch => statement is SwitchStatement;

  String toString() => 'Target:$statement';
}

class TypeVariableElementX extends ElementX with AstElementMixin
    implements TypeVariableElement {
  final Node node;
  TypeVariableType typeCache;
  DartType boundCache;

  TypeVariableElementX(String name, TypeDeclarationElement enclosing, this.node)
    : super(name, ElementKind.TYPE_VARIABLE, enclosing);

  TypeDeclarationElement get typeDeclaration => enclosingElement;

  TypeVariableType computeType(compiler) => type;

  TypeVariableType get type {
    assert(invariant(this, typeCache != null,
        message: "Type has not been set on $this."));
    return typeCache;
  }

  DartType get bound {
    assert(invariant(this, boundCache != null,
        message: "Bound has not been set on $this."));
    return boundCache;
  }

  bool get hasNode => true;

  Node parseNode(compiler) => node;

  String toString() => "${enclosingElement.toString()}.${name}";

  Token get position => node.getBeginToken();

  accept(ElementVisitor visitor) => visitor.visitTypeVariableElement(this);

  // A type variable cannot be patched therefore defines itself.
  AstElement get definingElement => this;
}

/**
 * A single metadata annotation.
 *
 * For example, consider:
 *
 *     class Data {
 *       const Data();
 *     }
 *
 *     const data = const Data();
 *
 *     @data
 *     class Foo {}
 *
 *     @data @data
 *     class Bar {}
 *
 * In this example, there are three instances of [MetadataAnnotation]
 * and they correspond each to a location in the source code where
 * there is an at-sign, '@'. The [constant] of each of these instances
 * are the same compile-time constant, [: const Data() :].
 *
 * The mirror system does not have a concept matching this class.
 */
abstract class MetadataAnnotationX implements MetadataAnnotation {
  /**
   * The compile-time constant which this annotation resolves to.
   * In the mirror system, this would be an object mirror.
   */
  ConstantExpression constant;
  Element annotatedElement;
  int resolutionState;

  /**
   * The beginning token of this annotation, or [:null:] if it is synthetic.
   */
  Token get beginToken;

  MetadataAnnotationX([this.resolutionState = STATE_NOT_STARTED]);

  MetadataAnnotation ensureResolved(Compiler compiler) {
    if (annotatedElement.isClass || annotatedElement.isTypedef) {
      TypeDeclarationElement typeDeclaration = annotatedElement;
      typeDeclaration.ensureResolved(compiler);
    }
    if (resolutionState == STATE_NOT_STARTED) {
      compiler.resolver.resolveMetadataAnnotation(this);
    }
    return this;
  }

  Node parseNode(DiagnosticListener listener);

  String toString() => 'MetadataAnnotation($constant, $resolutionState)';
}

/// Metadata annotation on a parameter.
class ParameterMetadataAnnotation extends MetadataAnnotationX {
  final Metadata metadata;

  ParameterMetadataAnnotation(Metadata this.metadata);

  Node parseNode(DiagnosticListener listener) => metadata.expression;

  Token get beginToken => metadata.getBeginToken();

  Token get endToken => metadata.getEndToken();

  bool get hasNode => true;

  Metadata get node => metadata;
}

/// Mixin for the implementation of patched elements.
///
/// See [:patch_parser.dart:] for a description of the terminology.
abstract class PatchMixin<E extends Element> implements Element {
  // TODO(johnniwinther): Use type variables when issue 18630 is fixed.
  Element/*E*/ patch = null;
  Element/*E*/ origin = null;

  bool get isPatch => origin != null;
  bool get isPatched => patch != null;

  bool get isImplementation => !isPatched;
  bool get isDeclaration => !isPatch;

  Element/*E*/ get implementation => isPatched ? patch : this;
  Element/*E*/ get declaration => isPatch ? origin : this;

  /// Applies a patch to this element. This method must be called at most once.
  void applyPatch(PatchMixin<E> patch) {
    assert(invariant(this, this.patch == null,
                     message: "Element is patched twice."));
    assert(invariant(this, this.origin == null,
                     message: "Origin element is a patch."));
    assert(invariant(patch, patch.origin == null,
                     message: "Element is patched twice."));
    assert(invariant(patch, patch.patch == null,
                     message: "Patch element is patched."));
    this.patch = patch;
    patch.origin = this;
  }
}

/// Abstract implementation of the [AstElement] interface.
abstract class AstElementMixin implements AstElement {
  /// The element whose node defines this element.
  ///
  /// For patched functions the defining element is the patch element found
  /// through [implementation] since its node define the implementation of the
  /// function. For patched classes the defining element is the origin element
  /// found through [declaration] since its node define the inheritance relation
  /// for the class. For unpatched elements the defining element is the element
  /// itself.
  AstElement get definingElement;

  bool get hasResolvedAst => definingElement.hasTreeElements;

  ResolvedAst get resolvedAst {
    return new ResolvedAst(declaration,
        definingElement.node, definingElement.treeElements);
  }

}
