// 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"
|
|
namespace v8 {
|
namespace internal {
|
namespace torque {
|
|
void DeclarationVisitor::Visit(Expression* expr) {
|
CurrentSourcePosition::Scope scope(expr->pos);
|
switch (expr->kind) {
|
#define ENUM_ITEM(name) \
|
case AstNode::Kind::k##name: \
|
return Visit(name::cast(expr));
|
AST_EXPRESSION_NODE_KIND_LIST(ENUM_ITEM)
|
#undef ENUM_ITEM
|
default:
|
UNIMPLEMENTED();
|
}
|
}
|
|
void DeclarationVisitor::Visit(Statement* stmt) {
|
CurrentSourcePosition::Scope scope(stmt->pos);
|
switch (stmt->kind) {
|
#define ENUM_ITEM(name) \
|
case AstNode::Kind::k##name: \
|
return Visit(name::cast(stmt));
|
AST_STATEMENT_NODE_KIND_LIST(ENUM_ITEM)
|
#undef ENUM_ITEM
|
default:
|
UNIMPLEMENTED();
|
}
|
}
|
|
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();
|
}
|
}
|
|
void DeclarationVisitor::Visit(CallableNode* decl, const Signature& signature,
|
Statement* body) {
|
switch (decl->kind) {
|
#define ENUM_ITEM(name) \
|
case AstNode::Kind::k##name: \
|
return Visit(name::cast(decl), signature, body);
|
AST_CALLABLE_NODE_KIND_LIST(ENUM_ITEM)
|
#undef ENUM_ITEM
|
default:
|
UNIMPLEMENTED();
|
}
|
}
|
|
Builtin* DeclarationVisitor::BuiltinDeclarationCommon(
|
BuiltinDeclaration* decl, bool external, const Signature& signature) {
|
const bool javascript = decl->javascript_linkage;
|
const bool varargs = decl->signature->parameters.has_varargs;
|
Builtin::Kind kind = !javascript ? Builtin::kStub
|
: varargs ? Builtin::kVarArgsJavaScript
|
: Builtin::kFixedArgsJavaScript;
|
|
if (signature.types().size() == 0 ||
|
!(signature.types()[0] ==
|
declarations()->LookupGlobalType(CONTEXT_TYPE_STRING))) {
|
std::stringstream stream;
|
stream << "first parameter to builtin " << decl->name
|
<< " is not a context but should be";
|
ReportError(stream.str());
|
}
|
|
if (varargs && !javascript) {
|
std::stringstream stream;
|
stream << "builtin " << decl->name
|
<< " with rest parameters must be a JavaScript builtin";
|
ReportError(stream.str());
|
}
|
|
if (javascript) {
|
if (signature.types().size() < 2 ||
|
!(signature.types()[1] ==
|
declarations()->LookupGlobalType(OBJECT_TYPE_STRING))) {
|
std::stringstream stream;
|
stream << "second parameter to javascript builtin " << decl->name
|
<< " is " << *signature.types()[1] << " but should be Object";
|
ReportError(stream.str());
|
}
|
}
|
|
if (const StructType* struct_type =
|
StructType::DynamicCast(signature.return_type)) {
|
std::stringstream stream;
|
stream << "builtins (in this case" << decl->name
|
<< ") cannot return structs (in this case " << struct_type->name()
|
<< ")";
|
ReportError(stream.str());
|
}
|
|
std::string generated_name = GetGeneratedCallableName(
|
decl->name, declarations()->GetCurrentSpecializationTypeNamesVector());
|
return declarations()->DeclareBuiltin(generated_name, kind, external,
|
signature);
|
}
|
|
void DeclarationVisitor::Visit(ExternalRuntimeDeclaration* decl,
|
const Signature& signature, Statement* body) {
|
if (global_context_.verbose()) {
|
std::cout << "found declaration of external runtime " << decl->name
|
<< " with signature ";
|
}
|
|
if (signature.parameter_types.types.size() == 0 ||
|
!(signature.parameter_types.types[0] ==
|
declarations()->LookupGlobalType(CONTEXT_TYPE_STRING))) {
|
std::stringstream stream;
|
stream << "first parameter to runtime " << decl->name
|
<< " is not a context but should be";
|
ReportError(stream.str());
|
}
|
|
if (signature.return_type->IsStructType()) {
|
std::stringstream stream;
|
stream << "runtime functions (in this case" << decl->name
|
<< ") cannot return structs (in this case "
|
<< static_cast<const StructType*>(signature.return_type)->name()
|
<< ")";
|
ReportError(stream.str());
|
}
|
|
declarations()->DeclareRuntimeFunction(decl->name, signature);
|
}
|
|
void DeclarationVisitor::Visit(ExternalMacroDeclaration* decl,
|
const Signature& signature, Statement* body) {
|
if (global_context_.verbose()) {
|
std::cout << "found declaration of external macro " << decl->name
|
<< " with signature ";
|
}
|
|
std::string generated_name = GetGeneratedCallableName(
|
decl->name, declarations()->GetCurrentSpecializationTypeNamesVector());
|
declarations()->DeclareMacro(generated_name, signature, decl->op);
|
}
|
|
void DeclarationVisitor::Visit(TorqueBuiltinDeclaration* decl,
|
const Signature& signature, Statement* body) {
|
Builtin* builtin = BuiltinDeclarationCommon(decl, false, signature);
|
CurrentCallableActivator activator(global_context_, builtin, decl);
|
DeclareSignature(signature);
|
if (signature.parameter_types.var_args) {
|
declarations()->DeclareExternConstant(
|
decl->signature->parameters.arguments_variable,
|
TypeOracle::GetArgumentsType(), "arguments");
|
}
|
torque_builtins_.push_back(builtin);
|
Visit(body);
|
}
|
|
void DeclarationVisitor::Visit(TorqueMacroDeclaration* decl,
|
const Signature& signature, Statement* body) {
|
std::string generated_name = GetGeneratedCallableName(
|
decl->name, declarations()->GetCurrentSpecializationTypeNamesVector());
|
Macro* macro =
|
declarations()->DeclareMacro(generated_name, signature, decl->op);
|
|
CurrentCallableActivator activator(global_context_, macro, decl);
|
|
DeclareSignature(signature);
|
Variable* return_variable = nullptr;
|
if (!signature.return_type->IsVoidOrNever()) {
|
return_variable =
|
DeclareVariable(kReturnValueVariable, signature.return_type,
|
signature.return_type->IsConstexpr());
|
}
|
|
PushControlSplit();
|
if (body != nullptr) {
|
Visit(body);
|
}
|
auto changed_vars = PopControlSplit();
|
if (return_variable) changed_vars.insert(return_variable);
|
global_context_.AddControlSplitChangedVariables(
|
decl, declarations()->GetCurrentSpecializationTypeNamesVector(),
|
changed_vars);
|
}
|
|
void DeclarationVisitor::Visit(ConstDeclaration* decl) {
|
declarations()->DeclareModuleConstant(decl->name,
|
declarations()->GetType(decl->type));
|
Visit(decl->expression);
|
}
|
|
void DeclarationVisitor::Visit(StandardDeclaration* decl) {
|
Signature signature = MakeSignature(decl->callable->signature.get());
|
Visit(decl->callable, signature, decl->body);
|
}
|
|
void DeclarationVisitor::Visit(GenericDeclaration* decl) {
|
declarations()->DeclareGeneric(decl->callable->name, CurrentModule(), decl);
|
}
|
|
void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
|
if ((decl->body != nullptr) == decl->external) {
|
std::stringstream stream;
|
stream << "specialization of " << decl->name
|
<< " must either be marked 'extern' or have a body";
|
ReportError(stream.str());
|
}
|
|
GenericList* generic_list = declarations()->LookupGeneric(decl->name);
|
// Find the matching generic specialization based on the concrete parameter
|
// list.
|
CallableNode* matching_callable = nullptr;
|
SpecializationKey matching_key;
|
Signature signature_with_types = MakeSignature(decl->signature.get());
|
for (Generic* generic : generic_list->list()) {
|
SpecializationKey key = {generic, GetTypeVector(decl->generic_parameters)};
|
CallableNode* callable_candidate = generic->declaration()->callable;
|
// Abuse the Specialization nodes' scope to temporarily declare the
|
// specialization aliases for the generic types to compare signatures. This
|
// scope is never used for anything else, so it's OK to pollute it.
|
Declarations::CleanNodeScopeActivator specialization_activator(
|
declarations(), decl);
|
DeclareSpecializedTypes(key);
|
Signature generic_signature_with_types =
|
MakeSignature(generic->declaration()->callable->signature.get());
|
if (signature_with_types.HasSameTypesAs(generic_signature_with_types)) {
|
if (matching_callable != nullptr) {
|
std::stringstream stream;
|
stream << "specialization of " << callable_candidate->name
|
<< " is ambigous, it matches more than one generic declaration ("
|
<< *matching_key.first << " and " << *key.first << ")";
|
ReportError(stream.str());
|
}
|
matching_callable = callable_candidate;
|
matching_key = key;
|
}
|
}
|
|
if (matching_callable == nullptr) {
|
std::stringstream stream;
|
stream << "specialization of " << decl->name
|
<< " doesn't match any generic declaration";
|
ReportError(stream.str());
|
}
|
|
// Make sure the declarations of the parameter types for the specialization
|
// are the ones from the matching generic.
|
{
|
Declarations::CleanNodeScopeActivator specialization_activator(
|
declarations(), decl);
|
DeclareSpecializedTypes(matching_key);
|
}
|
|
SpecializeGeneric({matching_key, matching_callable, decl->signature.get(),
|
decl->body, decl->pos});
|
}
|
|
void DeclarationVisitor::Visit(ReturnStatement* stmt) {
|
if (stmt->value) {
|
Visit(*stmt->value);
|
}
|
}
|
|
Variable* DeclarationVisitor::DeclareVariable(const std::string& name,
|
const Type* type, bool is_const) {
|
Variable* result = declarations()->DeclareVariable(name, type, is_const);
|
if (type->IsStructType()) {
|
const StructType* struct_type = StructType::cast(type);
|
for (auto& field : struct_type->fields()) {
|
std::string field_var_name = name + "." + field.name;
|
DeclareVariable(field_var_name, field.type, is_const);
|
}
|
}
|
return result;
|
}
|
|
Parameter* DeclarationVisitor::DeclareParameter(const std::string& name,
|
const Type* type) {
|
Parameter* result = declarations()->DeclareParameter(
|
name, GetParameterVariableFromName(name), type);
|
if (type->IsStructType()) {
|
const StructType* struct_type = StructType::cast(type);
|
for (auto& field : struct_type->fields()) {
|
std::string field_var_name = name + "." + field.name;
|
DeclareParameter(field_var_name, field.type);
|
}
|
}
|
return result;
|
}
|
|
void DeclarationVisitor::Visit(VarDeclarationStatement* stmt) {
|
std::string variable_name = stmt->name;
|
if (!stmt->const_qualified) {
|
if (!stmt->type) {
|
ReportError(
|
"variable declaration is missing type. Only 'const' bindings can "
|
"infer the type.");
|
}
|
const Type* type = declarations()->GetType(*stmt->type);
|
if (type->IsConstexpr()) {
|
ReportError(
|
"cannot declare variable with constexpr type. Use 'const' instead.");
|
}
|
DeclareVariable(variable_name, type, stmt->const_qualified);
|
if (global_context_.verbose()) {
|
std::cout << "declared variable " << variable_name << " with type "
|
<< *type << "\n";
|
}
|
}
|
|
// const qualified variables are required to be initialized properly.
|
if (stmt->const_qualified && !stmt->initializer) {
|
std::stringstream stream;
|
stream << "local constant \"" << variable_name << "\" is not initialized.";
|
ReportError(stream.str());
|
}
|
|
if (stmt->initializer) {
|
Visit(*stmt->initializer);
|
if (global_context_.verbose()) {
|
std::cout << "variable has initialization expression at "
|
<< CurrentPositionAsString() << "\n";
|
}
|
}
|
}
|
|
void DeclarationVisitor::Visit(ExternConstDeclaration* decl) {
|
const Type* type = declarations()->GetType(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(StructDeclaration* decl) {
|
std::vector<NameAndType> fields;
|
for (auto& field : decl->fields) {
|
const Type* field_type = declarations()->GetType(field.type);
|
fields.push_back({field.name, field_type});
|
}
|
declarations()->DeclareStruct(CurrentModule(), decl->name, fields);
|
}
|
|
void DeclarationVisitor::Visit(LogicalOrExpression* expr) {
|
{
|
Declarations::NodeScopeActivator scope(declarations(), expr->left);
|
declarations()->DeclareLabel(kFalseLabelName);
|
Visit(expr->left);
|
}
|
Visit(expr->right);
|
}
|
|
void DeclarationVisitor::Visit(LogicalAndExpression* expr) {
|
{
|
Declarations::NodeScopeActivator scope(declarations(), expr->left);
|
declarations()->DeclareLabel(kTrueLabelName);
|
Visit(expr->left);
|
}
|
Visit(expr->right);
|
}
|
|
void DeclarationVisitor::DeclareExpressionForBranch(Expression* node) {
|
Declarations::NodeScopeActivator scope(declarations(), node);
|
// Conditional expressions can either explicitly return a bit
|
// type, or they can be backed by macros that don't return but
|
// take a true and false label. By declaring the labels before
|
// visiting the conditional expression, those label-based
|
// macro conditionals will be able to find them through normal
|
// label lookups.
|
declarations()->DeclareLabel(kTrueLabelName);
|
declarations()->DeclareLabel(kFalseLabelName);
|
Visit(node);
|
}
|
|
void DeclarationVisitor::Visit(ConditionalExpression* expr) {
|
DeclareExpressionForBranch(expr->condition);
|
PushControlSplit();
|
Visit(expr->if_true);
|
Visit(expr->if_false);
|
auto changed_vars = PopControlSplit();
|
global_context_.AddControlSplitChangedVariables(
|
expr, declarations()->GetCurrentSpecializationTypeNamesVector(),
|
changed_vars);
|
}
|
|
void DeclarationVisitor::Visit(IfStatement* stmt) {
|
if (!stmt->is_constexpr) {
|
PushControlSplit();
|
}
|
DeclareExpressionForBranch(stmt->condition);
|
Visit(stmt->if_true);
|
if (stmt->if_false) Visit(*stmt->if_false);
|
if (!stmt->is_constexpr) {
|
auto changed_vars = PopControlSplit();
|
global_context_.AddControlSplitChangedVariables(
|
stmt, declarations()->GetCurrentSpecializationTypeNamesVector(),
|
changed_vars);
|
}
|
}
|
|
void DeclarationVisitor::Visit(WhileStatement* stmt) {
|
Declarations::NodeScopeActivator scope(declarations(), stmt);
|
DeclareExpressionForBranch(stmt->condition);
|
PushControlSplit();
|
Visit(stmt->body);
|
auto changed_vars = PopControlSplit();
|
global_context_.AddControlSplitChangedVariables(
|
stmt, declarations()->GetCurrentSpecializationTypeNamesVector(),
|
changed_vars);
|
}
|
|
void DeclarationVisitor::Visit(ForOfLoopStatement* stmt) {
|
// Scope for for iteration variable
|
Declarations::NodeScopeActivator scope(declarations(), stmt);
|
Visit(stmt->var_declaration);
|
Visit(stmt->iterable);
|
if (stmt->begin) Visit(*stmt->begin);
|
if (stmt->end) Visit(*stmt->end);
|
PushControlSplit();
|
Visit(stmt->body);
|
auto changed_vars = PopControlSplit();
|
global_context_.AddControlSplitChangedVariables(
|
stmt, declarations()->GetCurrentSpecializationTypeNamesVector(),
|
changed_vars);
|
}
|
|
void DeclarationVisitor::Visit(ForLoopStatement* stmt) {
|
Declarations::NodeScopeActivator scope(declarations(), stmt);
|
if (stmt->var_declaration) Visit(*stmt->var_declaration);
|
PushControlSplit();
|
|
// Same as DeclareExpressionForBranch, but without the extra scope.
|
// If no test expression is present we can not use it for the scope.
|
declarations()->DeclareLabel(kTrueLabelName);
|
declarations()->DeclareLabel(kFalseLabelName);
|
if (stmt->test) Visit(*stmt->test);
|
|
Visit(stmt->body);
|
if (stmt->action) Visit(*stmt->action);
|
auto changed_vars = PopControlSplit();
|
global_context_.AddControlSplitChangedVariables(
|
stmt, declarations()->GetCurrentSpecializationTypeNamesVector(),
|
changed_vars);
|
}
|
|
void DeclarationVisitor::Visit(TryLabelStatement* stmt) {
|
// Activate a new scope to declare handler labels, they should not be
|
// visible outside the label block.
|
{
|
Declarations::NodeScopeActivator scope(declarations(), stmt);
|
|
// Declare labels
|
for (LabelBlock* block : stmt->label_blocks) {
|
CurrentSourcePosition::Scope scope(block->pos);
|
Label* shared_label = declarations()->DeclareLabel(block->label);
|
{
|
Declarations::NodeScopeActivator scope(declarations(), block->body);
|
if (block->parameters.has_varargs) {
|
std::stringstream stream;
|
stream << "cannot use ... for label parameters";
|
ReportError(stream.str());
|
}
|
|
size_t i = 0;
|
for (auto p : block->parameters.names) {
|
const Type* type =
|
declarations()->GetType(block->parameters.types[i]);
|
if (type->IsConstexpr()) {
|
ReportError("no constexpr type allowed for label arguments");
|
}
|
|
shared_label->AddVariable(DeclareVariable(p, type, false));
|
++i;
|
}
|
}
|
if (global_context_.verbose()) {
|
std::cout << " declaring label " << block->label << "\n";
|
}
|
}
|
|
Visit(stmt->try_block);
|
}
|
|
for (LabelBlock* block : stmt->label_blocks) {
|
Visit(block->body);
|
}
|
}
|
|
void DeclarationVisitor::GenerateHeader(std::string& file_name) {
|
std::stringstream new_contents_stream;
|
new_contents_stream
|
<< "#ifndef V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
|
"#define V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
|
"\n"
|
"#define BUILTIN_LIST_FROM_DSL(CPP, API, TFJ, TFC, TFS, TFH, ASM) "
|
"\\\n";
|
for (auto builtin : torque_builtins_) {
|
int firstParameterIndex = 1;
|
bool declareParameters = true;
|
if (builtin->IsStub()) {
|
new_contents_stream << "TFS(" << builtin->name();
|
} else {
|
new_contents_stream << "TFJ(" << builtin->name();
|
if (builtin->IsVarArgsJavaScript()) {
|
new_contents_stream
|
<< ", SharedFunctionInfo::kDontAdaptArgumentsSentinel";
|
declareParameters = false;
|
} else {
|
assert(builtin->IsFixedArgsJavaScript());
|
// FixedArg javascript builtins need to offer the parameter
|
// count.
|
assert(builtin->parameter_names().size() >= 2);
|
new_contents_stream << ", " << (builtin->parameter_names().size() - 2);
|
// And the receiver is explicitly declared.
|
new_contents_stream << ", kReceiver";
|
firstParameterIndex = 2;
|
}
|
}
|
if (declareParameters) {
|
int index = 0;
|
for (auto parameter : builtin->parameter_names()) {
|
if (index >= firstParameterIndex) {
|
new_contents_stream << ", k" << CamelifyString(parameter);
|
}
|
index++;
|
}
|
}
|
new_contents_stream << ") \\\n";
|
}
|
new_contents_stream
|
<< "\n"
|
"#endif // V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
|
|
std::string new_contents(new_contents_stream.str());
|
ReplaceFileContentsIfDifferent(file_name, new_contents);
|
}
|
|
void DeclarationVisitor::Visit(IdentifierExpression* expr) {
|
if (expr->generic_arguments.size() != 0) {
|
TypeVector specialization_types;
|
for (auto t : expr->generic_arguments) {
|
specialization_types.push_back(declarations()->GetType(t));
|
}
|
// Specialize all versions of the generic, since the exact parameter type
|
// list cannot be resolved until the call's parameter expressions are
|
// evaluated. This is an overly conservative but simple way to make sure
|
// that the correct specialization exists.
|
for (auto generic : declarations()->LookupGeneric(expr->name)->list()) {
|
CallableNode* callable = generic->declaration()->callable;
|
if (generic->declaration()->body) {
|
QueueGenericSpecialization({generic, specialization_types}, callable,
|
callable->signature.get(),
|
generic->declaration()->body);
|
}
|
}
|
}
|
}
|
|
void DeclarationVisitor::Visit(CallExpression* expr) {
|
Visit(&expr->callee);
|
for (Expression* arg : expr->arguments) Visit(arg);
|
}
|
|
void DeclarationVisitor::Visit(TypeDeclaration* decl) {
|
std::string generates = decl->generates ? *decl->generates : std::string("");
|
const AbstractType* type = declarations()->DeclareAbstractType(
|
decl->name, generates, {}, decl->extends);
|
|
if (decl->constexpr_generates) {
|
std::string constexpr_name = CONSTEXPR_TYPE_PREFIX + decl->name;
|
base::Optional<std::string> constexpr_extends;
|
if (decl->extends)
|
constexpr_extends = CONSTEXPR_TYPE_PREFIX + *decl->extends;
|
declarations()->DeclareAbstractType(
|
constexpr_name, *decl->constexpr_generates, type, constexpr_extends);
|
}
|
}
|
|
void DeclarationVisitor::MarkLocationModified(Expression* location) {
|
if (IdentifierExpression* id = IdentifierExpression::cast(location)) {
|
const Value* value = declarations()->LookupValue(id->name);
|
if (value->IsVariable()) {
|
const Variable* variable = Variable::cast(value);
|
bool was_live = MarkVariableModified(variable);
|
if (was_live && global_context_.verbose()) {
|
std::cout << *variable << " was modified in control split at "
|
<< PositionAsString(id->pos) << "\n";
|
}
|
}
|
}
|
}
|
|
bool DeclarationVisitor::MarkVariableModified(const Variable* variable) {
|
auto e = live_and_changed_variables_.rend();
|
auto c = live_and_changed_variables_.rbegin();
|
bool was_live_in_preceeding_split = false;
|
while (c != e) {
|
if (c->live.find(variable) != c->live.end()) {
|
c->changed.insert(variable);
|
was_live_in_preceeding_split = true;
|
}
|
c++;
|
}
|
return was_live_in_preceeding_split;
|
}
|
|
void DeclarationVisitor::DeclareSignature(const Signature& signature) {
|
auto type_iterator = signature.parameter_types.types.begin();
|
for (auto name : signature.parameter_names) {
|
const Type* t(*type_iterator++);
|
if (name.size() != 0) {
|
DeclareParameter(name, t);
|
}
|
}
|
for (auto& label : signature.labels) {
|
auto label_params = label.types;
|
Label* new_label = declarations()->DeclareLabel(label.name);
|
size_t i = 0;
|
for (auto var_type : label_params) {
|
if (var_type->IsConstexpr()) {
|
ReportError("no constexpr type allowed for label arguments");
|
}
|
|
std::string var_name = label.name + std::to_string(i++);
|
new_label->AddVariable(DeclareVariable(var_name, var_type, false));
|
}
|
}
|
}
|
|
void DeclarationVisitor::DeclareSpecializedTypes(const SpecializationKey& key) {
|
size_t i = 0;
|
Generic* generic = key.first;
|
const std::size_t generic_parameter_count =
|
generic->declaration()->generic_parameters.size();
|
if (generic_parameter_count != key.second.size()) {
|
std::stringstream stream;
|
stream << "Wrong generic argument count for specialization of \""
|
<< generic->name() << "\", expected: " << generic_parameter_count
|
<< ", actual: " << key.second.size();
|
ReportError(stream.str());
|
}
|
|
for (auto type : key.second) {
|
std::string generic_type_name =
|
generic->declaration()->generic_parameters[i++];
|
declarations()->DeclareType(generic_type_name, type);
|
}
|
}
|
|
void DeclarationVisitor::Specialize(const SpecializationKey& key,
|
CallableNode* callable,
|
const CallableNodeSignature* signature,
|
Statement* body) {
|
Generic* generic = key.first;
|
|
// TODO(tebbi): The error should point to the source position where the
|
// instantiation was requested.
|
CurrentSourcePosition::Scope pos_scope(generic->declaration()->pos);
|
size_t generic_parameter_count =
|
generic->declaration()->generic_parameters.size();
|
if (generic_parameter_count != key.second.size()) {
|
std::stringstream stream;
|
stream << "number of template parameters ("
|
<< std::to_string(key.second.size())
|
<< ") to intantiation of generic " << callable->name
|
<< " doesnt match the generic's declaration ("
|
<< std::to_string(generic_parameter_count) << ")";
|
ReportError(stream.str());
|
}
|
|
Signature type_signature;
|
{
|
// Manually activate the specialized generic's scope when declaring the
|
// generic parameter specializations.
|
Declarations::GenericScopeActivator namespace_scope(declarations(), key);
|
DeclareSpecializedTypes(key);
|
type_signature = MakeSignature(signature);
|
}
|
|
Visit(callable, type_signature, body);
|
}
|
|
} // namespace torque
|
} // namespace internal
|
} // namespace v8
|