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

/// Implementation of the element model used for deserialiation.
///
/// These classes are created by [ElementDeserializer] triggered by the
/// [Deserializer].

library dart2js.serialization.modelz;

import '../common.dart';
import '../common/resolution.dart' show Resolution;
import '../constants/constructors.dart';
import '../constants/expressions.dart';
import '../dart_types.dart';
import '../elements/common.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart' show FunctionSignatureX;
import '../elements/visitor.dart';
import '../io/source_file.dart';
import '../ordered_typeset.dart';
import '../resolution/class_members.dart' as class_members;
import '../resolution/scope.dart' show Scope;
import '../resolution/tree_elements.dart' show TreeElements;
import '../script.dart';
import '../serialization/constant_serialization.dart';
import '../tokens/token.dart' show Token;
import '../tree/tree.dart';
import '../util/util.dart' show Link, LinkBuilder;
import 'keys.dart';
import 'serialization.dart';

/// Compute a [Link] from an [Iterable].
Link toLink(Iterable iterable) {
  LinkBuilder builder = new LinkBuilder();
  for (var element in iterable) {
    builder.addLast(element);
  }
  return builder.toLink();
}

abstract class ElementZ extends Element with ElementCommon {
  String toString() {
    if (enclosingElement == null || isTopLevel) return 'Z$kind($name)';
    return 'Z$kind(${enclosingElement.name}#$name)';
  }

  _unsupported(text) => throw new UnsupportedError('${this}.$text');

  @override
  AnalyzableElement get analyzableElement {
    Element element = this;
    if (element is AnalyzableElement) {
      return element;
    } else if (enclosingElement != null) {
      return enclosingElement.analyzableElement;
    }
    return null;
  }

  @override
  FunctionElement asFunctionElement() => null;

  @override
  Scope buildScope() => _unsupported('buildScope');

  @override
  ClassElement get enclosingClass => null;

  @override
  LibraryElement get implementationLibrary => library;

  @override
  bool get isAbstract => false;

  @override
  bool get isClassMember => false;

  @override
  bool get isClosure => false;

  @override
  bool get isConst => false;

  @override
  bool get isDeferredLoaderGetter => false;

  @override
  bool get isFinal => false;

  @override
  bool get isInstanceMember => false;

  @override
  bool get isLocal => false;

  @override
  bool get isMixinApplication => false;

  @override
  bool get isOperator => false;

  @override
  bool get isStatic => false;

  @override
  bool get isSynthesized => false;

  @override
  bool get isTopLevel => false;

  @override
  Iterable<MetadataAnnotation> get metadata => const <MetadataAnnotation>[];

  @override
  Token get position => _unsupported('position');
}

abstract class DeserializedElementZ extends ElementZ {
  ObjectDecoder _decoder;
  List<MetadataAnnotation> _metadata;

  DeserializedElementZ(this._decoder);

  @override
  String get name => _decoder.getString(Key.NAME);

  // TODO(johnniwinther): Should this be cached?
  @override
  int get sourceOffset => _decoder.getInt(Key.OFFSET, isOptional: true);

  @override
  SourceSpan get sourcePosition {
    // TODO(johnniwinther): Should this be cached?
    int offset = sourceOffset;
    if (offset == null) return null;
    Uri uri = _decoder.getUri(Key.URI, isOptional: true);
    if (uri == null) {
      uri = compilationUnit.script.readableUri;
    }
    int length = _decoder.getInt(Key.LENGTH, isOptional: true);
    if (length == null) {
      length = name.length;
    }
    return new SourceSpan(uri, offset, offset + length);
  }

  @override
  Iterable<MetadataAnnotation> get metadata {
    if (_metadata == null) {
      _metadata = <MetadataAnnotation>[];
      ListDecoder list = _decoder.getList(Key.METADATA, isOptional: true);
      if (list != null) {
        for (int index = 0; index < list.length; index++) {
          ObjectDecoder object = list.getObject(index);
          Element element = object.getElement(Key.ELEMENT);
          Uri uri = object.getUri(Key.URI);
          int offset = object.getInt(Key.OFFSET);
          int length = object.getInt(Key.LENGTH);
          ConstantExpression constant = object.getConstant(Key.CONSTANT);
          _metadata.add(new MetadataAnnotationZ(
              element, new SourceSpan(uri, offset, offset + length), constant));
        }
      }
    }
    return _metadata;
  }
}

/// Deserializer for a collection of member elements serialized as a map from
/// names to element declarations.
///
/// The serialized data contains the declared getters and setters but lookup
/// into the map returns an [AbstractFieldElement] for pairs of corresponding
/// getters and setters.
///
/// The underlying map encoding allows for lazy computation of the members upon
/// query.
class MappedContainer {
  Map<String, Element> _lookupCache = {};

  Element lookup(String name, MapDecoder members) {
    if (_lookupCache.containsKey(name)) {
      Element element = _lookupCache[name];
      if (element != null) {
        return element;
      }
    }
    if (members == null) {
      return null;
    }
    bool hasId = members.containsKey(name);
    String setterName = '$name,=';
    bool hasSetterId = members.containsKey(setterName);
    Element element;
    SetterElement setterElement;
    if (!hasId && !hasSetterId) {
      _lookupCache[name] = null;
      return null;
    }
    bool isAccessor = false;
    if (hasId) {
      element = members.getElement(name);
      isAccessor = element.isGetter;
    }
    if (hasSetterId) {
      setterElement = members.getElement(setterName);
      isAccessor = true;
    }
    if (isAccessor) {
      element = new AbstractFieldElementZ(name, element, setterElement);
    }
    _lookupCache[name] = element;
    return element;
  }
}

/// Deserializer for a collection of member elements serialized as a list of
/// element declarations.
///
/// The serialized data contains the declared getters and setters but lookup
/// into the map returns an [AbstractFieldElement] for pairs of corresponding
/// getters and setters.
///
/// The underlying list encoding requires the complete lookup map to be computed
/// before query.
class ListedContainer {
  final Map<String, Element> _lookupMap = <String, Element>{};

  ListedContainer(List<Element> elements) {
    Set<String> accessorNames = new Set<String>();
    Map<String, Element> getters = <String, Element>{};
    Map<String, Element> setters = <String, Element>{};
    for (Element element in elements) {
      String name = element.name;
      if (element.isDeferredLoaderGetter) {
        // Store directly.
        // TODO(johnniwinther): Should modelx be normalized to put `loadLibrary`
        // in an [AbstractFieldElement] instead?
        _lookupMap[name] = element;
      } else if (element.isGetter) {
        accessorNames.add(name);
        getters[name] = element;
        // Inserting [element] here to ensure insert order of [name].
        _lookupMap[name] = element;
      } else if (element.isSetter) {
        accessorNames.add(name);
        setters[name] = element;
        // Inserting [element] here to ensure insert order of [name].
        _lookupMap[name] = element;
      } else {
        _lookupMap[name] = element;
      }
    }
    for (String name in accessorNames) {
      _lookupMap[name] =
          new AbstractFieldElementZ(name, getters[name], setters[name]);
    }
  }

  Element lookup(String name) => _lookupMap[name];

  void forEach(f(Element element)) => _lookupMap.values.forEach(f);

  Iterable<Element> get values => _lookupMap.values;
}

abstract class AnalyzableElementMixin implements AnalyzableElement, ElementZ {
  @override
  bool get hasTreeElements => _unsupported('hasTreeElements');

  @override
  TreeElements get treeElements => _unsupported('treeElements');
}

abstract class AstElementMixinZ implements AstElement, ElementZ {
  ResolvedAst _resolvedAst;

  // TODO(johnniwinther): This is needed for the token invariant assertion. Find
  // another way to bypass the test for modelz.
  @override
  bool get hasNode => false;

  @override
  bool get hasResolvedAst => _resolvedAst != null;

  @override
  get node => _unsupported('node');

  @override
  ResolvedAst get resolvedAst {
    assert(invariant(this, _resolvedAst != null,
        message: "ResolvedAst has not been set for $this."));
    return _resolvedAst;
  }

  void set resolvedAst(ResolvedAst value) {
    assert(invariant(this, _resolvedAst == null,
        message: "ResolvedAst has already been set for $this."));
    _resolvedAst = value;
  }
}

abstract class ContainerMixin
    implements DeserializedElementZ, ScopeContainerElement {
  MappedContainer _membersMap = new MappedContainer();

  @override
  Element localLookup(String name) {
    return _membersMap.lookup(
        name, _decoder.getMap(Key.MEMBERS, isOptional: true));
  }

  @override
  void forEachLocalMember(f(Element element)) {
    MapDecoder members = _decoder.getMap(Key.MEMBERS, isOptional: true);
    if (members == null) return;
    members.forEachKey((String key) {
      Element member = members.getElement(key);
      if (member != null) {
        f(member);
      }
    });
  }
}

class AbstractFieldElementZ extends ElementZ
    with AbstractFieldElementCommon
    implements AbstractFieldElement {
  final String name;
  final GetterElementZ getter;
  final SetterElementZ setter;

  factory AbstractFieldElementZ(
      String name, GetterElement getter, SetterElement setter) {
    if (getter?.abstractField != null) {
      return getter.abstractField;
    } else if (setter?.abstractField != null) {
      return setter.abstractField;
    } else {
      return new AbstractFieldElementZ._(name, getter, setter);
    }
  }

  AbstractFieldElementZ._(this.name, this.getter, this.setter) {
    if (getter != null) {
      getter.abstractField = this;
      getter.setter = setter;
    }
    if (setter != null) {
      setter.abstractField = this;
      setter.getter = getter;
    }
  }

  FunctionElement get _canonicalElement => getter != null ? getter : setter;

  @override
  ElementKind get kind => ElementKind.ABSTRACT_FIELD;

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitAbstractFieldElement(this, arg);
  }

  @override
  LibraryElement get library => _canonicalElement.library;

  @override
  CompilationUnitElement get compilationUnit {
    return _canonicalElement.compilationUnit;
  }

  @override
  Element get enclosingElement => _canonicalElement.enclosingElement;

  @override
  int get sourceOffset => _canonicalElement.sourceOffset;

  @override
  SourceSpan get sourcePosition => _canonicalElement.sourcePosition;

  @override
  ClassElement get enclosingClass => _canonicalElement.enclosingClass;

  @override
  bool get isClassMember => _canonicalElement.isClassMember;

  @override
  bool get isInstanceMember => _canonicalElement.isInstanceMember;

  @override
  bool get isStatic => _canonicalElement.isStatic;

  @override
  bool get isTopLevel => _canonicalElement.isTopLevel;
}

class LibraryElementZ extends DeserializedElementZ
    with AnalyzableElementMixin, ContainerMixin, LibraryElementCommon
    implements LibraryElement {
  Uri _canonicalUri;
  CompilationUnitElement _entryCompilationUnit;
  Link<CompilationUnitElement> _compilationUnits;
  List<ImportElement> _imports;
  List<ExportElement> _exports;
  ListedContainer _exportsMap;
  ListedContainer _importsMap;
  Map<Element, List<ImportElement>> _importsFor;

  LibraryElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  ElementKind get kind => ElementKind.LIBRARY;

  @override
  Element get enclosingElement => null;

  @override
  String get name => entryCompilationUnit.name;

  @override
  SourceSpan get sourcePosition => entryCompilationUnit.sourcePosition;

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitLibraryElement(this, arg);
  }

  @override
  LibraryElement get library => this;

  @override
  CompilationUnitElement get compilationUnit => entryCompilationUnit;

  @override
  Uri get canonicalUri {
    if (_canonicalUri == null) {
      _canonicalUri = _decoder.getUri(Key.CANONICAL_URI);
    }
    return _canonicalUri;
  }

  @override
  CompilationUnitElement get entryCompilationUnit {
    if (_entryCompilationUnit == null) {
      _entryCompilationUnit = _decoder.getElement(Key.COMPILATION_UNIT);
    }
    return _entryCompilationUnit;
  }

  @override
  Link<CompilationUnitElement> get compilationUnits {
    if (_compilationUnits == null) {
      _compilationUnits = toLink(_decoder.getElements(Key.COMPILATION_UNITS));
    }
    return _compilationUnits;
  }

  @override
  bool get hasLibraryName {
    return libraryName != '';
  }

  @override
  String get libraryName {
    return _decoder.getString(Key.LIBRARY_NAME);
  }

  @override
  bool get exportsHandled => true;

  void _ensureExports() {
    if (_exportsMap == null) {
      _exportsMap = new ListedContainer(
          _decoder.getElements(Key.EXPORT_SCOPE, isOptional: true));
    }
  }

  @override
  void forEachExport(f(Element element)) {
    _ensureExports();
    _exportsMap.forEach(f);
  }

  @override
  Element find(String elementName) {
    Element element = localLookup(elementName);
    if (element == null) {
      _ensureImports();
      element = _importsMap.lookup(elementName);
    }
    return element;
  }

  @override
  Element findLocal(String elementName) {
    return localLookup(elementName);
  }

  @override
  Element findExported(String elementName) {
    _ensureExports();
    return _exportsMap.lookup(elementName);
  }

  void _ensureImports() {
    if (_importsMap == null) {
      _importsMap = new ListedContainer(
          _decoder.getElements(Key.IMPORT_SCOPE, isOptional: true));
      _importsFor = <Element, List<ImportElement>>{};

      ListDecoder importsDecoder = _decoder.getList(Key.IMPORTS_FOR);
      for (int index = 0; index < importsDecoder.length; index++) {
        ObjectDecoder objectDecoder = importsDecoder.getObject(index);
        Element key = objectDecoder.getElement(Key.ELEMENT);
        List<ImportElement> imports =
            objectDecoder.getElements(Key.IMPORTS, isOptional: true);

        // Imports are mapped to [AbstractFieldElement] which are not serialized
        // so we use getter (or setter if there is no getter) as the key.
        Element importedElement = key;
        if (key.isDeferredLoaderGetter) {
          // Use as [importedElement].
        } else if (key.isAccessor) {
          AccessorElement accessor = key;
          importedElement = accessor.abstractField;
        }
        _importsFor[importedElement] = imports;
      }
    }
  }

  @override
  void forEachImport(f(Element element)) {
    _ensureImports();
    _importsMap.forEach(f);
  }

  @override
  Iterable<ImportElement> getImportsFor(Element element) {
    _ensureImports();
    return _importsFor[element] ?? const <ImportElement>[];
  }

  String toString() {
    return 'Zlibrary(${canonicalUri})';
  }

  @override
  Iterable<ExportElement> get exports {
    if (_exports == null) {
      _exports = _decoder.getElements(Key.EXPORTS, isOptional: true);
    }
    return _exports;
  }

  @override
  Iterable<ImportElement> get imports {
    if (_imports == null) {
      _imports = _decoder.getElements(Key.IMPORTS, isOptional: true);
    }
    return _imports;
  }
}

class ScriptZ implements Script {
  final Uri resourceUri;
  SourceFile _file;
  bool _isSynthesized = false;

  ScriptZ(this.resourceUri);

  @override
  Script copyWithFile(SourceFile file) {
    throw new UnsupportedError('ScriptZ.copyWithFile');
  }

