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