// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/torque/declaration-visitor.h"

#include "src/torque/ast.h"
#include "src/torque/server-data.h"
#include "src/torque/type-inference.h"
#include "src/torque/type-visitor.h"

namespace v8 {
namespace internal {
namespace torque {

Namespace* GetOrCreateNamespace(const std::string& name) {
  std::vector<Namespace*> existing_namespaces = FilterDeclarables<Namespace>(
      Declarations::TryLookupShallow(QualifiedName(name)));
  if (existing_namespaces.empty()) {
    return Declarations::DeclareNamespace(name);
  }
  DCHECK_EQ(1, existing_namespaces.size());
  return existing_namespaces.front();
}

void PredeclarationVisitor::Predeclare(Declaration* decl) {
  CurrentSourcePosition::Scope scope(decl->pos);
  switch (decl->kind) {
#define ENUM_ITEM(name)        \
  case AstNode::Kind::k##name: \
    return Predeclare(name::cast(decl));
    AST_TYPE_DECLARATION_NODE_KIND_LIST(ENUM_ITEM)
#undef ENUM_ITEM
    case AstNode::Kind::kNamespaceDeclaration:
      return Predeclare(NamespaceDeclaration::cast(decl));
    case AstNode::Kind::kGenericCallableDeclaration:
      return Predeclare(GenericCallableDeclaration::cast(decl));
    case AstNode::Kind::kGenericTypeDeclaration:
      return Predeclare(GenericTypeDeclaration::cast(decl));

    default:
      // Only processes type declaration nodes, namespaces and generics.
      break;
  }
}

void DeclarationVisitor::Visit(Declaration* decl) {
  CurrentSourcePosition::Scope scope(decl->pos);
  switch (decl->kind) {
#define ENUM_ITEM(name)        \
  case AstNode::Kind::k##name: \
    return Visit(name::cast(decl));
    AST_DECLARATION_NODE_KIND_LIST(ENUM_ITEM)
#undef ENUM_ITEM
    default:
      UNIMPLEMENTED();
  }
}

Builtin* DeclarationVisitor::CreateBuiltin(BuiltinDeclaration* decl,
                                           std::string external_name,
                                           std::string readable_name,
                                           Signature signature,
                                           base::Optional<Statement*> body) {
  const bool javascript = decl->javascript_linkage;
  const bool varargs = decl->parameters.has_varargs;
  Builtin::Kind kind = !javascript ? Builtin::kStub
                                   : varargs ? Builtin::kVarArgsJavaScript
                                             : Builtin::kFixedArgsJavaScript;

  if (varargs && !javascript) {
    Error("Rest parameters require ", decl->name,
          " to be a JavaScript builtin");
  }

  if (javascript) {
    if (!signature.return_type->IsSubtypeOf(TypeOracle::GetJSAnyType())) {
      Error("Return type of JavaScript-linkage builtins has to be JSAny.")
          .Position(decl->return_type->pos);
    }
    for (size_t i = signature.implicit_count;
         i < signature.parameter_types.types.size(); ++i) {
      const Type* parameter_type = signature.parameter_types.types[i];
      if (!TypeOracle::GetJSAnyType()->IsSubtypeOf(parameter_type)) {
        Error(
            "Parameters of JavaScript-linkage builtins have to be a supertype "
            "of JSAny.")
            .Position(decl->parameters.types[i]->pos);
      }
    }
  }

  for (size_t i = 0; i < signature.types().size(); ++i) {
    if (signature.types()[i]->StructSupertype()) {
      Error("Builtin do not support structs as arguments, but argument ",
            signature.parameter_names[i], " has type ", *signature.types()[i],
            ".");
    }
  }

  if (signature.return_type->StructSupertype()) {
    Error("Builtins cannot return structs, but the return type is ",
          *signature.return_type, ".");
  }

  if (signature.return_type == TypeOracle::GetVoidType()) {
    Error("Builtins cannot have return type void.");
  }

  return Declarations::CreateBuiltin(std::move(external_name),
                                     std::move(readable_name), kind,
                                     std::move(signature), body);
}

void DeclarationVisitor::Visit(ExternalBuiltinDeclaration* decl) {
  Declarations::Declare(
      decl->name->value,
      CreateBuiltin(decl, decl->name->value, decl->name->value,
                    TypeVisitor::MakeSignature(decl), base::nullopt));
}

void DeclarationVisitor::Visit(ExternalRuntimeDeclaration* decl) {
  Signature signature = TypeVisitor::MakeSignature(decl);
  if (signature.parameter_types.types.size() == 0) {
    ReportError(
        "Missing parameters for runtime function, at least the context "
        "parameter is required.");
  }
  if (!(signature.parameter_types.types[0] == TypeOracle::GetContextType() ||
        signature.parameter_types.types[0] == TypeOracle::GetNoContextType())) {
    ReportError(
        "first parameter to runtime functions has to be the context and have "
        "type Context or NoContext, but found type ",
        *signature.parameter_types.types[0]);
  }
  if (!(signature.return_type->IsSubtypeOf(TypeOracle::GetStrongTaggedType()) ||
        signature.return_type == TypeOracle::GetVoidType() ||
        signature.return_type == TypeOracle::GetNeverType())) {
    ReportError(
        "runtime functions can only return strong tagged values, but "
        "found type ",
        signature.return_type);
  }
  for (const Type* parameter_type : signature.parameter_types.types) {
    if (!parameter_type->IsSubtypeOf(TypeOracle::GetStrongTaggedType())) {
      ReportError(
          "runtime functions can only take strong tagged parameters, but "
          "found type ",
          *parameter_type);
    }
  }

  Declarations::DeclareRuntimeFunction(decl->name->value, signature);
}

void DeclarationVisitor::Visit(ExternalMacroDeclaration* decl) {
  Declarations::DeclareMacro(
      decl->name->value, true, decl->external_assembler_name,
      TypeVisitor::MakeSignature(decl), base::nullopt, decl->op);
}

void DeclarationVisitor::Visit(TorqueBuiltinDeclaration* decl) {
  Declarations::Declare(
      decl->name->value,
      CreateBuiltin(decl, decl->name->value, decl->name->value,
                    TypeVisitor::MakeSignature(decl), decl->body));
}

void DeclarationVisitor::Visit(TorqueMacroDeclaration* decl) {
  Macro* macro = Declarations::DeclareMacro(
      decl->name->value, decl->export_to_csa, base::nullopt,
      TypeVisitor::MakeSignature(decl), decl->body, decl->op);
  // TODO(szuend): Set identifier_position to decl->name->pos once all callable
  // names are changed from std::string to Identifier*.
  macro->SetPosition(decl->pos);
}

void DeclarationVisitor::Visit(IntrinsicDeclaration* decl) {
  Declarations::DeclareIntrinsic(decl->name->value,
                                 TypeVisitor::MakeSignature(decl));
}

void DeclarationVisitor::Visit(ConstDeclaration* decl) {
  Declarations::DeclareNamespaceConstant(
      decl->name, TypeVisitor::ComputeType(decl->type), decl->expression);
}

void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
  std::vector<GenericCallable*> generic_list =
      Declarations::LookupGeneric(decl->name->value);
  // Find the matching generic specialization based on the concrete parameter
  // list.
  GenericCallable* matching_generic = nullptr;
  Signature signature_with_types = TypeVisitor::MakeSignature(decl);
  for (GenericCallable* generic : generic_list) {
    // This argument inference is just to trigger constraint checking on the
    // generic arguments.
    TypeArgumentInference inference = generic->InferSpecializationTypes(
        TypeVisitor::ComputeTypeVector(decl->generic_parameters), {});
    if (inference.HasFailed()) {
      continue;
    }
    Signature generic_signature_with_types =
        MakeSpecializedSignature(SpecializationKey<GenericCallable>{
            generic, TypeVisitor::ComputeTypeVector(decl->generic_parameters)});
    if (signature_with_types.HasSameTypesAs(generic_signature_with_types,
                                            ParameterMode::kIgnoreImplicit)) {
      if (matching_generic != nullptr) {
        std::stringstream stream;
        stream << "specialization of " << decl->name
               << " is ambigous, it matches more than one generic declaration ("
               << *matching_generic << " and " << *generic << ")";
        ReportError(stream.str());
      }
      matching_generic = generic;
    }
  }

  if (matching_generic == nullptr) {
    std::stringstream stream;
    if (generic_list.size() == 0) {
      stream << "no generic defined with the name " << decl->name;
      ReportError(stream.str());
    }
    stream << "specialization of " << decl->name
           << " doesn't match any generic declaration\n";
    stream << "specialization signature:";
    stream << "\n  " << signature_with_types;
    stream << "\ncandidates are:";
    for (GenericCallable* generic : generic_list) {
      stream << "\n  "
             << MakeSpecializedSignature(SpecializationKey<GenericCallable>{
                    generic,
                    TypeVisitor::ComputeTypeVector(decl->generic_parameters)});
    }
    ReportError(stream.str());
  }

  if (GlobalContext::collect_language_server_data()) {
    LanguageServerData::AddDefinition(decl->name->pos,
                                      matching_generic->IdentifierPosition());
  }

  CallableDeclaration* generic_declaration = matching_generic->declaration();

  Specialize(SpecializationKey<GenericCallable>{matching_generic,
                                                TypeVisitor::ComputeTypeVector(
                                                    decl->generic_parameters)},
             generic_declaration, decl, decl->body, decl->pos);
}

void DeclarationVisitor::Visit(ExternConstDeclaration* decl) {
  const Type* type = TypeVisitor::ComputeType(decl->type);
  if (!type->IsConstexpr()) {
    std::stringstream stream;
    stream << "extern constants must have constexpr type, but found: \""
           << *type << "\"\n";
    ReportError(stream.str());
  }

  Declarations::DeclareExternConstant(decl->name, type, decl->literal);
}

void DeclarationVisitor::Visit(CppIncludeDeclaration* decl) {
  GlobalContext::AddCppInclude(decl->include_path);
}

void DeclarationVisitor::DeclareSpecializedTypes(
    const SpecializationKey<GenericCallable>& key) {
  size_t i = 0;
  const std::size_t generic_parameter_count =
      key.generic->generic_parameters().size();
  if (generic_parameter_count != key.specialized_types.size()) {
    std::stringstream stream;
    stream << "Wrong generic argument count for specialization of \""
           << key.generic->name() << "\", expected: " << generic_parameter_count
           << ", actual: " << key.specialized_types.size();
    ReportError(stream.str());
  }

  for (auto type : key.specialized_types) {
    Identifier* generic_type_name = key.generic->generic_parameters()[i++].name;
    TypeAlias* alias = Declarations::DeclareType(generic_type_name, type);
    alias->SetIsUserDefined(false);
  }
}

Signature DeclarationVisitor::MakeSpecializedSignature(
    const SpecializationKey<GenericCallable>& key) {
  CurrentScope::Scope generic_scope(key.generic->ParentScope());
  // Create a temporary fake-namespace just to temporarily declare the
  // specialization aliases for the generic types to create a signature.
  Namespace tmp_namespace("_tmp");
  CurrentScope::Scope tmp_namespace_scope(&tmp_namespace);
  DeclareSpecializedTypes(key);
  return TypeVisitor::MakeSignature(key.generic->declaration());
}

Callable* DeclarationVisitor::SpecializeImplicit(
    const SpecializationKey<GenericCallable>& key) {
  base::Optional<Statement*> body = key.generic->CallableBody();
  if (!body && IntrinsicDeclaration::DynamicCast(key.generic->declaration()) ==
                   nullptr) {
    ReportError("missing specialization of ", key.generic->name(),
                " with types <", key.specialized_types, "> declared at ",
                key.generic->Position());
  }
  SpecializationRequester requester{CurrentSourcePosition::Get(),
                                    CurrentScope::Get(), ""};
  CurrentScope::Scope generic_scope(key.generic->ParentScope());
  Callable* result = Specialize(key, key.generic->declaration(), base::nullopt,
                                body, CurrentSourcePosition::Get());
  result->SetIsUserDefined(false);
  requester.name = result->ReadableName();
  result->SetSpecializationRequester(requester);
  CurrentScope::Scope callable_scope(result);
  DeclareSpecializedTypes(key);
  return result;
}

Callable* DeclarationVisitor::Specialize(
    const SpecializationKey<GenericCallable>& key,
    CallableDeclaration* declaration,
    base::Optional<const SpecializationDeclaration*> explicit_specialization,
    base::Optional<Statement*> body, SourcePosition position) {
  CurrentSourcePosition::Scope pos_scope(position);
  size_t generic_parameter_count = key.generic->generic_parameters().size();
  if (generic_parameter_count != key.specialized_types.size()) {
    std::stringstream stream;
    stream << "number of template parameters ("
           << std::to_string(key.specialized_types.size())
           << ") to intantiation of generic " << declaration->name
           << " doesnt match the generic's declaration ("
           << std::to_string(generic_parameter_count) << ")";
    ReportError(stream.str());
  }
  if (key.generic->GetSpecialization(key.specialized_types)) {
    ReportError("cannot redeclare specialization of ", key.generic->name(),
                " with types <", key.specialized_types, ">");
  }

  Signature type_signature =
      explicit_specialization
          ? TypeVisitor::MakeSignature(*explicit_specialization)
          : MakeSpecializedSignature(key);

  std::string generated_name = Declarations::GetGeneratedCallableName(
      declaration->name->value, key.specialized_types);
  std::stringstream readable_name;
  readable_name << declaration->name->value << "<";
  bool first = true;
  for (const Type* t : key.specialized_types) {
    if (!first) readable_name << ", ";
    readable_name << *t;
    first = false;
  }
  readable_name << ">";
  Callable* callable;
  if (MacroDeclaration::DynamicCast(declaration) != nullptr) {
    callable =
        Declarations::CreateTorqueMacro(generated_name, readable_name.str(),
                                        false, type_signature, *body, true);
  } else if (IntrinsicDeclaration::DynamicCast(declaration) != nullptr) {
    callable =
        Declarations::CreateIntrinsic(declaration->name->value, type_signature);
  } else {
    BuiltinDeclaration* builtin = BuiltinDeclaration::cast(declaration);
    callable =
        CreateBuiltin(builtin, GlobalContext::MakeUniqueName(generated_name),
                      readable_name.str(), type_signature, *body);
  }
  key.generic->AddSpecialization(key.specialized_types, callable);
  return callable;
}

void PredeclarationVisitor::ResolvePredeclarations() {
  const auto& all_declarables = GlobalContext::AllDeclarables();
  for (size_t i = 0; i < all_declarables.size(); ++i) {
    Declarable* declarable = all_declarables[i].get();
    if (const TypeAlias* alias = TypeAlias::DynamicCast(declarable)) {
      CurrentScope::Scope scope_activator(alias->ParentScope());
      CurrentSourcePosition::Scope position_activator(alias->Position());
      alias->Resolve();
    }
  }
}

}  // namespace torque
}  // namespace internal
}  // namespace v8
