// Copyright (c) 2016, 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 dart2js.serialization.resolved_ast;

import '../common.dart';
import '../common/resolution.dart';
import '../constants/expressions.dart';
import '../dart_types.dart';
import '../diagnostics/diagnostic_listener.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart';
import '../parser/listener.dart' show ParserError;
import '../parser/node_listener.dart' show NodeListener;
import '../parser/parser.dart' show Parser;
import '../resolution/enum_creator.dart';
import '../resolution/send_structure.dart';
import '../resolution/tree_elements.dart';
import '../tokens/token.dart';
import '../tree/tree.dart';
import '../universe/selector.dart';
import '../util/util.dart';
import 'keys.dart';
import 'modelz.dart';
import 'serialization.dart';
import 'serialization_util.dart';
import 'modelz.dart';

/// Visitor that computes a node-index mapping.
class AstIndexComputer extends Visitor {
  final Map<Node, int> nodeIndices = <Node, int>{};
  final List<Node> nodeList = <Node>[];

  @override
  visitNode(Node node) {
    nodeIndices.putIfAbsent(node, () {
      // Some nodes (like Modifier and empty NodeList) can be reused.
      nodeList.add(node);
      return nodeIndices.length;
    });
    node.visitChildren(this);
  }
}

/// The kind of AST node. Used for determining how to deserialize
/// [ResolvedAst]s.
enum AstKind {
  ENUM_CONSTRUCTOR,
  ENUM_CONSTANT,
  ENUM_INDEX_FIELD,
  ENUM_VALUES_FIELD,
  ENUM_TO_STRING,
  FACTORY,
  FIELD,
  FUNCTION,
}

/// Serializer for [ResolvedAst]s.
class ResolvedAstSerializer extends Visitor {
  final SerializerPlugin nativeDataSerializer;
  final ObjectEncoder objectEncoder;
  final ResolvedAst resolvedAst;
  final AstIndexComputer indexComputer = new AstIndexComputer();
  final Map<int, ObjectEncoder> nodeData = <int, ObjectEncoder>{};
  ListEncoder _nodeDataEncoder;

  ResolvedAstSerializer(
      this.objectEncoder, this.resolvedAst, this.nativeDataSerializer);

  AstElement get element => resolvedAst.element;

  TreeElements get elements => resolvedAst.elements;

  Node get root => resolvedAst.node;

  Map<Node, int> get nodeIndices => indexComputer.nodeIndices;
  List<Node> get nodeList => indexComputer.nodeList;

  Map<JumpTarget, int> jumpTargetMap = <JumpTarget, int>{};
  Map<LabelDefinition, int> labelDefinitionMap = <LabelDefinition, int>{};

  /// Returns the unique id for [jumpTarget], creating it if necessary.
  int getJumpTargetId(JumpTarget jumpTarget) {
    return jumpTargetMap.putIfAbsent(jumpTarget, () => jumpTargetMap.length);
  }

  /// Returns the unique id for [labelDefinition], creating it if necessary.
  int getLabelDefinitionId(LabelDefinition labelDefinition) {
    return labelDefinitionMap.putIfAbsent(
        labelDefinition, () => labelDefinitionMap.length);
  }

  /// Serializes [resolvedAst] into [objectEncoder].
  void serialize() {
    objectEncoder.setEnum(Key.KIND, resolvedAst.kind);
    switch (resolvedAst.kind) {
      case ResolvedAstKind.PARSED:
        serializeParsed();
        break;
      case ResolvedAstKind.DEFAULT_CONSTRUCTOR:
      case ResolvedAstKind.FORWARDING_CONSTRUCTOR:
        // No additional properties.
        break;
    }
  }