  @override
  SourceFile get file {
    if (_file == null) {
      throw new UnsupportedError('ScriptZ.file');
    }
    return _file;
  }

  void set file(SourceFile value) {
    _file = value;
  }

  // TODO(johnniwinther): Decide if it is meaningful to serialize erroneous
  // elements.
  @override
  bool get isSynthesized => _isSynthesized;

  void set isSynthesized(bool value) {
    _isSynthesized = value;
  }

  @override
  String get name {
    if (_file != null) {
      return _file.filename;
    }
    return resourceUri.toString();
  }

  // TODO(johnniwinther): Support the distinction between [readableUri] and
  // [resourceUri]; needed for platform libraries.
  @override
  Uri get readableUri => resourceUri;

  @override
  String get text {
    if (_file != null) {
      return _file.slowText();
    }
    throw new UnsupportedError('ScriptZ.text');
  }
}

class CompilationUnitElementZ extends DeserializedElementZ
    with LibraryMemberMixin, CompilationUnitElementCommon
    implements CompilationUnitElement {
  List<Element> _members;
  Script _script;

  CompilationUnitElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  ElementKind get kind => ElementKind.COMPILATION_UNIT;

  @override
  CompilationUnitElement get compilationUnit => this;

  @override
  Element get enclosingElement => library;

  @override
  SourceSpan get sourcePosition => new SourceSpan(script.resourceUri, 0, 0);

  @override
  bool get isTopLevel => false;

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitCompilationUnitElement(this, arg);
  }

  @override
  void forEachLocalMember(f(Element element)) {
    if (_members == null) {
      _members = _decoder.getElements(Key.ELEMENTS, isOptional: true);
    }
    _members.forEach(f);
  }

  @override
  Script get script {
    if (_script == null) {
      Uri resolvedUri = _decoder.getUri(Key.URI);
      _script = new ScriptZ(resolvedUri);
    }
    return _script;
  }

  @override
  String get name => script.name;
}

abstract class LibraryMemberMixin implements DeserializedElementZ {
  LibraryElement _library;
  CompilationUnitElement _compilationUnit;

  @override
  LibraryElement get library {
    if (_library == null) {
      _library = _decoder.getElement(Key.LIBRARY);
    }
    return _library;
  }

  @override
  CompilationUnitElement get compilationUnit {
    if (_compilationUnit == null) {
      _compilationUnit = _decoder.getElement(Key.COMPILATION_UNIT);
    }
    return _compilationUnit;
  }

  @override
  Element get enclosingElement => compilationUnit;

  @override
  ClassElement get enclosingClass => null;

  @override
  bool get isTopLevel => true;

  @override
  bool get isStatic => false;
}

abstract class ClassMemberMixin implements DeserializedElementZ {
  ClassElement _class;
  CompilationUnitElement _compilationUnit;

  @override
  Element get enclosingElement => enclosingClass;

  @override
  ClassElement get enclosingClass {
    if (_class == null) {
      _class = _decoder.getElement(Key.CLASS);
    }
    return _class;
  }

  @override
  bool get isClassMember => true;

  @override
  LibraryElement get library => enclosingClass.library;

  @override
  CompilationUnitElement get compilationUnit {
    if (_compilationUnit == null) {
      _compilationUnit =
          _decoder.getElement(Key.COMPILATION_UNIT, isOptional: true);
      if (_compilationUnit == null) {
        _compilationUnit = enclosingClass.compilationUnit;
      }
    }
    return _compilationUnit;
  }
}

abstract class InstanceMemberMixin implements DeserializedElementZ {
  @override
  bool get isTopLevel => false;

  @override
  bool get isStatic => false;

  @override
  bool get isInstanceMember => true;

  @override
  bool get isClassMember => true;
}

abstract class StaticMemberMixin implements DeserializedElementZ {
  @override
  bool get isTopLevel => false;

  @override
  bool get isStatic => true;

  @override
  bool get isClassMember => true;
}

abstract class TypedElementMixin implements DeserializedElementZ, TypedElement {
  DartType _type;

  @override
  DartType get type {
    if (_type == null) {
      _type = _decoder.getType(Key.TYPE);
    }
    return _type;
  }

  @override
  DartType computeType(Resolution resolution) => type;
}

abstract class ParametersMixin
    implements DeserializedElementZ, FunctionTypedElement {
  FunctionSignature _functionSignature;
  List<ParameterElement> _parameters;

  bool get hasFunctionSignature => true;

  @override
  FunctionSignature get functionSignature {
    if (_functionSignature == null) {
      List<Element> requiredParameters = [];
      List<Element> optionalParameters = [];
      List orderedOptionalParameters = [];
      int requiredParameterCount = 0;
      int optionalParameterCount = 0;
      bool optionalParametersAreNamed = false;
      List<DartType> parameterTypes = <DartType>[];
      List<DartType> optionalParameterTypes = <DartType>[];
      for (ParameterElement parameter in parameters) {
        if (parameter.isOptional) {
          optionalParameterCount++;
          optionalParameters.add(parameter);
          orderedOptionalParameters.add(parameter);
          if (parameter.isNamed) {
            optionalParametersAreNamed = true;
          } else {
            optionalParameterTypes.add(parameter.type);
          }
        } else {
          requiredParameterCount++;
          requiredParameters.add(parameter);
          parameterTypes.add(parameter.type);
        }
      }
      List<String> namedParameters = const <String>[];
      List<DartType> namedParameterTypes = const <DartType>[];
      if (optionalParametersAreNamed) {
        namedParameters = <String>[];
        namedParameterTypes = <DartType>[];
        orderedOptionalParameters.sort((Element a, Element b) {
          return a.name.compareTo(b.name);
        });
        for (ParameterElement parameter in orderedOptionalParameters) {
          namedParameters.add(parameter.name);
          namedParameterTypes.add(parameter.type);
        }
      }
      List<DartType> typeVariables =
          _decoder.getTypes(Key.TYPE_VARIABLES, isOptional: true);

      FunctionType type = new FunctionType(
          this,
          _decoder.getType(Key.RETURN_TYPE),
          parameterTypes,
          optionalParameterTypes,
          namedParameters,
          namedParameterTypes);
      _functionSignature = new FunctionSignatureX(
          typeVariables: typeVariables,
          requiredParameters: requiredParameters,
          requiredParameterCount: requiredParameterCount,
          optionalParameters: optionalParameters,
          optionalParameterCount: optionalParameterCount,
          optionalParametersAreNamed: optionalParametersAreNamed,
          orderedOptionalParameters: orderedOptionalParameters,
          type: type);
    }
    return _functionSignature;
  }

  List<ParameterElement> get parameters {
    if (_parameters == null) {
      _parameters = _decoder.getElements(Key.PARAMETERS, isOptional: true);
    }
    return _parameters;
  }
}

abstract class FunctionTypedElementMixin
    implements FunctionElement, DeserializedElementZ {
  @override
  FunctionElement asFunctionElement() => this;

  @override
  bool get isExternal {
    return _decoder.getBool(Key.IS_EXTERNAL,
        isOptional: true, defaultValue: false);
  }

  @override
  List<DartType> get typeVariables => functionSignature.typeVariables;
}

