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, ...@@ -160,8 +160,8 @@ void DeclarationVisitor::Visit(TorqueBuiltinDeclaration* decl,
const Signature& signature, Statement* body) { const Signature& signature, Statement* body) {
Builtin* builtin = BuiltinDeclarationCommon(decl, false, signature); Builtin* builtin = BuiltinDeclarationCommon(decl, false, signature);
CurrentCallableActivator activator(global_context_, builtin, decl); CurrentCallableActivator activator(global_context_, builtin, decl);
DeclareSignature(builtin->signature()); DeclareSignature(signature);
if (builtin->signature().parameter_types.var_args) { if (signature.parameter_types.var_args) {
declarations()->DeclareConstant( declarations()->DeclareConstant(
decl->signature->parameters.arguments_variable, decl->signature->parameters.arguments_variable,
GetTypeOracle().GetArgumentsType(), "arguments"); GetTypeOracle().GetArgumentsType(), "arguments");
...@@ -206,23 +206,29 @@ void DeclarationVisitor::Visit(SpecializationDeclaration* decl) { ...@@ -206,23 +206,29 @@ void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
Generic* generic = declarations()->LookupGeneric(decl->name); Generic* generic = declarations()->LookupGeneric(decl->name);
SpecializationKey key = {generic, GetTypeVector(decl->generic_parameters)}; SpecializationKey key = {generic, GetTypeVector(decl->generic_parameters)};
CallableNode* callable = generic->declaration()->callable; 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()) { Signature signature_with_types =
std::stringstream stream; MakeSignature(callable, decl->signature.get());
stream << "specialization parameter count doesn't match generic " // Abuse the Specialization nodes' scope to temporarily declare the
"declaration at " // specialization aliases for the generic types to compare signatures. This
<< PositionAsString(decl->pos); // scope is never used for anything else, so it's OK to pollute it.
ReportError(stream.str()); Declarations::NodeScopeActivator specialization_activator(declarations(),
} decl);
if (callable->signature->labels.size() != decl->signature->labels.size()) { DeclareSpecializedTypes(key);
std::stringstream stream; Signature generic_signature_with_types =
stream << "specialization label count doesn't match generic " MakeSignature(generic->declaration()->callable,
"declaration at " generic->declaration()->callable->signature.get());
<< PositionAsString(decl->pos); if (!signature_with_types.HasSameTypesAs(generic_signature_with_types)) {
ReportError(stream.str()); 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) { void DeclarationVisitor::Visit(ReturnStatement* stmt) {
...@@ -312,6 +318,16 @@ void DeclarationVisitor::Visit(CallExpression* expr) { ...@@ -312,6 +318,16 @@ void DeclarationVisitor::Visit(CallExpression* expr) {
for (Expression* arg : expr->arguments) Visit(arg); 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, void DeclarationVisitor::Specialize(const SpecializationKey& key,
CallableNode* callable, CallableNode* callable,
const CallableNodeSignature* signature, const CallableNodeSignature* signature,
...@@ -334,15 +350,10 @@ void DeclarationVisitor::Specialize(const SpecializationKey& key, ...@@ -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. // generic parameter specializations.
Declarations::GenericScopeActivator scope(declarations(), key); Declarations::GenericScopeActivator scope(declarations(), key);
size_t i = 0; DeclareSpecializedTypes(key);
for (auto type : key.second) {
std::string generic_type_name =
generic->declaration()->generic_parameters[i++];
declarations()->DeclareTypeAlias(generic_type_name, type);
}
} }
Visit(callable, MakeSignature(callable, signature), body); Visit(callable, MakeSignature(callable, signature), body);
......
...@@ -354,6 +354,8 @@ class DeclarationVisitor : public FileVisitor { ...@@ -354,6 +354,8 @@ class DeclarationVisitor : public FileVisitor {
} }
} }
void DeclareSpecializedTypes(const SpecializationKey& key);
void Specialize(const SpecializationKey& key, CallableNode* callable, void Specialize(const SpecializationKey& key, CallableNode* callable,
const CallableNodeSignature* signature, const CallableNodeSignature* signature,
Statement* body) override; Statement* body) override;
......
...@@ -106,7 +106,8 @@ class Declarations { ...@@ -106,7 +106,8 @@ class Declarations {
class NodeScopeActivator; class NodeScopeActivator;
class GenericScopeActivator; class GenericScopeActivator;
class ScopedGenericInstantiation; class ScopedGenericSpecializationKey;
class ScopedGenericScopeChainSnapshot;
private: private:
Scope* GetNodeScope(const AstNode* node); Scope* GetNodeScope(const AstNode* node);
...@@ -156,20 +157,29 @@ class Declarations::GenericScopeActivator { ...@@ -156,20 +157,29 @@ class Declarations::GenericScopeActivator {
Scope::Activator activator_; Scope::Activator activator_;
}; };
class Declarations::ScopedGenericInstantiation { class Declarations::ScopedGenericSpecializationKey {
public: public:
ScopedGenericInstantiation(Declarations* declarations, ScopedGenericSpecializationKey(Declarations* declarations,
const SpecializationKey& key) const SpecializationKey& key)
: declarations_(declarations), : declarations_(declarations) {
restorer_(declarations->generic_declaration_scopes_[key.first]) {
declarations->current_generic_specialization_ = &key; declarations->current_generic_specialization_ = &key;
} }
~ScopedGenericInstantiation() { ~ScopedGenericSpecializationKey() {
declarations_->current_generic_specialization_ = nullptr; declarations_->current_generic_specialization_ = nullptr;
} }
private: private:
Declarations* declarations_; Declarations* declarations_;
};
class Declarations::ScopedGenericScopeChainSnapshot {
public:
ScopedGenericScopeChainSnapshot(Declarations* declarations,
const SpecializationKey& key)
: restorer_(declarations->generic_declaration_scopes_[key.first]) {}
~ScopedGenericScopeChainSnapshot() {}
private:
ScopeChain::ScopedSnapshotRestorer restorer_; ScopeChain::ScopedSnapshotRestorer restorer_;
}; };
......
...@@ -87,10 +87,28 @@ Callable* FileVisitor::LookupCall(const std::string& name, ...@@ -87,10 +87,28 @@ Callable* FileVisitor::LookupCall(const std::string& name,
} }
void FileVisitor::QueueGenericSpecialization( void FileVisitor::QueueGenericSpecialization(
SpecializationKey key, CallableNode* callable, const SpecializationKey& key, CallableNode* callable,
const CallableNodeSignature* signature, Statement* body) { const CallableNodeSignature* signature, Statement* body) {
pending_specializations_.push_back({key, callable, signature, body, pending_specializations_.push_back({key, callable, signature, body});
declarations()->GetScopeChainSnapshot()}); }
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() { void FileVisitor::DrainSpecializationQueue() {
...@@ -99,13 +117,9 @@ void FileVisitor::DrainSpecializationQueue() { ...@@ -99,13 +117,9 @@ void FileVisitor::DrainSpecializationQueue() {
pending_specializations_.pop_front(); pending_specializations_.pop_front();
if (completed_specializations_.find(specialization.key) == if (completed_specializations_.find(specialization.key) ==
completed_specializations_.end()) { completed_specializations_.end()) {
Declarations::ScopedGenericInstantiation instantiation( Declarations::ScopedGenericScopeChainSnapshot scope(declarations(),
declarations(), specialization.key); specialization.key);
FileVisitor::ScopedModuleActivator activator( SpecializeGeneric(specialization);
this, specialization.key.first->module());
Specialize(specialization.key, specialization.callable,
specialization.signature, specialization.body);
completed_specializations_.insert(specialization.key);
} }
} }
} }
......
...@@ -82,13 +82,15 @@ class FileVisitor { ...@@ -82,13 +82,15 @@ class FileVisitor {
CallableNode* callable; CallableNode* callable;
const CallableNodeSignature* signature; const CallableNodeSignature* signature;
Statement* body; Statement* body;
ScopeChain::Snapshot snapshot;
}; };
void QueueGenericSpecialization(SpecializationKey, CallableNode* callable, void QueueGenericSpecialization(const SpecializationKey& key,
CallableNode* callable,
const CallableNodeSignature* signature, const CallableNodeSignature* signature,
Statement* body); Statement* body);
void SpecializeGeneric(const PendingSpecialization& specialization);
virtual void Specialize(const SpecializationKey&, CallableNode* callable, virtual void Specialize(const SpecializationKey&, CallableNode* callable,
const CallableNodeSignature* signature, const CallableNodeSignature* signature,
Statement* body) = 0; Statement* body) = 0;
......
...@@ -1437,8 +1437,10 @@ void ImplementationVisitor::Visit(SpecializationDeclaration* decl) { ...@@ -1437,8 +1437,10 @@ void ImplementationVisitor::Visit(SpecializationDeclaration* decl) {
Generic* generic = declarations()->LookupGeneric(decl->name); Generic* generic = declarations()->LookupGeneric(decl->name);
TypeVector specialization_types = GetTypeVector(decl->generic_parameters); TypeVector specialization_types = GetTypeVector(decl->generic_parameters);
CallableNode* callable = generic->declaration()->callable; CallableNode* callable = generic->declaration()->callable;
QueueGenericSpecialization({generic, specialization_types}, callable, SpecializeGeneric({{generic, specialization_types},
decl->signature.get(), decl->body); callable,
decl->signature.get(),
decl->body});
} }
VisitResult ImplementationVisitor::Visit(CallExpression* expr, VisitResult ImplementationVisitor::Visit(CallExpression* expr,
......
...@@ -50,6 +50,24 @@ std::ostream& operator<<(std::ostream& os, const ParameterTypes& p) { ...@@ -50,6 +50,24 @@ std::ostream& operator<<(std::ostream& os, const ParameterTypes& p) {
return os; 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 torque
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -97,6 +97,7 @@ struct Signature { ...@@ -97,6 +97,7 @@ struct Signature {
ParameterTypes parameter_types; ParameterTypes parameter_types;
const Type* return_type; const Type* return_type;
LabelDeclarationVector labels; LabelDeclarationVector labels;
bool HasSameTypesAs(const Signature& other) const;
}; };
struct Arguments { 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