  /// Serialize [ResolvedAst] that is defined in terms of an AST together with
  /// [TreeElements].
  void serializeParsed() {
    objectEncoder.setUri(
        Key.URI,
        elements.analyzedElement.compilationUnit.script.resourceUri,
        elements.analyzedElement.compilationUnit.script.resourceUri);
    AstKind kind;
    if (element.enclosingClass is EnumClassElement) {
      if (element.name == 'index') {
        kind = AstKind.ENUM_INDEX_FIELD;
      } else if (element.name == 'values') {
        kind = AstKind.ENUM_VALUES_FIELD;
      } else if (element.name == 'toString') {
        kind = AstKind.ENUM_TO_STRING;
      } else if (element.isConstructor) {
        kind = AstKind.ENUM_CONSTRUCTOR;
      } else {
        assert(invariant(element, element.isConst,
            message: "Unexpected enum member: $element"));
        kind = AstKind.ENUM_CONSTANT;
      }
    } else {
      // [element] has a body that we'll need to re-parse. We store where to
      // start parsing from.
      objectEncoder.setInt(Key.OFFSET, root.getBeginToken().charOffset);
      if (element.isFactoryConstructor) {
        kind = AstKind.FACTORY;
      } else if (element.isField) {
        kind = AstKind.FIELD;
      } else {
        kind = AstKind.FUNCTION;
        FunctionExpression functionExpression = root.asFunctionExpression();
        if (functionExpression.getOrSet != null) {
          // Getters/setters need the get/set token to be parsed.
          objectEncoder.setInt(
              Key.GET_OR_SET, functionExpression.getOrSet.charOffset);
        }
      }
    }
    objectEncoder.setEnum(Key.SUB_KIND, kind);
    root.accept(indexComputer);
    objectEncoder.setBool(Key.CONTAINS_TRY, elements.containsTryStatement);
    if (resolvedAst.body != null) {
      int index = nodeIndices[resolvedAst.body];
      assert(invariant(element, index != null,
          message: "No index for body of $element: "
              "${resolvedAst.body} ($nodeIndices)."));
      objectEncoder.setInt(Key.BODY, index);
    }
    root.accept(this);
    if (jumpTargetMap.isNotEmpty) {
      ListEncoder list = objectEncoder.createList(Key.JUMP_TARGETS);
      for (JumpTarget jumpTarget in jumpTargetMap.keys) {
        serializeJumpTarget(jumpTarget, list.createObject());
      }
    }
    if (labelDefinitionMap.isNotEmpty) {
      ListEncoder list = objectEncoder.createList(Key.LABEL_DEFINITIONS);
      for (LabelDefinition labelDefinition in labelDefinitionMap.keys) {
        serializeLabelDefinition(labelDefinition, list.createObject());
      }
    }
    if (element is FunctionElement) {
      FunctionElement function = element;
      function.functionSignature.forEachParameter((ParameterElement parameter) {
        ParameterElement parameterImpl = parameter.implementation;
        // TODO(johnniwinther): Should we support element->node mapping as well?
        getNodeDataEncoder(parameterImpl.node)
            .setElement(PARAMETER_NODE, parameter);
        if (parameter.initializer != null) {
          getNodeDataEncoder(parameterImpl.initializer)
              .setElement(PARAMETER_INITIALIZER, parameter);
        }
      });
    }
  }

  /// Serialize [target] into [encoder].
  void serializeJumpTarget(JumpTarget jumpTarget, ObjectEncoder encoder) {
    encoder.setElement(Key.EXECUTABLE_CONTEXT, jumpTarget.executableContext);
    encoder.setInt(Key.NODE, nodeIndices[jumpTarget.statement]);
    encoder.setInt(Key.NESTING_LEVEL, jumpTarget.nestingLevel);
    encoder.setBool(Key.IS_BREAK_TARGET, jumpTarget.isBreakTarget);
    encoder.setBool(Key.IS_CONTINUE_TARGET, jumpTarget.isContinueTarget);
    if (jumpTarget.labels.isNotEmpty) {
      List<int> labelIdList = <int>[];
      for (LabelDefinition label in jumpTarget.labels) {
        labelIdList.add(getLabelDefinitionId(label));
      }
      encoder.setInts(Key.LABELS, labelIdList);
    }
  }

  /// Serialize [label] into [encoder].
  void serializeLabelDefinition(
      LabelDefinition labelDefinition, ObjectEncoder encoder) {
    encoder.setInt(Key.NODE, nodeIndices[labelDefinition.label]);
    encoder.setString(Key.NAME, labelDefinition.labelName);
    encoder.setBool(Key.IS_BREAK_TARGET, labelDefinition.isBreakTarget);
    encoder.setBool(Key.IS_CONTINUE_TARGET, labelDefinition.isContinueTarget);
    encoder.setInt(Key.JUMP_TARGET, getJumpTargetId(labelDefinition.target));
  }

  /// Computes the [ListEncoder] for serializing data for nodes.
  ListEncoder get nodeDataEncoder {
    if (_nodeDataEncoder == null) {
      _nodeDataEncoder = objectEncoder.createList(Key.DATA);
    }
    return _nodeDataEncoder;
  }

  /// Computes the [ObjectEncoder] for serializing data for [node].
  ObjectEncoder getNodeDataEncoder(Node node) {
    assert(invariant(element, node != null, message: "Node must be non-null."));
    int id = nodeIndices[node];
    assert(invariant(element, id != null, message: "Node without id: $node"));
    return nodeData.putIfAbsent(id, () {
      ObjectEncoder objectEncoder = nodeDataEncoder.createObject();
      objectEncoder.setInt(Key.ID, id);
      return objectEncoder;
    });
  }

  @override
  visitNode(Node node) {
    Element nodeElement = elements[node];
    if (nodeElement != null) {
      serializeElementReference(element, Key.ELEMENT, Key.NAME,
          getNodeDataEncoder(node), nodeElement);
    }
    DartType type = elements.getType(node);
    if (type != null) {
      getNodeDataEncoder(node).setType(Key.TYPE, type);
    }
    Selector selector = elements.getSelector(node);
    if (selector != null) {
      serializeSelector(
          selector, getNodeDataEncoder(node).createObject(Key.SELECTOR));
    }
    ConstantExpression constant = elements.getConstant(node);
    if (constant != null) {
      getNodeDataEncoder(node).setConstant(Key.CONSTANT, constant);
    }
    DartType cachedType = elements.typesCache[node];
    if (cachedType != null) {
      getNodeDataEncoder(node).setType(Key.CACHED_TYPE, cachedType);
    }
    JumpTarget jumpTargetDefinition = elements.getTargetDefinition(node);
    if (jumpTargetDefinition != null) {
      getNodeDataEncoder(node).setInt(
          Key.JUMP_TARGET_DEFINITION, getJumpTargetId(jumpTargetDefinition));
    }
    var nativeData = elements.getNativeData(node);
    if (nativeData != null) {
      nativeDataSerializer.onData(
          nativeData, getNodeDataEncoder(node).createObject(Key.NATIVE));
    }
    node.visitChildren(this);
  }

  @override
  visitSend(Send node) {
    visitExpression(node);
    SendStructure structure = elements.getSendStructure(node);
    if (structure != null) {
      serializeSendStructure(
          structure, getNodeDataEncoder(node).createObject(Key.SEND_STRUCTURE));
    }
  }

  @override
  visitNewExpression(NewExpression node) {
    visitExpression(node);
    NewStructure structure = elements.getNewStructure(node);
    if (structure != null) {
      serializeNewStructure(
          structure, getNodeDataEncoder(node).createObject(Key.NEW_STRUCTURE));
    }
  }

  @override
  visitGotoStatement(GotoStatement node) {
    visitStatement(node);
    JumpTarget jumpTarget = elements.getTargetOf(node);
    if (jumpTarget != null) {
      getNodeDataEncoder(node)
          .setInt(Key.JUMP_TARGET, getJumpTargetId(jumpTarget));
    }
    if (node.target != null) {
      LabelDefinition targetLabel = elements.getTargetLabel(node);
      if (targetLabel != null) {
        getNodeDataEncoder(node)
            .setInt(Key.TARGET_LABEL, getLabelDefinitionId(targetLabel));
      }
    }
  }

  @override
  visitLabel(Label node) {
    visitNode(node);
    LabelDefinition labelDefinition = elements.getLabelDefinition(node);
    if (labelDefinition != null) {
      getNodeDataEncoder(node)
          .setInt(Key.LABEL_DEFINITION, getLabelDefinitionId(labelDefinition));
    }
  }

  @override
  visitFunctionExpression(FunctionExpression node) {
    visitExpression(node);
    Element function = elements.getFunctionDefinition(node);
    if (function != null && function.isFunction && function.isLocal) {
      // Mark root nodes of local functions; these need their own ResolvedAst.
      getNodeDataEncoder(node).setElement(Key.FUNCTION, function);
    }
  }
}

class ResolvedAstDeserializer {
  /// Find the [Token] at [offset] searching through successors of [token].
  static Token findTokenInStream(Token token, int offset) {
    while (token.charOffset <= offset && token.next != token) {
      if (token.charOffset == offset) {
        return token;
      }
      token = token.next;
    }
    return null;
  }

  /// Deserializes the [ResolvedAst]s for [element] and its nested local
  /// functions from [objectDecoder] and adds these to [resolvedAstMap].
  /// [parsing] and [getBeginToken] are used for parsing the [Node] for
  /// [element] from its source code.
  static void deserialize(
      Element element,
      ObjectDecoder objectDecoder,
      ParsingContext parsing,
      Token getBeginToken(Uri uri, int charOffset),
      DeserializerPlugin nativeDataDeserializer) {
    ResolvedAstKind kind =
        objectDecoder.getEnum(Key.KIND, ResolvedAstKind.values);
    switch (kind) {
      case ResolvedAstKind.PARSED:
        deserializeParsed(element, objectDecoder, parsing, getBeginToken,
            nativeDataDeserializer);
        break;
      case ResolvedAstKind.DEFAULT_CONSTRUCTOR:
      case ResolvedAstKind.FORWARDING_CONSTRUCTOR:
        (element as AstElementMixinZ).resolvedAst =
            new SynthesizedResolvedAst(element, kind);
        break;
    }
  }

  /// Deserialize the [ResolvedAst]s for the member [element] (constructor,
  /// method, or field) and its nested closures. The [ResolvedAst]s are added
  /// to [resolvedAstMap].
  static void deserializeParsed(
      AstElementMixinZ element,
      ObjectDecoder objectDecoder,
      ParsingContext parsing,
      Token getBeginToken(Uri uri, int charOffset),
      DeserializerPlugin nativeDataDeserializer) {
    CompilationUnitElement compilationUnit = element.compilationUnit;
    DiagnosticReporter reporter = parsing.reporter;
    Uri uri = objectDecoder.getUri(Key.URI);

    /// Returns the first [Token] for parsing the [Node] for [element].
    Token readBeginToken() {
      int charOffset = objectDecoder.getInt(Key.OFFSET);
      Token beginToken = getBeginToken(uri, charOffset);
      if (beginToken == null) {
        // TODO(johnniwinther): Handle unfound tokens by adding an erronous
        // resolved ast kind.
        reporter.internalError(
            element, "No token found for $element in $uri @ $charOffset");
      }
      return beginToken;
    }

    /// Create the [Node] for the element by parsing the source code.
    Node doParse(parse(Parser parser)) {
      return parsing.measure(() {
        return reporter.withCurrentElement(element, () {
          CompilationUnitElement unit = element.compilationUnit;
          NodeListener listener = new NodeListener(
              parsing.getScannerOptionsFor(element), reporter, null);
          listener.memberErrors = listener.memberErrors.prepend(false);
          try {
            Parser parser = new Parser(listener, parsing.parserOptions);
            parse(parser);
          } on ParserError catch (e) {
            reporter.internalError(element, '$e');
          }
          return listener.popNode();
        });
      });
    }

    /// Computes the [Node] for the element based on the [AstKind].
    Node computeNode(AstKind kind) {
      switch (kind) {
        case AstKind.ENUM_INDEX_FIELD:
          AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
          Identifier identifier = builder.identifier('index');
          VariableDefinitions node = new VariableDefinitions(
              null,
              builder.modifiers(isFinal: true),
              new NodeList.singleton(identifier));
          return node;
        case AstKind.ENUM_VALUES_FIELD:
          EnumClassElement enumClass = element.enclosingClass;
          AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
          List<FieldElement> enumValues = <FieldElement>[];
          List<Node> valueReferences = <Node>[];
          for (EnumConstantElement enumConstant in enumClass.enumValues) {
            AstBuilder valueBuilder =
                new AstBuilder(enumConstant.sourcePosition.begin);
            Identifier name = valueBuilder.identifier(enumConstant.name);

            // Add reference for the `values` field.
            valueReferences.add(valueBuilder.reference(name));
          }

          Identifier valuesIdentifier = builder.identifier('values');
          // TODO(johnniwinther): Add type argument.
          Expression initializer =
              builder.listLiteral(valueReferences, isConst: true);

          Node definition =
              builder.createDefinition(valuesIdentifier, initializer);
          VariableDefinitions node = new VariableDefinitions(
              null,
              builder.modifiers(isStatic: true, isConst: true),
              new NodeList.singleton(definition));
          return node;
        case AstKind.ENUM_TO_STRING:
          EnumClassElement enumClass = element.enclosingClass;
          AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
          List<LiteralMapEntry> mapEntries = <LiteralMapEntry>[];
          for (EnumConstantElement enumConstant in enumClass.enumValues) {
            AstBuilder valueBuilder =
                new AstBuilder(enumConstant.sourcePosition.begin);
            Identifier name = valueBuilder.identifier(enumConstant.name);

            // Add map entry for `toString` implementation.
            mapEntries.add(valueBuilder.mapLiteralEntry(
                valueBuilder.literalInt(enumConstant.index),
                valueBuilder
                    .literalString('${enumClass.name}.${name.source}')));
          }

          // TODO(johnniwinther): Support return type. Note `String` might be
          // prefixed or not imported within the current library.
          FunctionExpression toStringNode = builder.functionExpression(
              Modifiers.EMPTY,
              'toString',
              null,
              builder.argumentList([]),
              builder.returnStatement(builder.indexGet(
                  builder.mapLiteral(mapEntries, isConst: true),
                  builder.reference(builder.identifier('index')))));
          return toStringNode;
        case AstKind.ENUM_CONSTRUCTOR:
          AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
          VariableDefinitions indexDefinition =
              builder.initializingFormal('index');
          FunctionExpression constructorNode = builder.functionExpression(
              builder.modifiers(isConst: true),
              element.enclosingClass.name,
              null,
              builder.argumentList([indexDefinition]),
              builder.emptyStatement());
          return constructorNode;
        case AstKind.ENUM_CONSTANT:
          EnumConstantElementZ enumConstant = element;
          EnumClassElement enumClass = element.enclosingClass;
          int index = enumConstant.index;
          AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
          Identifier name = builder.identifier(element.name);

          Expression initializer = builder.newExpression(
              enumClass.name, builder.argumentList([builder.literalInt(index)]),
              isConst: true);
          SendSet definition = builder.createDefinition(name, initializer);

          VariableDefinitions node = new VariableDefinitions(
              null,
              builder.modifiers(isStatic: true, isConst: true),
              new NodeList.singleton(definition));
          return node;
        case AstKind.FACTORY:
          Token beginToken = readBeginToken();
          return doParse((parser) => parser.parseFactoryMethod(beginToken));
        case AstKind.FIELD:
          Token beginToken = readBeginToken();
          return doParse((parser) => parser.parseMember(beginToken));
        case AstKind.FUNCTION:
          Token beginToken = readBeginToken();
          int getOrSetOffset =
              objectDecoder.getInt(Key.GET_OR_SET, isOptional: true);
          Token getOrSet;
          if (getOrSetOffset != null) {
            getOrSet = findTokenInStream(beginToken, getOrSetOffset);
            if (getOrSet == null) {
              reporter.internalError(
                  element,
                  "No token found for $element in "
                  "${objectDecoder.getUri(Key.URI)} @ $getOrSetOffset");
            }
          }
          return doParse((parser) {
            parser.parseFunction(beginToken, getOrSet);
          });
      }
    }

    AstKind kind = objectDecoder.getEnum(Key.SUB_KIND, AstKind.values);
    Node root = computeNode(kind);
    TreeElementMapping elements = new TreeElementMapping(element);
    AstIndexComputer indexComputer = new AstIndexComputer();
    Map<Node, int> nodeIndices = indexComputer.nodeIndices;
    List<Node> nodeList = indexComputer.nodeList;
    root.accept(indexComputer);
    elements.containsTryStatement = objectDecoder.getBool(Key.CONTAINS_TRY);

    Node body;
    int bodyNodeIndex = objectDecoder.getInt(Key.BODY, isOptional: true);
    if (bodyNodeIndex != null) {
      assert(invariant(element, bodyNodeIndex < nodeList.length,
          message: "Body node index ${bodyNodeIndex} out of range. "
              "Node count: ${nodeList.length}"));
      body = nodeList[bodyNodeIndex];
    }

    List<JumpTarget> jumpTargets = <JumpTarget>[];
    Map<JumpTarget, List<int>> jumpTargetLabels = <JumpTarget, List<int>>{};
    List<LabelDefinition> labelDefinitions = <LabelDefinition>[];

    ListDecoder jumpTargetsDecoder =
        objectDecoder.getList(Key.JUMP_TARGETS, isOptional: true);
    if (jumpTargetsDecoder != null) {
      for (int i = 0; i < jumpTargetsDecoder.length; i++) {
        ObjectDecoder decoder = jumpTargetsDecoder.getObject(i);
        ExecutableElement executableContext =
            decoder.getElement(Key.EXECUTABLE_CONTEXT);
        Node statement = nodeList[decoder.getInt(Key.NODE)];
        int nestingLevel = decoder.getInt(Key.NESTING_LEVEL);
        JumpTarget jumpTarget =
            new JumpTargetX(statement, nestingLevel, executableContext);
        jumpTarget.isBreakTarget = decoder.getBool(Key.IS_BREAK_TARGET);
        jumpTarget.isContinueTarget = decoder.getBool(Key.IS_CONTINUE_TARGET);
        jumpTargetLabels[jumpTarget] =
            decoder.getInts(Key.LABELS, isOptional: true);
        jumpTargets.add(jumpTarget);
      }
    }

    ListDecoder labelDefinitionsDecoder =
        objectDecoder.getList(Key.LABEL_DEFINITIONS, isOptional: true);
    if (labelDefinitionsDecoder != null) {
      for (int i = 0; i < labelDefinitionsDecoder.length; i++) {
        ObjectDecoder decoder = labelDefinitionsDecoder.getObject(i);
        Label label = nodeList[decoder.getInt(Key.NODE)];
        String labelName = decoder.getString(Key.NAME);
        JumpTarget target = jumpTargets[decoder.getInt(Key.JUMP_TARGET)];
        LabelDefinitionX labelDefinition =
            new LabelDefinitionX(label, labelName, target);
        labelDefinition.isBreakTarget = decoder.getBool(Key.IS_BREAK_TARGET);
        labelDefinition.isContinueTarget =
            decoder.getBool(Key.IS_CONTINUE_TARGET);
        labelDefinitions.add(labelDefinition);
      }
    }
    jumpTargetLabels.forEach((JumpTargetX jumpTarget, List<int> labelIds) {
      if (labelIds.isEmpty) return;
      LinkBuilder<LabelDefinition> linkBuilder =
          new LinkBuilder<LabelDefinition>();
      for (int labelId in labelIds) {
        linkBuilder.addLast(labelDefinitions[labelId]);
      }
      jumpTarget.labels = linkBuilder.toLink();
    });

    ListDecoder dataDecoder = objectDecoder.getList(Key.DATA, isOptional: true);
    if (dataDecoder != null) {
      for (int i = 0; i < dataDecoder.length; i++) {
        ObjectDecoder objectDecoder = dataDecoder.getObject(i);
        int id = objectDecoder.getInt(Key.ID);
        Node node = nodeList[id];
        Element nodeElement = deserializeElementReference(
            element, Key.ELEMENT, Key.NAME, objectDecoder,
            isOptional: true);
        if (nodeElement != null) {
          elements[node] = nodeElement;
        }
        DartType type = objectDecoder.getType(Key.TYPE, isOptional: true);
        if (type != null) {
          elements.setType(node, type);
        }
        ObjectDecoder selectorDecoder =
            objectDecoder.getObject(Key.SELECTOR, isOptional: true);
        if (selectorDecoder != null) {
          elements.setSelector(node, deserializeSelector(selectorDecoder));
        }
        ConstantExpression constant =
            objectDecoder.getConstant(Key.CONSTANT, isOptional: true);
        if (constant != null) {
          elements.setConstant(node, constant);
        }
        DartType cachedType =
            objectDecoder.getType(Key.CACHED_TYPE, isOptional: true);
        if (cachedType != null) {
          elements.typesCache[node] = cachedType;
        }
        ObjectDecoder sendStructureDecoder =
            objectDecoder.getObject(Key.SEND_STRUCTURE, isOptional: true);
        if (sendStructureDecoder != null) {
          elements.setSendStructure(
              node, deserializeSendStructure(sendStructureDecoder));
        }
        ObjectDecoder newStructureDecoder =
            objectDecoder.getObject(Key.NEW_STRUCTURE, isOptional: true);
        if (newStructureDecoder != null) {
          elements.setNewStructure(
              node, deserializeNewStructure(newStructureDecoder));
        }
        int targetDefinitionId =
            objectDecoder.getInt(Key.JUMP_TARGET_DEFINITION, isOptional: true);
        if (targetDefinitionId != null) {
          elements.defineTarget(node, jumpTargets[targetDefinitionId]);
        }
        int targetOfId =
            objectDecoder.getInt(Key.JUMP_TARGET, isOptional: true);
        if (targetOfId != null) {
          elements.registerTargetOf(node, jumpTargets[targetOfId]);
        }
        int labelDefinitionId =
            objectDecoder.getInt(Key.LABEL_DEFINITION, isOptional: true);
        if (labelDefinitionId != null) {
          elements.defineLabel(node, labelDefinitions[labelDefinitionId]);
        }
        int targetLabelId =
            objectDecoder.getInt(Key.TARGET_LABEL, isOptional: true);
        if (targetLabelId != null) {
          elements.registerTargetLabel(node, labelDefinitions[targetLabelId]);
        }
        ObjectDecoder nativeDataDecoder =
            objectDecoder.getObject(Key.NATIVE, isOptional: true);
        if (nativeDataDecoder != null) {
          var nativeData = nativeDataDeserializer.onData(nativeDataDecoder);
          if (nativeData != null) {
            elements.registerNativeData(node, nativeData);
          }
        }
        LocalFunctionElementZ function =
            objectDecoder.getElement(Key.FUNCTION, isOptional: true);
        if (function != null) {
          FunctionExpression functionExpression = node;
          function.resolvedAst = new ParsedResolvedAst(function,
              functionExpression, functionExpression.body, elements, uri);
        }
        // TODO(johnniwinther): Remove these when inference doesn't need `.node`
        // and `.initializer` of [ParameterElement]s.
        ParameterElementZ parameter =
            objectDecoder.getElement(PARAMETER_NODE, isOptional: true);
        if (parameter != null) {
          parameter.node = node;
        }
        parameter =
            objectDecoder.getElement(PARAMETER_INITIALIZER, isOptional: true);
        if (parameter != null) {
          parameter.initializer = node;
        }
      }
    }
    element.resolvedAst =
        new ParsedResolvedAst(element, root, body, elements, uri);
  }
}

const Key PARAMETER_NODE = const Key('parameter.node');
const Key PARAMETER_INITIALIZER = const Key('parameter.initializer');