abstract class ClassElementMixin
    implements ElementZ, ClassElement, class_members.ClassMemberMixin {
  bool _isResolved = false;

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

  @override
  ElementKind get kind => ElementKind.CLASS;

  @override
  bool get hasConstructor => _unsupported('hasConstructor');

  @override
  bool get hasIncompleteHierarchy => _unsupported('hasIncompleteHierarchy');

  @override
  bool get hasLocalScopeMembers => _unsupported('hasLocalScopeMembers');

  @override
  bool get isEnumClass => false;

  @override
  ConstructorElement lookupDefaultConstructor() {
    ConstructorElement constructor = lookupConstructor("");
    if (constructor != null &&
        constructor.functionSignature.requiredParameterCount == 0) {
      return constructor;
    }
    return null;
  }

  @override
  ClassElement get superclass => supertype != null ? supertype.element : null;

  @override
  void ensureResolved(Resolution resolution) {
    if (!_isResolved) {
      _isResolved = true;
      // TODO(johnniwinther): Avoid eager computation of all members. `call` is
      // always needed, but the remaining should be computed on-demand or on
      // type instantiation.
      class_members.MembersCreator.computeAllClassMembers(resolution, this);
      resolution.registerClass(this);
    }
  }
}

class ClassElementZ extends DeserializedElementZ
    with
        AnalyzableElementMixin,
        AstElementMixinZ,
        ClassElementCommon,
        class_members.ClassMemberMixin,
        ContainerMixin,
        LibraryMemberMixin,
        TypeDeclarationMixin<InterfaceType>,
        ClassElementMixin
    implements ClassElement {
  bool _isObject;
  DartType _supertype;
  OrderedTypeSet _allSupertypesAndSelf;
  Link<DartType> _interfaces;
  FunctionType _callType;

  ClassElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  List<DartType> _getTypeVariables() {
    return _decoder.getTypes(Key.TYPE_VARIABLES, isOptional: true);
  }

  void _ensureSuperHierarchy() {
    if (_interfaces == null) {
      InterfaceType supertype =
          _decoder.getType(Key.SUPERTYPE, isOptional: true);
      if (supertype == null) {
        _isObject = true;
        _allSupertypesAndSelf = new OrderedTypeSet.singleton(thisType);
        _interfaces = const Link<DartType>();
      } else {
        _isObject = false;
        _interfaces =
            toLink(_decoder.getTypes(Key.INTERFACES, isOptional: true));
        List<InterfaceType> mixins =
            _decoder.getTypes(Key.MIXINS, isOptional: true);
        for (InterfaceType mixin in mixins) {
          MixinApplicationElement mixinElement =
              new UnnamedMixinApplicationElementZ(this, supertype, mixin);
          supertype = mixinElement.thisType
              .subst(typeVariables, mixinElement.typeVariables);
        }
        _supertype = supertype;
        _allSupertypesAndSelf = new OrderedTypeSetBuilder(this)
            .createOrderedTypeSet(_supertype, _interfaces);
        _callType = _decoder.getType(Key.CALL_TYPE, isOptional: true);
      }
    }
  }

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitClassElement(this, arg);
  }

  @override
  DartType get supertype {
    _ensureSuperHierarchy();
    return _supertype;
  }

  @override
  bool get isAbstract => _decoder.getBool(Key.IS_ABSTRACT);

  @override
  bool get isObject {
    _ensureSuperHierarchy();
    return _isObject;
  }

  @override
  OrderedTypeSet get allSupertypesAndSelf {
    _ensureSuperHierarchy();
    return _allSupertypesAndSelf;
  }

  @override
  Link<DartType> get interfaces {
    _ensureSuperHierarchy();
    return _interfaces;
  }

  @override
  bool get isProxy => _decoder.getBool(Key.IS_PROXY);

  @override
  bool get isInjected => _decoder.getBool(Key.IS_INJECTED);

  @override
  bool get isUnnamedMixinApplication => false;

  @override
  FunctionType get callType {
    _ensureSuperHierarchy();
    // TODO(johnniwinther): Why can't this always be computed in ensureResolved?
    return _callType;
  }
}

abstract class MixinApplicationElementMixin
    implements ElementZ, MixinApplicationElement {
  @override
  bool get isMixinApplication => true;

  @override
  ClassElement get mixin => mixinType.element;
}

class NamedMixinApplicationElementZ extends ClassElementZ
    with MixinApplicationElementMixin {
  Link<Element> _constructors;
  InterfaceType _mixinType;

  NamedMixinApplicationElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  InterfaceType get mixinType => _mixinType ??= _decoder.getType(Key.MIXIN);

  @override
  ClassElement get subclass => null;
}

class UnnamedMixinApplicationElementZ extends ElementZ
    with
        ClassElementCommon,
        ClassElementMixin,
        class_members.ClassMemberMixin,
        TypeDeclarationMixin<InterfaceType>,
        AnalyzableElementMixin,
        AstElementMixinZ,
        MixinApplicationElementCommon,
        MixinApplicationElementMixin {
  final String name;
  final ClassElement subclass;
  final InterfaceType _supertypeBase;
  final InterfaceType _mixinBase;
  InterfaceType _supertype;
  Link<DartType> _interfaces;
  OrderedTypeSet _allSupertypesAndSelf;
  Link<ConstructorElement> _constructors;

  UnnamedMixinApplicationElementZ(
      this.subclass, InterfaceType supertype, InterfaceType mixin)
      : this._supertypeBase = supertype,
        this._mixinBase = mixin,
        this.name = "${supertype.name}+${mixin.name}";

  @override
  CompilationUnitElement get compilationUnit => subclass.compilationUnit;

  @override
  bool get isTopLevel => true;

  @override
  bool get isAbstract => true;

  @override
  bool get isUnnamedMixinApplication => true;

  Link<ConstructorElement> get constructors {
    if (_constructors == null) {
      LinkBuilder<ConstructorElement> builder =
          new LinkBuilder<ConstructorElement>();
      for (ConstructorElement definingConstructor in superclass.constructors) {
        if (definingConstructor.isGenerativeConstructor &&
            definingConstructor.memberName.isAccessibleFrom(library)) {
          ForwardingConstructorElementZ constructor =
              new ForwardingConstructorElementZ(this, definingConstructor);
          constructor.resolvedAst = new SynthesizedResolvedAst(
              constructor, ResolvedAstKind.FORWARDING_CONSTRUCTOR);
          builder.addLast(constructor);
        }
      }
      _constructors = builder.toLink();
    }
    return _constructors;
  }

  @override
  List<DartType> _getTypeVariables() {
    // Create synthetic type variables for the mixin application.
    List<DartType> typeVariables = <DartType>[];
    int index = 0;
    for (TypeVariableType type in subclass.typeVariables) {
      SyntheticTypeVariableElementZ typeVariableElement =
          new SyntheticTypeVariableElementZ(this, index, type.name);
      TypeVariableType typeVariable = new TypeVariableType(typeVariableElement);
      typeVariables.add(typeVariable);
      index++;
    }
    // Setup bounds on the synthetic type variables.
    for (TypeVariableType type in subclass.typeVariables) {
      TypeVariableType typeVariable = typeVariables[type.element.index];
      SyntheticTypeVariableElementZ typeVariableElement = typeVariable.element;
      typeVariableElement._type = typeVariable;
      typeVariableElement._bound =
          type.element.bound.subst(typeVariables, subclass.typeVariables);
    }
    return typeVariables;
  }

  @override
  InterfaceType get supertype {
    if (_supertype == null) {
      // Substitute the type variables in [_supertypeBase] provided by
      // [_subclass] with the type variables in this unnamed mixin application.
      //
      // For instance
      //    class S<S.T> {}
      //    class M<M.T> {}
      //    class C<C.T> extends S<C.T> with M<C.T> {}
      // the unnamed mixin application should be
      //    abstract class S+M<S+M.T> extends S<S+M.T> implements M<S+M.T> {}
      // but the supertype is provided as S<C.T> and we need to substitute S+M.T
      // for C.T.
      _supertype = _supertypeBase.subst(typeVariables, subclass.typeVariables);
    }
    return _supertype;
  }

  @override
  Link<DartType> get interfaces {
    if (_interfaces == null) {
      // Substitute the type variables in [_mixinBase] provided by
      // [_subclass] with the type variables in this unnamed mixin application.
      //
      // For instance
      //    class S<S.T> {}
      //    class M<M.T> {}
      //    class C<C.T> extends S<C.T> with M<C.T> {}
      // the unnamed mixin application should be
      //    abstract class S+M<S+M.T> extends S<S+M.T> implements M<S+M.T> {}
      // but the mixin is provided as M<C.T> and we need to substitute S+M.T
      // for C.T.
      _interfaces = const Link<DartType>()
          .prepend(_mixinBase.subst(typeVariables, subclass.typeVariables));
    }
    return _interfaces;
  }

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitMixinApplicationElement(this, arg);
  }

  @override
  OrderedTypeSet get allSupertypesAndSelf {
    if (_allSupertypesAndSelf == null) {
      _allSupertypesAndSelf = new OrderedTypeSetBuilder(this)
          .createOrderedTypeSet(supertype, interfaces);
    }
    return _allSupertypesAndSelf;
  }

  @override
  Element get enclosingElement => subclass.enclosingElement;

  @override
  bool get isObject => false;

  @override
  bool get isProxy => false;

  @override
  LibraryElement get library => enclosingElement.library;

  @override
  InterfaceType get mixinType => interfaces.head;

  @override
  int get sourceOffset => subclass.sourceOffset;

  @override
  SourceSpan get sourcePosition => subclass.sourcePosition;
}

class EnumClassElementZ extends ClassElementZ implements EnumClassElement {
  List<FieldElement> _enumValues;

  EnumClassElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  bool get isEnumClass => true;

  @override
  List<FieldElement> get enumValues {
    if (_enumValues == null) {
      _enumValues = _decoder.getElements(Key.FIELDS);
    }
    return _enumValues;
  }
}

abstract class ConstructorElementZ extends DeserializedElementZ
    with
        AnalyzableElementMixin,
        AstElementMixinZ,
        ClassMemberMixin,
        FunctionTypedElementMixin,
        ParametersMixin,
        TypedElementMixin,
        MemberElementMixin,
        ConstructorElementCommon
    implements
        ConstructorElement,
        // TODO(johnniwinther): Sort out whether a constructor is a method.
        MethodElement {
  ConstantConstructor _constantConstructor;
  ConstructorElement _effectiveTarget;

  ConstructorElementZ(ObjectDecoder decoder) : super(decoder);

  accept(ElementVisitor visitor, arg) {
    return visitor.visitConstructorElement(this, arg);
  }

  @override
  bool get isConst => _decoder.getBool(Key.IS_CONST);

  @override
  bool get isExternal => _decoder.getBool(Key.IS_EXTERNAL);

  @override
  bool get isDefaultConstructor => false;

  ConstantConstructor get constantConstructor {
    if (isConst && _constantConstructor == null) {
      ObjectDecoder data =
          _decoder.getObject(Key.CONSTRUCTOR, isOptional: true);
      if (data == null) {
        assert(isFromEnvironmentConstructor || isExternal);
        return null;
      }
      _constantConstructor = ConstantConstructorDeserializer.deserialize(data);
    }
    return _constantConstructor;
  }

  @override
  AsyncMarker get asyncMarker => AsyncMarker.SYNC;

  @override
  ConstructorElement get definingConstructor => null;

  @override
  bool get hasEffectiveTarget => true;

  @override
  ConstructorElement get effectiveTarget {
    if (_effectiveTarget == null) {
      _effectiveTarget =
          _decoder.getElement(Key.EFFECTIVE_TARGET, isOptional: true);
      if (_effectiveTarget == null) {
        _effectiveTarget = this;
      }
    }
    return _effectiveTarget;
  }

  @override
  ConstructorElement get immediateRedirectionTarget => null;

  // TODO(johnniwinther): Should serialization support erroneous element
  // relations?
  @override
  bool get isEffectiveTargetMalformed => false;

  @override
  bool get isCyclicRedirection => false;

  @override
  bool get isRedirectingFactory => false;

  @override
  bool get isRedirectingGenerative => false;

  @override
  PrefixElement get redirectionDeferredPrefix => null;

  @override
  InterfaceType computeEffectiveTargetType(InterfaceType newType) => newType;
}

class GenerativeConstructorElementZ extends ConstructorElementZ {
  GenerativeConstructorElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  ElementKind get kind => ElementKind.GENERATIVE_CONSTRUCTOR;

  @override
  bool get isRedirectingGenerative => _decoder.getBool(Key.IS_REDIRECTING);
}

class DefaultConstructorElementZ extends ConstructorElementZ {
  DefaultConstructorElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  ElementKind get kind => ElementKind.GENERATIVE_CONSTRUCTOR;

  @override
  bool get isSynthesized => true;

  @override
  bool get isDefaultConstructor => true;

  @override
  ConstructorElement get definingConstructor {
    return enclosingClass.superclass.lookupConstructor('');
  }
}

class FactoryConstructorElementZ extends ConstructorElementZ {
  FactoryConstructorElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  ElementKind get kind => ElementKind.FACTORY_CONSTRUCTOR;
}

class RedirectingFactoryConstructorElementZ extends ConstructorElementZ {
  DartType _effectiveTargetType;
  ConstructorElement _immediateRedirectionTarget;
  PrefixElement _redirectionDeferredPrefix;
  bool _effectiveTargetIsMalformed;

  RedirectingFactoryConstructorElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  ElementKind get kind => ElementKind.FACTORY_CONSTRUCTOR;

  @override
  bool get isRedirectingFactory => true;

  void _ensureEffectiveTarget() {
    if (_effectiveTarget == null) {
      _effectiveTarget =
          _decoder.getElement(Key.EFFECTIVE_TARGET, isOptional: true);
      if (_effectiveTarget == null) {
        _effectiveTarget = this;
        _effectiveTargetType = enclosingClass.thisType;
        _effectiveTargetIsMalformed = false;
      } else {
        _effectiveTargetType = _decoder.getType(Key.EFFECTIVE_TARGET_TYPE);
        _effectiveTargetIsMalformed =
            _decoder.getBool(Key.EFFECTIVE_TARGET_IS_MALFORMED);
      }
    }
  }

  bool get isEffectiveTargetMalformed {
    _ensureEffectiveTarget();
    return _effectiveTargetIsMalformed;
  }

  @override
  ConstructorElement get effectiveTarget {
    _ensureEffectiveTarget();
    return _effectiveTarget;
  }

  @override
  DartType computeEffectiveTargetType(InterfaceType newType) {
    _ensureEffectiveTarget();
    return _effectiveTargetType.substByContext(newType);
  }

  void _ensureRedirection() {
    if (_immediateRedirectionTarget == null) {
      _immediateRedirectionTarget =
          _decoder.getElement(Key.IMMEDIATE_REDIRECTION_TARGET);
      _redirectionDeferredPrefix =
          _decoder.getElement(Key.PREFIX, isOptional: true);
    }
  }

  @override
  ConstructorElement get immediateRedirectionTarget {
    _ensureRedirection();
    return _immediateRedirectionTarget;
  }

  @override
  PrefixElement get redirectionDeferredPrefix {
    _ensureRedirection();
    return _redirectionDeferredPrefix;
  }
}

class ForwardingConstructorElementZ extends ElementZ
    with
        AnalyzableElementMixin,
        AstElementMixinZ
    implements
        ConstructorElement,
        // TODO(johnniwinther): Sort out whether a constructor is a method.
        MethodElement {
  final MixinApplicationElement enclosingClass;
  final ConstructorElement definingConstructor;

  ForwardingConstructorElementZ(this.enclosingClass, this.definingConstructor);

  @override
  CompilationUnitElement get compilationUnit => enclosingClass.compilationUnit;

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitConstructorElement(this, arg);
  }

  @override
  AsyncMarker get asyncMarker => AsyncMarker.SYNC;

  @override
  InterfaceType computeEffectiveTargetType(InterfaceType newType) {
    return enclosingClass.thisType.substByContext(newType);
  }

  @override
  DartType computeType(Resolution resolution) => type;

  @override
  bool get isConst => false;

  @override
  bool get isClassMember => true;

  @override
  bool get isDefaultConstructor => false;

  @override
  ConstantConstructor get constantConstructor => null;

  @override
  bool get hasEffectiveTarget => true;

  @override
  ConstructorElement get effectiveTarget => this;

  @override
  Element get enclosingElement => enclosingClass;

  @override
  FunctionSignature get functionSignature {
    // TODO(johnniwinther): Ensure that the function signature (and with it the
    // function type) substitutes type variables correctly.
    return definingConstructor.functionSignature;
  }

  @override
  bool get hasFunctionSignature {
    return _unsupported('hasFunctionSignature');
  }

  @override
  ConstructorElement get immediateRedirectionTarget => null;

  @override
  bool get isCyclicRedirection => false;

  @override
  bool get isEffectiveTargetMalformed => false;

  @override
  bool get isExternal => false;

  @override
  bool get isFromEnvironmentConstructor => false;

  @override
  bool get isIntFromEnvironmentConstructor => false;

  @override
  bool get isBoolFromEnvironmentConstructor => false;

  @override
  bool get isStringFromEnvironmentConstructor => false;

  @override
  bool get isRedirectingFactory => false;

  @override
  bool get isRedirectingGenerative => false;

  @override
  bool get isSynthesized => true;

  @override
  ElementKind get kind => ElementKind.GENERATIVE_CONSTRUCTOR;

  @override
  LibraryElement get library => enclosingClass.library;

  @override
  MemberElement get memberContext => this;

  @override
  Name get memberName => definingConstructor.memberName;

  @override
  String get name => definingConstructor.name;

  @override
  List<FunctionElement> get nestedClosures => const <FunctionElement>[];

  @override
  List<ParameterElement> get parameters {
    // TODO(johnniwinther): We need to create synthetic parameters that
    // substitute type variables.
    return definingConstructor.parameters;
  }

  // TODO: implement redirectionDeferredPrefix
  @override
  PrefixElement get redirectionDeferredPrefix => null;

  @override
  int get sourceOffset => enclosingClass.sourceOffset;

  @override
  SourceSpan get sourcePosition => enclosingClass.sourcePosition;

  @override
  FunctionType get type {
    // TODO(johnniwinther): Ensure that the function type substitutes type
    // variables correctly.
    return definingConstructor.type;
  }

  @override
  List<DartType> get typeVariables => _unsupported("typeVariables");
}

abstract class MemberElementMixin
    implements DeserializedElementZ, MemberElement {
  final List<FunctionElement> nestedClosures = <FunctionElement>[];

  @override
  MemberElement get memberContext => this;

  @override
  Name get memberName => new Name(name, library);

  @override
  bool get isInjected => _decoder.getBool(Key.IS_INJECTED);

  @override
  void forgetElement() {
    nestedClosures.clear();
  }
}

abstract class FieldElementZ extends DeserializedElementZ
    with
        AnalyzableElementMixin,
        AstElementMixinZ,
        TypedElementMixin,
        MemberElementMixin
    implements FieldElement {
  bool _isConst;
  ConstantExpression _constant;

  FieldElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  ElementKind get kind => ElementKind.FIELD;

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitFieldElement(this, arg);
  }

  @override
  bool get isFinal => _decoder.getBool(Key.IS_FINAL);

  void _ensureConstant() {
    if (_isConst == null) {
      _isConst = _decoder.getBool(Key.IS_CONST);
      _constant = _decoder.getConstant(Key.CONSTANT, isOptional: true);
    }
  }

  @override
  bool get isConst {
    _ensureConstant();
    return _isConst;
  }

  @override
  bool get hasConstant => true;

  @override
  ConstantExpression get constant {
    _ensureConstant();
    return _constant;
  }

  @override
  Expression get initializer => _unsupported('initializer');
}

class TopLevelFieldElementZ extends FieldElementZ with LibraryMemberMixin {
  TopLevelFieldElementZ(ObjectDecoder decoder) : super(decoder);
}

class StaticFieldElementZ extends FieldElementZ
    with ClassMemberMixin, StaticMemberMixin {
  StaticFieldElementZ(ObjectDecoder decoder) : super(decoder);
}

class EnumConstantElementZ extends StaticFieldElementZ
    implements EnumConstantElement {
  EnumConstantElementZ(ObjectDecoder decoder) : super(decoder);

  int get index => _decoder.getInt(Key.INDEX);
}

class InstanceFieldElementZ extends FieldElementZ
    with ClassMemberMixin, InstanceMemberMixin {
  InstanceFieldElementZ(ObjectDecoder decoder) : super(decoder);
}

abstract class FunctionElementZ extends DeserializedElementZ
    with
        AnalyzableElementMixin,
        AstElementMixinZ,
        ParametersMixin,
        FunctionTypedElementMixin,
        TypedElementMixin,
        MemberElementMixin
    implements MethodElement {
  FunctionElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  ElementKind get kind => ElementKind.FUNCTION;

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitMethodElement(this, arg);
  }

  @override
  AsyncMarker get asyncMarker {
    return _decoder.getEnum(Key.ASYNC_MARKER, AsyncMarker.values);
  }

  @override
  bool get isAbstract => _decoder.getBool(Key.IS_ABSTRACT);

  @override
  bool get isOperator => _decoder.getBool(Key.IS_OPERATOR);
}

class TopLevelFunctionElementZ extends FunctionElementZ
    with LibraryMemberMixin {
  TopLevelFunctionElementZ(ObjectDecoder decoder) : super(decoder);
}

class StaticFunctionElementZ extends FunctionElementZ
    with ClassMemberMixin, StaticMemberMixin {
  StaticFunctionElementZ(ObjectDecoder decoder) : super(decoder);
}

class InstanceFunctionElementZ extends FunctionElementZ
    with ClassMemberMixin, InstanceMemberMixin {
  InstanceFunctionElementZ(ObjectDecoder decoder) : super(decoder);
}

abstract class LocalExecutableMixin
    implements DeserializedElementZ, ExecutableElement, LocalElement {
  ExecutableElement _executableContext;

  @override
  Element get enclosingElement => executableContext;

  @override
  Element get enclosingClass => memberContext.enclosingClass;

  @override
  ExecutableElement get executableContext {
    if (_executableContext == null) {
      _executableContext = _decoder.getElement(Key.EXECUTABLE_CONTEXT);
    }
    return _executableContext;
  }

  @override
  MemberElement get memberContext => executableContext.memberContext;

  @override
  bool get isLocal => true;

  @override
  LibraryElement get library => memberContext.library;

  @override
  CompilationUnitElement get compilationUnit {
    return memberContext.compilationUnit;
  }

  @override
  bool get hasTreeElements => memberContext.hasTreeElements;

  @override
  TreeElements get treeElements => memberContext.treeElements;
}

class LocalFunctionElementZ extends DeserializedElementZ
    with
        LocalExecutableMixin,
        AstElementMixinZ,
        ParametersMixin,
        FunctionTypedElementMixin,
        TypedElementMixin
    implements LocalFunctionElement {
  LocalFunctionElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitLocalFunctionElement(this, arg);
  }

  @override
  ElementKind get kind => ElementKind.FUNCTION;

  @override
  AsyncMarker get asyncMarker {
    return _decoder.getEnum(Key.ASYNC_MARKER, AsyncMarker.values);
  }
}

abstract class GetterElementZ extends DeserializedElementZ
    with
        AnalyzableElementMixin,
        AstElementMixinZ,
        FunctionTypedElementMixin,
        ParametersMixin,
        TypedElementMixin,
        MemberElementMixin
    implements GetterElement {
  AbstractFieldElement abstractField;
  SetterElement setter;

  GetterElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  ElementKind get kind => ElementKind.GETTER;

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitGetterElement(this, arg);
  }

  @override
  bool get isAbstract => _decoder.getBool(Key.IS_ABSTRACT);

  @override
  AsyncMarker get asyncMarker {
    return _decoder.getEnum(Key.ASYNC_MARKER, AsyncMarker.values);
  }
}

class TopLevelGetterElementZ extends GetterElementZ with LibraryMemberMixin {
  TopLevelGetterElementZ(ObjectDecoder decoder) : super(decoder);
}

class StaticGetterElementZ extends GetterElementZ
    with ClassMemberMixin, StaticMemberMixin {
  StaticGetterElementZ(ObjectDecoder decoder) : super(decoder);
}

class InstanceGetterElementZ extends GetterElementZ
    with ClassMemberMixin, InstanceMemberMixin {
  InstanceGetterElementZ(ObjectDecoder decoder) : super(decoder);
}

abstract class SetterElementZ extends DeserializedElementZ
    with
        AnalyzableElementMixin,
        AstElementMixinZ,
        FunctionTypedElementMixin,
        ParametersMixin,
        TypedElementMixin,
        MemberElementMixin
    implements SetterElement {
  AbstractFieldElement abstractField;
  GetterElement getter;

  SetterElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  ElementKind get kind => ElementKind.SETTER;

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitSetterElement(this, arg);
  }

  @override
  bool get isAbstract => _decoder.getBool(Key.IS_ABSTRACT);

  @override
  AsyncMarker get asyncMarker => AsyncMarker.SYNC;
}

class TopLevelSetterElementZ extends SetterElementZ with LibraryMemberMixin {
  TopLevelSetterElementZ(ObjectDecoder decoder) : super(decoder);
}

class StaticSetterElementZ extends SetterElementZ
    with ClassMemberMixin, StaticMemberMixin {
  StaticSetterElementZ(ObjectDecoder decoder) : super(decoder);
}

class InstanceSetterElementZ extends SetterElementZ
    with ClassMemberMixin, InstanceMemberMixin {
  InstanceSetterElementZ(ObjectDecoder decoder) : super(decoder);
}

abstract class TypeDeclarationMixin<T extends GenericType>
    implements ElementZ, TypeDeclarationElement {
  List<DartType> _typeVariables;
  T _rawType;
  T _thisType;
  Name _memberName;

  Name get memberName {
    if (_memberName == null) {
      _memberName = new Name(name, library);
    }
    return _memberName;
  }

  List<DartType> _getTypeVariables();

  void _ensureTypes() {
    if (_typeVariables == null) {
      _typeVariables = _getTypeVariables();
      _rawType = _createType(new List<DartType>.filled(
          _typeVariables.length, const DynamicType()));
      _thisType = _createType(_typeVariables);
    }
  }

  T _createType(List<DartType> typeArguments);

  @override
  List<DartType> get typeVariables {
    _ensureTypes();
    return _typeVariables;
  }

  @override
  T get rawType {
    _ensureTypes();
    return _rawType;
  }

  @override
  T get thisType {
    _ensureTypes();
    return _thisType;
  }

  @override
  T computeType(Resolution resolution) => thisType;

  @override
  bool get isResolved => true;
}

class TypedefElementZ extends DeserializedElementZ
    with
        AnalyzableElementMixin,
        AstElementMixinZ,
        LibraryMemberMixin,
        ParametersMixin,
        TypeDeclarationMixin<TypedefType>
    implements TypedefElement {
  DartType _alias;

  TypedefElementZ(ObjectDecoder decoder) : super(decoder);

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

  @override
  List<DartType> _getTypeVariables() {
    return _decoder.getTypes(Key.TYPE_VARIABLES, isOptional: true);
  }

  @override
  ElementKind get kind => ElementKind.TYPEDEF;

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitTypedefElement(this, arg);
  }

  @override
  DartType get alias {
    if (_alias == null) {
      _alias = _decoder.getType(Key.ALIAS);
    }
    return _alias;
  }

  @override
  void ensureResolved(Resolution resolution) {}

  @override
  void checkCyclicReference(Resolution resolution) {}
}

class TypeVariableElementZ extends DeserializedElementZ
    with AnalyzableElementMixin, AstElementMixinZ, TypedElementMixin
    implements TypeVariableElement {
  GenericElement _typeDeclaration;
  TypeVariableType _type;
  DartType _bound;
  Name _memberName;

  TypeVariableElementZ(ObjectDecoder decoder) : super(decoder);

  Name get memberName {
    if (_memberName == null) {
      _memberName = new Name(name, library);
    }
    return _memberName;
  }

  @override
  ElementKind get kind => ElementKind.TYPE_VARIABLE;

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitTypeVariableElement(this, arg);
  }

  @override
  CompilationUnitElement get compilationUnit {
    return typeDeclaration.compilationUnit;
  }

  @override
  Element get enclosingElement => typeDeclaration;

  @override
  Element get enclosingClass => typeDeclaration;

  @override
  int get index => _decoder.getInt(Key.INDEX);

  @override
  GenericElement get typeDeclaration {
    if (_typeDeclaration == null) {
      _typeDeclaration = _decoder.getElement(Key.TYPE_DECLARATION);
    }
    return _typeDeclaration;
  }

  DartType get bound {
    if (_bound == null) {
      _bound = _decoder.getType(Key.BOUND);
    }
    return _bound;
  }

  @override
  LibraryElement get library => typeDeclaration.library;
}

class SyntheticTypeVariableElementZ extends ElementZ
    with AnalyzableElementMixin, AstElementMixinZ
    implements TypeVariableElement {
  final TypeDeclarationElement typeDeclaration;
  final int index;
  final String name;
  TypeVariableType _type;
  DartType _bound;
  Name _memberName;

  SyntheticTypeVariableElementZ(this.typeDeclaration, this.index, this.name);

  Name get memberName {
    if (_memberName == null) {
      _memberName = new Name(name, library);
    }
    return _memberName;
  }

  @override
  ElementKind get kind => ElementKind.TYPE_VARIABLE;

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitTypeVariableElement(this, arg);
  }

  @override
  CompilationUnitElement get compilationUnit {
    return typeDeclaration.compilationUnit;
  }

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

  @override
  TypeVariableType computeType(Resolution resolution) => type;

  @override
  Element get enclosingElement => typeDeclaration;

  @override
  Element get enclosingClass => typeDeclaration;

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

  @override
  LibraryElement get library => typeDeclaration.library;

  @override
  int get sourceOffset => typeDeclaration.sourceOffset;

  @override
  SourceSpan get sourcePosition => typeDeclaration.sourcePosition;
}

abstract class ParameterElementZ extends DeserializedElementZ
    with AnalyzableElementMixin, AstElementMixinZ, TypedElementMixin
    implements ParameterElement {
  FunctionElement _functionDeclaration;
  ConstantExpression _constant;
  DartType _type;

  ParameterElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  bool get isFinal => _decoder.getBool(Key.IS_FINAL);

  @override
  bool get isConst => false;

  @override
  bool get hasConstant => true;

  @override
  ConstantExpression get constant {
    if (isOptional) {
      if (_constant == null) {
        _constant = _decoder.getConstant(Key.CONSTANT);
      }
      return _constant;
    }
    return null;
  }

  @override
  CompilationUnitElement get compilationUnit {
    return functionDeclaration.compilationUnit;
  }

  @override
  ExecutableElement get executableContext => functionDeclaration;

  @override
  Element get enclosingElement => functionDeclaration;

  @override
  FunctionElement get functionDeclaration {
    if (_functionDeclaration == null) {
      _functionDeclaration = _decoder.getElement(Key.FUNCTION);
    }
    return _functionDeclaration;
  }

  @override
  FunctionSignature get functionSignature => _unsupported('functionSignature');

  // TODO(johnniwinther): Remove [initializer] and [node] on
  // [ParameterElementZ] when the inference does need these.
  @override
  Expression initializer;

  @override
  Node node;

  @override
  bool get isNamed => _decoder.getBool(Key.IS_NAMED);

  @override
  bool get isOptional => _decoder.getBool(Key.IS_OPTIONAL);

  @override
  LibraryElement get library => executableContext.library;

  @override
  MemberElement get memberContext => executableContext.memberContext;

  @override
  List<DartType> get typeVariables => functionSignature.typeVariables;
}

class LocalParameterElementZ extends ParameterElementZ
    implements LocalParameterElement {
  LocalParameterElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitParameterElement(this, arg);
  }

  @override
  bool get isLocal => true;

  @override
  ElementKind get kind => ElementKind.PARAMETER;
}

class InitializingFormalElementZ extends LocalParameterElementZ
    implements InitializingFormalElement {
  FieldElement _fieldElement;

  InitializingFormalElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  FieldElement get fieldElement {
    if (_fieldElement == null) {
      _fieldElement = _decoder.getElement(Key.FIELD);
    }
    return _fieldElement;
  }

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitFieldParameterElement(this, arg);
  }

  @override
  ElementKind get kind => ElementKind.INITIALIZING_FORMAL;

  @override
  bool get isLocal => true;
}

class LocalVariableElementZ extends DeserializedElementZ
    with
        AnalyzableElementMixin,
        AstElementMixinZ,
        LocalExecutableMixin,
        TypedElementMixin
    implements LocalVariableElement {
  bool _isConst;
  ConstantExpression _constant;

  LocalVariableElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  accept(ElementVisitor visitor, arg) {
    return visitor.visitLocalVariableElement(this, arg);
  }

  @override
  ElementKind get kind => ElementKind.VARIABLE;

  @override
  bool get isFinal => _decoder.getBool(Key.IS_FINAL);

  @override
  bool get isConst {
    if (_isConst == null) {
      _constant = _decoder.getConstant(Key.CONSTANT, isOptional: true);
      _isConst = _constant != null;
    }
    return _isConst;
  }

  @override
  bool get hasConstant => true;

  @override
  ConstantExpression get constant {
    if (isConst) {
      return _constant;
    }
    return null;
  }

  @override
  Expression get initializer => _unsupported('initializer');
}

class ImportElementZ extends DeserializedElementZ
    with LibraryMemberMixin
    implements ImportElement {
  bool _isDeferred;
  PrefixElement _prefix;
  LibraryElement _importedLibrary;
  Uri _uri;

  ImportElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  String get name => '';

  @override
  accept(ElementVisitor visitor, arg) => visitor.visitImportElement(this, arg);

  @override
  ElementKind get kind => ElementKind.IMPORT;

  @override
  LibraryElement get importedLibrary {
    if (_importedLibrary == null) {
      _importedLibrary = _decoder.getElement(Key.LIBRARY_DEPENDENCY);
    }
    return _importedLibrary;
  }

  void _ensurePrefixResolved() {
    if (_isDeferred == null) {
      _isDeferred = _decoder.getBool(Key.IS_DEFERRED);
      _prefix = _decoder.getElement(Key.PREFIX, isOptional: true);
    }
  }

  @override
  bool get isDeferred {
    _ensurePrefixResolved();
    return _isDeferred;
  }

  @override
  PrefixElement get prefix {
    _ensurePrefixResolved();
    return _prefix;
  }

  @override
  Uri get uri {
    if (_uri == null) {
      _uri = _decoder.getUri(Key.URI);
    }
    return _uri;
  }

  @override
  Import get node => _unsupported('node');

  String toString() => 'Z$kind($uri)';
}

class ExportElementZ extends DeserializedElementZ
    with LibraryMemberMixin
    implements ExportElement {
  LibraryElement _exportedLibrary;
  Uri _uri;

  ExportElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  String get name => '';

  @override
  accept(ElementVisitor visitor, arg) => visitor.visitExportElement(this, arg);

  @override
  ElementKind get kind => ElementKind.EXPORT;

  @override
  LibraryElement get exportedLibrary {
    if (_exportedLibrary == null) {
      _exportedLibrary = _decoder.getElement(Key.LIBRARY_DEPENDENCY);
    }
    return _exportedLibrary;
  }

  @override
  Uri get uri {
    if (_uri == null) {
      _uri = _decoder.getUri(Key.URI);
    }
    return _uri;
  }

  @override
  Export get node => _unsupported('node');

  String toString() => 'Z$kind($uri)';
}

class PrefixElementZ extends DeserializedElementZ
    with LibraryMemberMixin
    implements PrefixElement {
  bool _isDeferred;
  ImportElement _deferredImport;
  GetterElement _loadLibrary;
  ListedContainer _members;

  PrefixElementZ(ObjectDecoder decoder) : super(decoder);

  @override
  accept(ElementVisitor visitor, arg) => visitor.visitPrefixElement(this, arg);

  @override
  bool get isTopLevel => false;

  void _ensureDeferred() {
    if (_isDeferred == null) {
      _isDeferred = _decoder.getBool(Key.IS_DEFERRED);
      if (_isDeferred) {
        _deferredImport = _decoder.getElement(Key.IMPORT);
        _loadLibrary = _decoder.getElement(Key.GETTER);
      }
    }
  }

  @override
  ImportElement get deferredImport {
    _ensureDeferred();
    return _deferredImport;
  }

  @override
  bool get isDeferred {
    _ensureDeferred();
    return _isDeferred;
  }

  @override
  GetterElement get loadLibrary {
    return _loadLibrary;
  }

  @override
  ElementKind get kind => ElementKind.PREFIX;

  void _ensureMembers() {
    if (_members == null) {
      _members = new ListedContainer(
          _decoder.getElements(Key.MEMBERS, isOptional: true));
    }
  }

  @override
  Element lookupLocalMember(String memberName) {
    _ensureMembers();
    return _members.lookup(memberName);
  }

  @override
  void forEachLocalMember(void f(Element member)) {
    _ensureMembers();
    _members.forEach(f);
  }
}

class MetadataAnnotationZ implements MetadataAnnotation {
  final Element annotatedElement;
  final SourceSpan sourcePosition;
  final ConstantExpression constant;

  MetadataAnnotationZ(
      this.annotatedElement, this.sourcePosition, this.constant);

  @override
  MetadataAnnotation ensureResolved(Resolution resolution) {
    // Do nothing.
  }

  @override
  Node get node => throw new UnsupportedError('${this}.node');

  @override
  bool get hasNode => false;

  String toString() => 'MetadataAnnotationZ(${constant.toDartText()})';
}
