blob: dfcdfe2c0f7eef548b28f9eb96788fef6e17d1a0 [file] [log] [blame]
// 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() {
for (auto& p : GlobalContext::AllDeclarables()) {
if (const TypeAlias* alias = TypeAlias::DynamicCast(p.get())) {
CurrentScope::Scope scope_activator(alias->ParentScope());
CurrentSourcePosition::Scope position_activator(alias->Position());
alias->Resolve();
}
}
}
} // namespace torque
} // namespace internal
} // namespace v8