Commit d4c812d8 authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

[torque]: Ensure specializations match generic signature

Fixes known issue that specialization doesn't rigorously checked to
verify that specialization signature precisely matches generic
declaration.

Change-Id: I884f7f16a467ab716d2b0c553485f4b1c55ed806
Reviewed-on: https://chromium-review.googlesource.com/1063613Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Daniel Clifford <danno@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53252}
parent e15a3fad
......@@ -160,8 +160,8 @@ void DeclarationVisitor::Visit(TorqueBuiltinDeclaration* decl,
const Signature& signature, Statement* body) {
Builtin* builtin = BuiltinDeclarationCommon(decl, false, signature);
CurrentCallableActivator activator(global_context_, builtin, decl);
DeclareSignature(builtin->signature());
if (builtin->signature().parameter_types.var_args) {
DeclareSignature(signature);
if (signature.parameter_types.var_args) {
declarations()->DeclareConstant(
decl->signature->parameters.arguments_variable,
GetTypeOracle().GetArgumentsType(), "arguments");
......@@ -206,23 +206,29 @@ void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
Generic* generic = declarations()->LookupGeneric(decl->name);
SpecializationKey key = {generic, GetTypeVector(decl->generic_parameters)};
CallableNode* callable = generic->declaration()->callable;
// Ensure that the specialized signature matches the generic signature.
if (callable->signature->parameters.names.size() !=
decl->signature->parameters.names.size()) {
std::stringstream stream;
stream << "specialization parameter count doesn't match generic "
"declaration at "
<< PositionAsString(decl->pos);
ReportError(stream.str());
}
if (callable->signature->labels.size() != decl->signature->labels.size()) {
std::stringstream stream;
stream << "specialization label count doesn't match generic "
"declaration at "
<< PositionAsString(decl->pos);
ReportError(stream.str());
{
Signature signature_with_types =
MakeSignature(callable, decl->signature.get());
// 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::NodeScopeActivator specialization_activator(declarations(),
decl);
DeclareSpecializedTypes(key);
Signature generic_signature_with_types =
MakeSignature(generic->declaration()->callable,
generic->declaration()->callable->signature.get());
if (!signature_with_types.HasSameTypesAs(generic_signature_with_types)) {
std::stringstream stream;
stream << "specialization of " << callable->name
<< " has incompatible parameter list or label list with generic "
"definition";
ReportError(stream.str());
}
}
QueueGenericSpecialization(key, callable, decl->signature.get(), decl->body);
SpecializeGeneric({key, callable, decl->signature.get(), decl->body});
}
void DeclarationVisitor::Visit(ReturnStatement* stmt) {
......@@ -312,6 +318,16 @@ void DeclarationVisitor::Visit(CallExpression* expr) {
for (Expression* arg : expr->arguments) Visit(arg);
}
void DeclarationVisitor::DeclareSpecializedTypes(const SpecializationKey& key) {
size_t i = 0;
Generic* generic = key.first;
for (auto type : key.second) {
std::string generic_type_name =
generic->declaration()->generic_parameters[i++];
declarations()->DeclareTypeAlias(generic_type_name, type);
}
}
void DeclarationVisitor::Specialize(const SpecializationKey& key,
CallableNode* callable,
const CallableNodeSignature* signature,
......@@ -334,15 +350,10 @@ void DeclarationVisitor::Specialize(const SpecializationKey& key,
}
{
// Manually activate the specialized generic's scope when defining the
// Manually activate the specialized generic's scope when declaring the
// generic parameter specializations.
Declarations::GenericScopeActivator scope(declarations(), key);
size_t i = 0;
for (auto type : key.second) {
std::string generic_type_name =
generic->declaration()->generic_parameters[i++];
declarations()->DeclareTypeAlias(generic_type_name, type);
}
DeclareSpecializedTypes(key);
}
Visit(callable, MakeSignature(callable, signature), body);
......
......@@ -354,6 +354,8 @@ class DeclarationVisitor : public FileVisitor {
}
}
void DeclareSpecializedTypes(const SpecializationKey& key);
void Specialize(const SpecializationKey& key, CallableNode* callable,
const CallableNodeSignature* signature,
Statement* body) override;
......
......@@ -106,7 +106,8 @@ class Declarations {
class NodeScopeActivator;
class GenericScopeActivator;
class ScopedGenericInstantiation;
class ScopedGenericSpecializationKey;
class ScopedGenericScopeChainSnapshot;
private:
Scope* GetNodeScope(const AstNode* node);
......@@ -156,20 +157,29 @@ class Declarations::GenericScopeActivator {
Scope::Activator activator_;
};
class Declarations::ScopedGenericInstantiation {
class Declarations::ScopedGenericSpecializationKey {
public:
ScopedGenericInstantiation(Declarations* declarations,
const SpecializationKey& key)
: declarations_(declarations),
restorer_(declarations->generic_declaration_scopes_[key.first]) {
ScopedGenericSpecializationKey(Declarations* declarations,
const SpecializationKey& key)
: declarations_(declarations) {
declarations->current_generic_specialization_ = &key;
}
~ScopedGenericInstantiation() {
~ScopedGenericSpecializationKey() {
declarations_->current_generic_specialization_ = nullptr;
}
private:
Declarations* declarations_;
};
class Declarations::ScopedGenericScopeChainSnapshot {
public:
ScopedGenericScopeChainSnapshot(Declarations* declarations,
const SpecializationKey& key)
: restorer_(declarations->generic_declaration_scopes_[key.first]) {}
~ScopedGenericScopeChainSnapshot() {}
private:
ScopeChain::ScopedSnapshotRestorer restorer_;
};
......
......@@ -87,10 +87,28 @@ Callable* FileVisitor::LookupCall(const std::string& name,
}
void FileVisitor::QueueGenericSpecialization(
SpecializationKey key, CallableNode* callable,
const SpecializationKey& key, CallableNode* callable,
const CallableNodeSignature* signature, Statement* body) {
pending_specializations_.push_back({key, callable, signature, body,
declarations()->GetScopeChainSnapshot()});
pending_specializations_.push_back({key, callable, signature, body});
}
void FileVisitor::SpecializeGeneric(
const PendingSpecialization& specialization) {
if (completed_specializations_.find(specialization.key) !=
completed_specializations_.end()) {
std::stringstream stream;
stream << "cannot redeclare specialization of "
<< specialization.key.first->declaration()->callable->name
<< " with types <" << specialization.key.second << ">";
ReportError(stream.str());
}
Declarations::ScopedGenericSpecializationKey instantiation(
declarations(), specialization.key);
FileVisitor::ScopedModuleActivator activator(
this, specialization.key.first->module());
Specialize(specialization.key, specialization.callable,
specialization.signature, specialization.body);
completed_specializations_.insert(specialization.key);
}
void FileVisitor::DrainSpecializationQueue() {
......@@ -99,13 +117,9 @@ void FileVisitor::DrainSpecializationQueue() {
pending_specializations_.pop_front();
if (completed_specializations_.find(specialization.key) ==
completed_specializations_.end()) {
Declarations::ScopedGenericInstantiation instantiation(
declarations(), specialization.key);
FileVisitor::ScopedModuleActivator activator(
this, specialization.key.first->module());
Specialize(specialization.key, specialization.callable,
specialization.signature, specialization.body);
completed_specializations_.insert(specialization.key);
Declarations::ScopedGenericScopeChainSnapshot scope(declarations(),
specialization.key);
SpecializeGeneric(specialization);
}
}
}
......
......@@ -82,13 +82,15 @@ class FileVisitor {
CallableNode* callable;
const CallableNodeSignature* signature;
Statement* body;
ScopeChain::Snapshot snapshot;
};
void QueueGenericSpecialization(SpecializationKey, CallableNode* callable,
void QueueGenericSpecialization(const SpecializationKey& key,
CallableNode* callable,
const CallableNodeSignature* signature,
Statement* body);
void SpecializeGeneric(const PendingSpecialization& specialization);
virtual void Specialize(const SpecializationKey&, CallableNode* callable,
const CallableNodeSignature* signature,
Statement* body) = 0;
......
......@@ -1437,8 +1437,10 @@ void ImplementationVisitor::Visit(SpecializationDeclaration* decl) {
Generic* generic = declarations()->LookupGeneric(decl->name);
TypeVector specialization_types = GetTypeVector(decl->generic_parameters);
CallableNode* callable = generic->declaration()->callable;
QueueGenericSpecialization({generic, specialization_types}, callable,
decl->signature.get(), decl->body);
SpecializeGeneric({{generic, specialization_types},
callable,
decl->signature.get(),
decl->body});
}
VisitResult ImplementationVisitor::Visit(CallExpression* expr,
......
......@@ -50,6 +50,24 @@ std::ostream& operator<<(std::ostream& os, const ParameterTypes& p) {
return os;
}
bool Signature::HasSameTypesAs(const Signature& other) const {
if (!(parameter_types.types == other.parameter_types.types &&
parameter_types.var_args == other.parameter_types.var_args &&
return_type == other.return_type)) {
return false;
}
if (labels.size() != other.labels.size()) {
return false;
}
size_t i = 0;
for (auto l : labels) {
if (l.types != other.labels[i++].types) {
return false;
}
}
return true;
}
} // namespace torque
} // namespace internal
} // namespace v8
......@@ -97,6 +97,7 @@ struct Signature {
ParameterTypes parameter_types;
const Type* return_type;
LabelDeclarationVector labels;
bool HasSameTypesAs(const Signature& other) const;
};
struct Arguments {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment