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

import 'package:analyzer/src/fasta/resolution_applier.dart';
import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart';
import 'package:front_end/src/fasta/kernel/kernel_type_variable_builder.dart';
import 'package:front_end/src/fasta/type_inference/type_inference_listener.dart';
import 'package:front_end/src/scanner/token.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/type_algebra.dart';

class ResolutionData {
  final List<DartType> argumentTypes;
  final Node combiner;
  final int declaration;
  final DartType inferredType;
  final DartType invokeType;
  final bool isExplicitCall;
  final bool isImplicitCall;
  final bool isNamespaceCombinatorReference;
  final bool isOutline;
  final bool isPrefixReference;
  final bool isTypeReference;
  final bool isWriteReference;
  final Node loadLibrary;
  final int prefixInfo;
  final DartType receiverType;
  final Node reference;
  final DartType writeContext;

  ResolutionData(
      {this.argumentTypes,
      this.combiner,
      this.declaration,
      this.inferredType,
      this.invokeType,
      this.isExplicitCall = false,
      this.isImplicitCall = false,
      this.isNamespaceCombinatorReference = false,
      this.isOutline = false,
      this.isPrefixReference = false,
      this.isTypeReference = false,
      this.isWriteReference = false,
      this.loadLibrary,
      this.prefixInfo,
      this.receiverType,
      this.reference,
      this.writeContext});
}

/// Type inference listener that records inferred types for later use by
/// [ResolutionApplier].
class ResolutionStorer
    implements TypeInferenceListener<int, Node, int>, TypeInferenceTokensSaver {
  final Map<int, ResolutionData> _data;

  final Map<TypeParameter, int> _typeVariableDeclarations;

  ResolutionStorer(Map<int, ResolutionData> data,
      Map<TypeParameter, int> typeVariableDeclarations)
      : _data = data,
        _typeVariableDeclarations = typeVariableDeclarations;

  @override
  TypeInferenceTokensSaver get typeInferenceTokensSaver => this;

  @override
  AsExpressionTokens asExpressionTokens(Token asOperator) {
    return new AsExpressionTokens(asOperator);
  }

  void asExpression(ExpressionJudgment judgment, int location, void expression,
      AsExpressionTokens tokens, void literalType, DartType inferredType) {
    _store(location, inferredType: inferredType);
  }

  @override
  AssertInitializerTokens assertInitializerTokens(Token assertKeyword,
      Token leftParenthesis, Token comma, Token rightParenthesis) {
    return new AssertInitializerTokens(
        assertKeyword, leftParenthesis, comma, rightParenthesis);
  }

  void assertInitializer(InitializerJudgment judgment, int location,
      AssertInitializerTokens tokens, void condition, void message) {}

  @override
  AssertStatementTokens assertStatementTokens(
      Token assertKeyword,
      Token leftParenthesis,
      Token comma,
      Token rightParenthesis,
      Token semicolon) {
    return new AssertStatementTokens(
        assertKeyword, leftParenthesis, comma, rightParenthesis, semicolon);
  }

  void assertStatement(StatementJudgment judgment, int location,
      AssertStatementTokens Tokens, void condition, void message) {}

  AwaitExpressionTokens awaitExpressionTokens(Token awaitKeyword) {
    return new AwaitExpressionTokens(awaitKeyword);
  }

  void awaitExpression(
          ExpressionJudgment judgment,
          int location,
          AwaitExpressionTokens tokens,
          void expression,
          DartType inferredType) =>
      genericExpression("awaitExpression", location, inferredType);

  Object binderForFunctionDeclaration(
      StatementJudgment judgment, int fileOffset, String name) {
    return new VariableDeclarationBinder(fileOffset, false);
  }

  void binderForStatementLabel(
      StatementJudgment judgment, int fileOffset, String name) {}

  void binderForSwitchLabel(
      SwitchCaseJudgment judgment, int fileOffset, String name) {}

  TypeVariableBinder binderForTypeVariable(
      KernelTypeVariableBuilder builder, int fileOffset, String name) {
    return new TypeVariableBinder(fileOffset);
  }

  Object binderForVariableDeclaration(StatementJudgment judgment,
      int fileOffset, String name, bool forSyntheticToken) {
    return new VariableDeclarationBinder(fileOffset, forSyntheticToken);
  }

  BlockTokens blockTokens(Token leftBracket, Token rightBracket) {
    return new BlockTokens(leftBracket, rightBracket);
  }

  void block(StatementJudgment judgment, int location, BlockTokens tokens,
      List<void> statements) {}

  BoolLiteralTokens boolLiteralTokens(Token literal) {
    return new BoolLiteralTokens(literal);
  }

  void boolLiteral(ExpressionJudgment judgment, int location,
          BoolLiteralTokens tokens, bool value, DartType inferredType) =>
      genericExpression("boolLiteral", location, inferredType);

  BreakStatementTokens breakStatementTokens(
      Token breakKeyword, Token semicolon) {
    return new BreakStatementTokens(breakKeyword, semicolon);
  }

  void breakStatement(StatementJudgment judgment, int location,
      BreakStatementTokens tokens, void label, covariant Object labelBinder) {}

  void cascadeExpression(
      ExpressionJudgment judgment, int location, DartType inferredType) {
    // Overridden so that the type of the expression will not be recorded. We
    // don't need to record the type because the type is always the same as the
    // type of the target, and we don't have the appropriate offset so we can't
    // correctly apply the type even if we recorded it.
  }

  CatchStatementTokens catchStatementTokens(Token onKeyword, Token catchKeyword,
      Token leftParenthesis, Token comma, Token rightParenthesis) {
    return new CatchStatementTokens(
        onKeyword, catchKeyword, leftParenthesis, comma, rightParenthesis);
  }

  void catchStatement(
      Catch judgment,
      int location,
      CatchStatementTokens tokens,
      void type,
      void body,
      covariant VariableDeclarationBinder exceptionBinder,
      DartType exceptionType,
      covariant VariableDeclarationBinder stackTraceBinder,
      DartType stackTraceType) {
    if (exceptionBinder != null) {
      _store(exceptionBinder.fileOffset,
          inferredType: exceptionType,
          isSynthetic: exceptionBinder.isSynthetic);
    }

    if (stackTraceBinder != null) {
      _store(stackTraceBinder.fileOffset, inferredType: stackTraceType);
    }
  }

  ConditionalExpressionTokens conditionalExpressionTokens(
      Token question, Token colon) {
    return new ConditionalExpressionTokens(question, colon);
  }

  void conditionalExpression(
          ExpressionJudgment judgment,
          int location,
          void condition,
          ConditionalExpressionTokens tokens,
          void thenExpression,
          void elseExpression,
          DartType inferredType) =>
      genericExpression("conditionalExpression", location, inferredType);

  void constructorInvocation(ExpressionJudgment judgment, int location,
      Node expressionTarget, DartType inferredType) {
    // A class reference may have already been stored at this location by
    // storeClassReference.  We want to replace it with a constructor
    // reference.
    _unstore(location);
    _store(location, inferredType: inferredType, reference: expressionTarget);
  }

  ContinueStatementTokens continueStatementTokens(
      Token continueKeyword, Token semicolon) {
    return new ContinueStatementTokens(continueKeyword, semicolon);
  }

  void continueStatement(
      StatementJudgment judgment,
      int location,
      ContinueStatementTokens tokens,
      void label,
      covariant Object labelBinder) {}

  ContinueSwitchStatementTokens continueSwitchStatementTokens(
      Token continueKeyword, Token semicolon) {
    return new ContinueSwitchStatementTokens(continueKeyword, semicolon);
  }

  void continueSwitchStatement(
      StatementJudgment judgment,
      int location,
      ContinueSwitchStatementTokens tokens,
      void label,
      covariant Object labelBinder) {}

  void deferredCheck(
      ExpressionJudgment judgment, int location, DartType inferredType) {
    // This judgment has no semantic value for Analyzer.
  }

  DoStatementTokens doStatementTokens(Token doKeyword, Token whileKeyword,
      Token leftParenthesis, Token rightParenthesis, Token semicolon) {
    return new DoStatementTokens(
        doKeyword, whileKeyword, leftParenthesis, rightParenthesis, semicolon);
  }

  void doStatement(StatementJudgment judgment, int location,
      DoStatementTokens tokens, void body, void condition) {}

  DoubleLiteralTokens doubleLiteralTokens(Token literal) {
    return new DoubleLiteralTokens(literal);
  }

  void doubleLiteral(ExpressionJudgment judgment, int location,
          DoubleLiteralTokens tokens, double value, DartType inferredType) =>
      genericExpression("doubleLiteral", location, inferredType);

  EmptyStatementTokens emptyStatementTokens(Token semicolon) {
    return new EmptyStatementTokens(semicolon);
  }

  void emptyStatement(EmptyStatementTokens tokens) {}

  ExpressionStatementTokens expressionStatementTokens(Token semicolon) {
    return new ExpressionStatementTokens(semicolon);
  }

  void expressionStatement(StatementJudgment judgment, int location,
      void expression, ExpressionStatementTokens tokens) {}

  void fieldInitializer(
      InitializerJudgment judgment,
      int location,
      Token thisKeyword,
      Token period,
      Token fieldName,
      Token equals,
      void expression,
      Node initializerField) {
    _store(location, reference: initializerField);
  }

  ForInStatementTokens forInStatementTokens(
      Token awaitKeyword,
      Token forKeyword,
      Token leftParenthesis,
      Token inKeyword,
      Token rightParenthesis) {
    return new ForInStatementTokens(
        awaitKeyword, forKeyword, leftParenthesis, inKeyword, rightParenthesis);
  }

  void forInStatement(
      StatementJudgment judgment,
      int location,
      ForInStatementTokens tokens,
      Object loopVariable,
      void iterator,
      void body,
      covariant VariableDeclarationBinder loopVariableBinder,
      DartType loopVariableType,
      int writeLocation,
      DartType writeType,
      covariant VariableDeclarationBinder writeVariableBinder,
      Node writeTarget) {
    if (loopVariableBinder != null) {
      _store(loopVariableBinder.fileOffset, inferredType: loopVariableType);
    } else {
      if (writeVariableBinder != null) {
        _store(writeLocation,
            declaration: writeVariableBinder.fileOffset,
            inferredType: writeType);
      } else {
        _store(writeLocation,
            reference: writeTarget,
            isWriteReference: true,
            writeContext: writeType);
      }
    }
  }

  ForStatementTokens forStatementTokens(
    Token forKeyword,
    Token leftParenthesis,
    Token leftSeparator,
    Token rightSeparator,
    Token rightParenthesis,
  ) {
    return new ForStatementTokens(forKeyword, leftParenthesis, leftSeparator,
        rightSeparator, rightParenthesis);
  }

  void forStatement(
      StatementJudgment judgment,
      int location,
      ForStatementTokens tokens,
      void variableDeclarationList,
      void initialization,
      void condition,
      void updaters,
      void body) {}

  void functionDeclaration(
      covariant VariableDeclarationBinder binder, FunctionType inferredType) {
    _store(binder.fileOffset, inferredType: inferredType);
  }

  void functionExpression(
          ExpressionJudgment judgment, int location, DartType inferredType) =>
      genericExpression("functionExpression", location, inferredType);

  @override
  void functionType(int location, DartType type) {
    _store(location, inferredType: type);
  }

  @override
  void functionTypedFormalParameter(int location, DartType type) {
    _store(location, inferredType: type);
  }

  void genericExpression(
      String expressionType, int location, DartType inferredType) {
    _store(location, inferredType: inferredType);
  }

  IfNullTokens ifNullTokens(Token operator) {
    return new IfNullTokens(operator);
  }

  void ifNull(ExpressionJudgment judgment, int location, void leftOperand,
          IfNullTokens tokens, void rightOperand, DartType inferredType) =>
      genericExpression('ifNull', location, inferredType);

  IfStatementTokens ifStatementTokens(Token ifKeyword, Token leftParenthesis,
      Token rightParenthesis, Token elseKeyword) {
    return new IfStatementTokens(
        ifKeyword, leftParenthesis, rightParenthesis, elseKeyword);
  }

  void ifStatement(
      StatementJudgment judgment,
      int location,
      IfStatementTokens tokens,
      void condition,
      void thenStatement,
      void elseStatement) {}

  void indexAssign(
      ExpressionJudgment judgment,
      int location,
      DartType receiverType,
      Node writeMember,
      Node combiner,
      DartType inferredType) {
    _store(location,
        reference: writeMember,
        inferredType: inferredType,
        combiner: combiner,
        receiverType: receiverType);
  }

  IntLiteralTokens intLiteralTokens(Token literal) {
    return new IntLiteralTokens(literal);
  }

  void intLiteral(ExpressionJudgment judgment, int location,
          IntLiteralTokens tokens, num value, DartType inferredType) =>
      genericExpression("intLiteral", location, inferredType);

  @override
  void invalidAssignment(ExpressionJudgment judgment, int location) {
    _store(location, inferredType: const DynamicType());
  }

  void invalidInitializer(InitializerJudgment judgment, int location) {}

  IsExpressionTokens isExpressionTokens(Token isOperator) {
    return new IsExpressionTokens(isOperator);
  }

  void isExpression(ExpressionJudgment judgment, int location, void expression,
      IsExpressionTokens tokens, void literalType, DartType inferredType) {
    _store(location, inferredType: inferredType);
  }

  IsNotExpressionTokens isNotExpressionTokens(
      Token isOperator, Token notOperator) {
    return new IsNotExpressionTokens(isOperator, notOperator);
  }

  void isNotExpression(
      ExpressionJudgment judgment,
      int location,
      void expression,
      IsNotExpressionTokens tokens,
      void literalType,
      DartType inferredType) {
    _store(location, inferredType: inferredType);
  }

  void labeledStatement(List<Object> labels, void statement) {}

  ListLiteralTokens listLiteralTokens(
      Token constKeyword, Token leftBracket, Token rightBracket) {
    return new ListLiteralTokens(constKeyword, leftBracket, rightBracket);
  }

  void listLiteral(
          ExpressionJudgment judgment,
          int location,
          ListLiteralTokens tokens,
          Object typeArguments,
          void elements,
          DartType inferredType) =>
      genericExpression("listLiteral", location, inferredType);

  @override
  void loadLibrary(LoadLibraryJudgment judgment, int location, Node library,
      FunctionType calleeType, DartType inferredType) {
    _store(location,
        loadLibrary: library,
        invokeType: calleeType,
        inferredType: inferredType);
  }

  @override
  void loadLibraryTearOff(LoadLibraryTearOffJudgment judgment, int location,
      Node library, DartType inferredType) {
    _store(location, loadLibrary: library, inferredType: inferredType);
  }

  LogicalExpressionTokens logicalExpressionTokens(Token operatorToken) {
    return new LogicalExpressionTokens(operatorToken);
  }

  void logicalExpression(
          ExpressionJudgment judgment,
          int location,
          void leftOperand,
          LogicalExpressionTokens tokens,
          void rightOperand,
          DartType inferredType) =>
      genericExpression("logicalExpression", location, inferredType);

  MapLiteralTokens mapLiteralTokens(
      Token constKeyword, Token leftBracket, Token rightBracket) {
    return new MapLiteralTokens(constKeyword, leftBracket, rightBracket);
  }

  void mapLiteral(
          ExpressionJudgment judgment,
          int location,
          MapLiteralTokens tokens,
          Object typeArguments,
          List<Object> entries,
          DartType inferredType) =>
      genericExpression("mapLiteral", location, inferredType);

  void mapLiteralEntry(
      Object judgment, int fileOffset, void key, Token separator, void value) {
    // TODO(brianwilkerson) Implement this.
  }

  void methodInvocation(
      ExpressionJudgment judgment,
      int resultOffset,
      DartType receiverType,
      List<DartType> argumentsTypes,
      bool isImplicitCall,
      Node interfaceMember,
      FunctionType calleeType,
      Substitution substitution,
      DartType inferredType) {
    FunctionType invokeType = substitution == null
        ? calleeType
        : substitution.substituteType(calleeType.withoutTypeParameters);

    _store(resultOffset,
        inferredType: inferredType,
        argumentTypes: argumentsTypes,
        invokeType: invokeType,
        isImplicitCall: isImplicitCall,
        receiverType: receiverType,
        reference: interfaceMember);
  }

  void methodInvocationCall(
      ExpressionJudgment judgment,
      int resultOffset,
      List<DartType> argumentsTypes,
      bool isImplicitCall,
      FunctionType calleeType,
      Substitution substitution,
      DartType inferredType) {
    FunctionType invokeType = substitution == null
        ? calleeType
        : substitution.substituteType(calleeType.withoutTypeParameters);

    _store(resultOffset,
        inferredType: inferredType,
        argumentTypes: argumentsTypes,
        invokeType: invokeType,
        isImplicitCall: isImplicitCall);
  }

  void namedFunctionExpression(ExpressionJudgment judgment,
          covariant VariableDeclarationBinder binder, DartType inferredType) =>
      genericExpression(
          "namedFunctionExpression", binder.fileOffset, inferredType);

  NotTokens notTokens(Token operator) {
    return new NotTokens(operator);
  }

  void not(ExpressionJudgment judgment, int location, NotTokens tokens,
          void operand, DartType inferredType) =>
      genericExpression("not", location, inferredType);

  NullLiteralTokens nullLiteralTokens(Token literal) {
    return new NullLiteralTokens(literal);
  }

  void nullLiteral(ExpressionJudgment judgment, int location,
      NullLiteralTokens tokens, bool isSynthetic, DartType inferredType) {
    if (isSynthetic) return null;
    genericExpression("nullLiteral", location, inferredType);
  }

  void propertyAssign(
      ExpressionJudgment judgment,
      int location,
      bool isSyntheticLhs,
      DartType receiverType,
      Node writeMember,
      DartType writeContext,
      Node combiner,
      DartType inferredType) {
    _store(location,
        isSynthetic: isSyntheticLhs,
        isWriteReference: true,
        reference: writeMember,
        writeContext: writeContext,
        combiner: combiner,
        inferredType: inferredType,
        receiverType: receiverType);
  }

  void propertyGet(
      ExpressionJudgment judgment,
      int location,
      bool forSyntheticToken,
      DartType receiverType,
      Node member,
      DartType inferredType) {
    _store(location,
        reference: member,
        inferredType: inferredType,
        isSynthetic: forSyntheticToken,
        receiverType: receiverType);
  }

  void propertyGetCall(
      ExpressionJudgment judgment, int location, DartType inferredType) {
    _store(location, isExplicitCall: true);
  }

  void redirectingInitializer(
      InitializerJudgment judgment,
      int location,
      Token thisKeyword,
      Token period,
      Token constructorName,
      covariant Object argumentList,
      Node initializerTarget) {
    _store(location, reference: initializerTarget);
  }

  RethrowTokens rethrowTokens(Token rethrowKeyword) {
    return new RethrowTokens(rethrowKeyword);
  }

  void rethrow_(ExpressionJudgment judgment, int location, RethrowTokens tokens,
          DartType inferredType) =>
      genericExpression('rethrow', location, inferredType);

  ReturnStatementTokens returnStatementTokens(
      Token returnKeyword, Token semicolon) {
    return new ReturnStatementTokens(returnKeyword, semicolon);
  }

  void returnStatement(StatementJudgment judgment, int location,
      ReturnStatementTokenstokens, void expression) {}

  void statementLabel(covariant void binder, Token label, Token colon) {}

  void staticAssign(ExpressionJudgment judgment, int location, Node writeMember,
      DartType writeContext, Node combiner, DartType inferredType) {
    _store(location,
        reference: writeMember,
        isWriteReference: true,
        writeContext: writeContext,
        combiner: combiner,
        inferredType: inferredType);
  }

  void staticGet(ExpressionJudgment judgment, int location,
      Node expressionTarget, DartType inferredType) {
    _store(location, reference: expressionTarget, inferredType: inferredType);
  }

  void staticInvocation(
      ExpressionJudgment judgment,
      int location,
      Node expressionTarget,
      List<DartType> expressionArgumentsTypes,
      FunctionType calleeType,
      Substitution substitution,
      DartType inferredType) {
    FunctionType invokeType = substitution == null
        ? calleeType
        : substitution.substituteType(calleeType.withoutTypeParameters);
    _store(location,
        invokeType: invokeType ?? const DynamicType(),
        argumentTypes: expressionArgumentsTypes,
        reference: expressionTarget,
        inferredType: inferredType);
  }

  void storeClassReference(int location, Node reference, DartType rawType) {
    // TODO(paulberry): would it be better to use literalType?
    _store(location, reference: reference, inferredType: rawType);
  }

  void storePrefixInfo(int location, int prefixInfo) {
    _store(location, isPrefixReference: true, prefixInfo: prefixInfo);
  }

  @override
  void storeUnresolved(int location) {
    _unstore(location);
    _store(location, inferredType: const DynamicType());
  }

  void stringConcatenation(
      ExpressionJudgment judgment, int location, DartType inferredType) {
    // We don't need the type - we already know that it is String.
    // Moreover, the file offset for StringConcatenation is `-1`.
  }

  StringLiteralTokens stringLiteralTokens(Token literal) {
    return new StringLiteralTokens(literal);
  }

  void stringLiteral(ExpressionJudgment judgment, int location,
          StringLiteralTokens tokens, String value, DartType inferredType) =>
      genericExpression("StringLiteral", location, inferredType);

  SuperInitializerTokens superInitializerTokens(
      Token superKeyword, Token period, Token constructorName) {
    return new SuperInitializerTokens(superKeyword, period, constructorName);
  }

  void superInitializer(InitializerJudgment judgment, int location,
      SuperInitializerTokens tokens, covariant Object argumentList) {}

  SwitchCaseTokens switchCaseTokens(Token keyword, Token colon) {
    return new SwitchCaseTokens(keyword, colon);
  }

  void switchCase(SwitchCaseJudgment judgment, List<Object> labels,
      Token keyword, void expression, Token colon, List<void> statements) {}

  void switchLabel(covariant void binder, Token label, Token colon) {}

  SwitchStatementTokens switchStatementTokens(
      Token switchKeyword,
      Token leftParenthesis,
      Token rightParenthesis,
      Token leftBracket,
      Token rightBracket) {
    return new SwitchStatementTokens(switchKeyword, leftParenthesis,
        rightParenthesis, leftBracket, rightBracket);
  }

  void switchStatement(StatementJudgment judgment, int location,
      SwitchStatementTokens tokens, void expression, void members) {}

  void symbolLiteral(ExpressionJudgment judgment, int location, Token poundSign,
          List<Token> components, String value, DartType inferredType) =>
      genericExpression("symbolLiteral", location, inferredType);

  ThisExpressionTokens thisExpressionTokens(Token thisKeyword) {
    return new ThisExpressionTokens(thisKeyword);
  }

  void thisExpression(ExpressionJudgment judgment, int location,
      ThisExpressionTokens token, DartType inferredType) {}

  ThrowTokens throwTokens(Token throwKeyword) {
    return new ThrowTokens(throwKeyword);
  }

  void throw_(ExpressionJudgment judgment, int location, ThrowTokens tokens,
          void expression, DartType inferredType) =>
      genericExpression('throw', location, inferredType);

  void tryCatch(StatementJudgment judgment, int location) {}

  TryFinallyTokens tryFinallyTokens(Token tryKeyword, Token finallyKeyword) {
    return new TryFinallyTokens(tryKeyword, finallyKeyword);
  }

  void tryFinally(
      StatementJudgment judgment,
      int location,
      TryFinallyTokens tokens,
      void body,
      void catchClauses,
      void finallyBlock) {}

  void typeLiteral(ExpressionJudgment judgment, int location,
      Node expressionType, DartType inferredType) {
    _store(location, reference: expressionType, inferredType: inferredType);
  }

  void typeReference(
      int location,
      bool forSyntheticToken,
      Token leftBracket,
      List<void> typeArguments,
      Token rightBracket,
      Node reference,
      covariant TypeVariableBinder binder,
      DartType type) {
    _store(location,
        isSynthetic: forSyntheticToken,
        reference: reference,
        declaration: binder?.fileOffset,
        inferredType: type,
        isTypeReference: true);
  }

  void typeVariableDeclaration(int location,
      covariant TypeVariableBinder binder, TypeParameter typeParameter) {
    _storeTypeVariableDeclaration(binder.fileOffset, typeParameter);
    _store(location, declaration: binder.fileOffset);
  }

  void variableAssign(
      ExpressionJudgment judgment,
      int location,
      bool isSyntheticLhs,
      DartType writeContext,
      covariant VariableDeclarationBinder writeVariableBinder,
      Node combiner,
      DartType inferredType) {
    _store(location,
        isSynthetic: isSyntheticLhs,
        declaration: writeVariableBinder?.fileOffset,
        isWriteReference: true,
        writeContext: writeContext,
        combiner: combiner,
        inferredType: inferredType);
  }

  void variableDeclaration(
      covariant VariableDeclarationBinder binder, DartType inferredType) {
    _store(binder.fileOffset,
        inferredType: inferredType, isSynthetic: binder.isSynthetic);
  }

  void variableGet(
      ExpressionJudgment judgment,
      int location,
      bool forSyntheticToken,
      bool isInCascade,
      covariant VariableDeclarationBinder variableBinder,
      DartType inferredType) {
    if (isInCascade) {
      return;
    }
    _store(location,
        isSynthetic: forSyntheticToken,
        declaration: variableBinder?.fileOffset,
        inferredType: inferredType);
  }

  void voidType(int location, Token token, DartType type) {
    _store(location, inferredType: type);
  }

  WhileStatementTokens whileStatementTokens(
      Token whileKeyword, Token leftParenthesis, Token rightParenthesis) {
    return new WhileStatementTokens(
        whileKeyword, leftParenthesis, rightParenthesis);
  }

  void whileStatement(StatementJudgment judgment, int location,
      WhileStatementTokens tokens, void condition, void body) {}

  YieldStatementTokens yieldStatementTokens(
      Token yieldKeyword, Token star, Token semicolon) {
    return new YieldStatementTokens(yieldKeyword, star, semicolon);
  }

  void yieldStatement(StatementJudgment judgment, int location,
      YieldStatementTokens tokens, void expression) {}

  void _store(int location,
      {List<DartType> argumentTypes,
      Node combiner,
      int declaration,
      DartType inferredType,
      DartType invokeType,
      bool isExplicitCall = false,
      bool isImplicitCall = false,
      bool isPrefixReference = false,
      bool isSynthetic = false,
      bool isTypeReference = false,
      bool isWriteReference = false,
      Node loadLibrary,
      int prefixInfo,
      DartType receiverType,
      Node reference,
      bool replace = false,
      DartType writeContext}) {
    _validateLocation(location);
    var encodedLocation = 2 * location + (isSynthetic ? 1 : 0);
    if (!replace) {
      var existing = _data[encodedLocation];
      if (existing != null) {
        if (existing.isOutline) {
          return;
        }
        throw new StateError('Data already stored for (offset=$location, '
            'isSynthetic=$isSynthetic)');
      }
    }
    _data[encodedLocation] = new ResolutionData(
        argumentTypes: argumentTypes,
        combiner: combiner,
        declaration: declaration,
        inferredType: inferredType,
        invokeType: invokeType,
        isExplicitCall: isExplicitCall,
        isImplicitCall: isImplicitCall,
        isPrefixReference: isPrefixReference,
        isTypeReference: isTypeReference,
        isWriteReference: isWriteReference,
        loadLibrary: loadLibrary,
        prefixInfo: prefixInfo,
        receiverType: receiverType,
        reference: reference,
        writeContext: writeContext);
  }

  void _storeTypeVariableDeclaration(
      int fileOffset, TypeParameter typeParameter) {
    if (_typeVariableDeclarations.containsKey(fileOffset)) {
      throw new StateError(
          'Type declaration already stored for offset $fileOffset');
    }
    _typeVariableDeclarations[typeParameter] = fileOffset;
  }

  void _unstore(int location, {bool isSynthetic: false}) {
    var encodedLocation = 2 * location + (isSynthetic ? 1 : 0);
    _data.remove(encodedLocation) == null;
  }

  void _validateLocation(int location) {
    if (location < 0) {
      throw new StateError('Invalid location: $location');
    }
  }

  NamedExpressionTokens namedExpressionTokens(Token nameToken, Token colon) {
    return new NamedExpressionTokens(nameToken, colon);
  }
}

/// A [DartType] wrapper around invocation type arguments.
class TypeArgumentsDartType implements DartType {
  final List<DartType> types;

  TypeArgumentsDartType(this.types);

  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);

  @override
  String toString() {
    return '<${types.join(', ')}>';
  }
}

/// TODO(paulberry): eventually just use the element directly.
class TypeVariableBinder {
  final int fileOffset;

  TypeVariableBinder(this.fileOffset);
}

/// TODO(paulberry): eventually just use the element directly.
class VariableDeclarationBinder {
  final int fileOffset;
  final bool isSynthetic;

  VariableDeclarationBinder(this.fileOffset, this.isSynthetic);
}
