// 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/factory.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<Type, Declaration, Reference, PrefixInfo> {
  final List<Type> argumentTypes;
  final Reference combiner;
  final Declaration declaration;
  final Type inferredType;
  final Type invokeType;
  final bool isExplicitCall;
  final bool isImplicitCall;
  final bool isTypeReference;
  final bool isWriteReference;
  final Type literalType;
  final Reference loadLibrary;
  final PrefixInfo prefixInfo;
  final Reference reference;
  final Type writeContext;

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

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

  final Map<TypeParameter, int> _typeVariableDeclarations;

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

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

  void assertInitializer(
      InitializerJudgment judgment,
      int location,
      Token assertKeyword,
      Token leftParenthesis,
      void condition,
      Token comma,
      void message,
      Token rightParenthesis) {}

  void assertStatement(
      StatementJudgment judgment,
      int location,
      Token assertKeyword,
      Token leftParenthesis,
      void condition,
      Token comma,
      void message,
      Token rightParenthesis,
      Token semicolon) {}

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

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

  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) {
    return new VariableDeclarationBinder(fileOffset);
  }

  void block(StatementJudgment judgment, int location, Token leftBracket,
      List<void> statements, Token rightBracket) {}

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

  void breakStatement(
      StatementJudgment judgment,
      int location,
      Token breakKeyword,
      void label,
      Token semicolon,
      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.
  }

  void catchStatement(
      Catch judgment,
      int location,
      Token onKeyword,
      void type,
      Token catchKeyword,
      Token leftParenthesis,
      Token exceptionParameter,
      Token comma,
      Token stackTraceParameter,
      Token rightParenthesis,
      void body,
      DartType guardType,
      covariant VariableDeclarationBinder exceptionBinder,
      DartType exceptionType,
      covariant VariableDeclarationBinder stackTraceBinder,
      DartType stackTraceType) {
    _store(location, literalType: guardType);

    if (exceptionBinder != null) {
      _store(exceptionBinder.fileOffset, literalType: exceptionType);
    }

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

  void conditionalExpression(
          ExpressionJudgment judgment,
          int location,
          void condition,
          Token question,
          void thenExpression,
          Token colon,
          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);
  }

  void continueStatement(
      StatementJudgment judgment,
      int location,
      Token continueKeyword,
      void label,
      Token semicolon,
      covariant Object labelBinder) {}

  void continueSwitchStatement(
      StatementJudgment judgment,
      int location,
      Token continueKeyword,
      void label,
      Token semicolon,
      covariant Object labelBinder) {}

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

  void doStatement(
      StatementJudgment judgment,
      int location,
      Token doKeyword,
      void body,
      Token whileKeyword,
      Token leftParenthesis,
      void condition,
      Token rightParenthesis,
      Token semicolon) {}

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

  void emptyStatement(Token semicolon) {}

  void expressionStatement(StatementJudgment judgment, int location,
      void expression, Token semicolon) {}

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

  void forInStatement(
      StatementJudgment judgment,
      int location,
      Token awaitKeyword,
      Token forKeyword,
      Token leftParenthesis,
      Object loopVariable,
      Token identifier,
      Token inKeyword,
      void iterator,
      Token rightParenthesis,
      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);
      }
    }
  }

  void forStatement(
      StatementJudgment judgment,
      int location,
      Token forKeyword,
      Token leftParenthesis,
      void variableDeclarationList,
      void initialization,
      Token leftSeparator,
      void condition,
      Token rightSeparator,
      void updaters,
      Token rightParenthesis,
      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 functionTypedFormalParameter(int location, DartType type) {
    _store(location, inferredType: type);
  }

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

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

  void ifStatement(
      StatementJudgment judgment,
      int location,
      Token ifKeyword,
      Token leftParenthesis,
      void condition,
      Token rightParenthesis,
      void thenStatement,
      Token elseKeyword,
      void elseStatement) {}

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

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

  void invalidInitializer(InitializerJudgment judgment, int location) {}

  void isExpression(
      ExpressionJudgment judgment,
      int location,
      void expression,
      Token isOperator,
      void literalType,
      DartType testedType,
      DartType inferredType) {
    _store(location, literalType: testedType, inferredType: inferredType);
  }

  void isNotExpression(
      ExpressionJudgment judgment,
      int location,
      void expression,
      Token isOperator,
      Token notOperator,
      void literalType,
      DartType type,
      DartType inferredType) {
    _store(location, literalType: type, inferredType: inferredType);
  }

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

  void listLiteral(
          ExpressionJudgment judgment,
          int location,
          Token constKeyword,
          Object typeArguments,
          Token leftBracket,
          void elements,
          Token rightBracket,
          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);
  }

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

  void mapLiteral(
          ExpressionJudgment judgment,
          int location,
          Token constKeyword,
          Object typeArguments,
          Token leftBracket,
          List<Object> entries,
          Token rightBracket,
          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,
      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,
        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);

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

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

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

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

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

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

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

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

  void returnStatement(StatementJudgment judgment, int location,
      Token returnKeyword, void expression, Token semicolon) {}

  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, prefixInfo: prefixInfo);
  }

  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`.
  }

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

  void superInitializer(
      InitializerJudgment judgment,
      int location,
      Token superKeyword,
      Token period,
      Token constructorName,
      covariant Object argumentList) {}

  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) {}

  void switchStatement(
      StatementJudgment judgment,
      int location,
      Token switchKeyword,
      Token leftParenthesis,
      void expression,
      Token rightParenthesis,
      Token leftBracket,
      void members,
      Token rightBracket) {}

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

  void thisExpression(ExpressionJudgment judgment, int location,
      Token thisKeyword, DartType inferredType) {}

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

  void tryCatch(StatementJudgment judgment, int location) {}

  void tryFinally(StatementJudgment judgment, int location, Token tryKeyword,
      void body, void catchClauses, Token finallyKeyword, void finallyBlock) {}

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

  void typeReference(
      int location,
      Token leftBracket,
      List<void> typeArguments,
      Token rightBracket,
      Node reference,
      covariant TypeVariableBinder binder,
      DartType type) {
    _store(location,
        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,
      DartType writeContext,
      covariant VariableDeclarationBinder writeVariableBinder,
      Node combiner,
      DartType inferredType) {
    _store(location,
        declaration: writeVariableBinder?.fileOffset,
        isWriteReference: true,
        writeContext: writeContext,
        combiner: combiner,
        inferredType: inferredType);
  }

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

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

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

  void whileStatement(
      StatementJudgment judgment,
      int location,
      Token whileKeyword,
      Token leftParenthesis,
      void condition,
      Token rightParenthesis,
      void body) {}

  void yieldStatement(StatementJudgment judgment, int location,
      Token yieldKeyword, Token star, void expression, Token semicolon) {}

  void _store(int location,
      {List<DartType> argumentTypes,
      Node combiner,
      int declaration,
      DartType inferredType,
      DartType invokeType,
      bool isExplicitCall = false,
      bool isImplicitCall = false,
      bool isTypeReference = false,
      bool isWriteReference = false,
      DartType literalType,
      Node loadLibrary,
      int prefixInfo,
      Node reference,
      bool replace = false,
      DartType writeContext}) {
    _validateLocation(location);
    if (!replace && _data.containsKey(location)) {
      throw new StateError('Data already stored for offset $location');
    }
    _data[location] = new ResolutionData(
        argumentTypes: argumentTypes,
        combiner: combiner,
        declaration: declaration,
        inferredType: inferredType,
        invokeType: invokeType,
        isExplicitCall: isExplicitCall,
        isImplicitCall: isImplicitCall,
        isTypeReference: isTypeReference,
        isWriteReference: isWriteReference,
        literalType: literalType,
        loadLibrary: loadLibrary,
        prefixInfo: prefixInfo,
        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) {
    _data.remove(location) == null;
  }

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

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

  VariableDeclarationBinder(this.fileOffset);
}
