[torque] use implicit parameters for template parameter inference
This allows templates to preserve the type of implicit parameters to select a better ovleroad, without generally extending overload resolution to implicit parameters, which could be confusing. Bug: v8:7793 Change-Id: Ie57090a295b0b46d03789829b975fc16e2a9c5b9 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2329630 Commit-Queue: Tobias Tebbi <tebbi@chromium.org> Reviewed-by: Seth Brenith <seth.brenith@microsoft.com> Cr-Commit-Position: refs/heads/master@{#69177}
This commit is contained in:
parent
09db7cf9a5
commit
50d5c2bb07
@ -2,10 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/torque/declarable.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "src/torque/declarable.h"
|
||||
#include "src/torque/ast.h"
|
||||
#include "src/torque/global-context.h"
|
||||
#include "src/torque/type-inference.h"
|
||||
#include "src/torque/type-visitor.h"
|
||||
@ -134,17 +136,13 @@ std::vector<TypeConstraint> ComputeConstraints(
|
||||
|
||||
TypeArgumentInference GenericCallable::InferSpecializationTypes(
|
||||
const TypeVector& explicit_specialization_types,
|
||||
const TypeVector& arguments) {
|
||||
size_t implicit_count = declaration()->parameters.implicit_count;
|
||||
const std::vector<base::Optional<const Type*>>& arguments) {
|
||||
const std::vector<TypeExpression*>& parameters =
|
||||
declaration()->parameters.types;
|
||||
std::vector<TypeExpression*> explicit_parameters(
|
||||
parameters.begin() + implicit_count, parameters.end());
|
||||
|
||||
CurrentScope::Scope generic_scope(ParentScope());
|
||||
TypeArgumentInference inference(generic_parameters(),
|
||||
explicit_specialization_types,
|
||||
explicit_parameters, arguments);
|
||||
explicit_specialization_types, parameters,
|
||||
arguments);
|
||||
if (!inference.HasFailed()) {
|
||||
if (auto violation =
|
||||
FindConstraintViolation(inference.GetResult(), Constraints())) {
|
||||
|
@ -567,7 +567,7 @@ class GenericCallable
|
||||
|
||||
TypeArgumentInference InferSpecializationTypes(
|
||||
const TypeVector& explicit_specialization_types,
|
||||
const TypeVector& arguments);
|
||||
const std::vector<base::Optional<const Type*>>& arguments);
|
||||
|
||||
private:
|
||||
friend class Declarations;
|
||||
|
@ -196,9 +196,10 @@ void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
|
||||
// This argument inference is just to trigger constraint checking on the
|
||||
// generic arguments.
|
||||
TypeArgumentInference inference = generic->InferSpecializationTypes(
|
||||
TypeVisitor::ComputeTypeVector(decl->generic_parameters),
|
||||
signature_with_types.GetExplicitTypes());
|
||||
if (inference.HasFailed()) continue;
|
||||
TypeVisitor::ComputeTypeVector(decl->generic_parameters), {});
|
||||
if (inference.HasFailed()) {
|
||||
continue;
|
||||
}
|
||||
Signature generic_signature_with_types =
|
||||
MakeSpecializedSignature(SpecializationKey<GenericCallable>{
|
||||
generic, TypeVisitor::ComputeTypeVector(decl->generic_parameters)});
|
||||
|
@ -1786,6 +1786,25 @@ bool ImplementationVisitor::TestLookupCallable(
|
||||
{}, {}, true) != nullptr;
|
||||
}
|
||||
|
||||
TypeArgumentInference ImplementationVisitor::InferSpecializationTypes(
|
||||
GenericCallable* generic, const TypeVector& explicit_specialization_types,
|
||||
const TypeVector& explicit_arguments) {
|
||||
std::vector<base::Optional<const Type*>> all_arguments;
|
||||
const ParameterList& parameters = generic->declaration()->parameters;
|
||||
for (size_t i = 0; i < parameters.implicit_count; ++i) {
|
||||
base::Optional<Binding<LocalValue>*> val =
|
||||
TryLookupLocalValue(parameters.names[i]->value);
|
||||
all_arguments.push_back(
|
||||
val ? (*val)->GetLocationReference(*val).ReferencedType()
|
||||
: base::nullopt);
|
||||
}
|
||||
for (const Type* explicit_argument : explicit_arguments) {
|
||||
all_arguments.push_back(explicit_argument);
|
||||
}
|
||||
return generic->InferSpecializationTypes(explicit_specialization_types,
|
||||
all_arguments);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
Callable* ImplementationVisitor::LookupCallable(
|
||||
const QualifiedName& name, const Container& declaration_container,
|
||||
@ -1799,8 +1818,8 @@ Callable* ImplementationVisitor::LookupCallable(
|
||||
std::vector<std::pair<GenericCallable*, std::string>> inapplicable_generics;
|
||||
for (auto* declarable : declaration_container) {
|
||||
if (GenericCallable* generic = GenericCallable::DynamicCast(declarable)) {
|
||||
TypeArgumentInference inference = generic->InferSpecializationTypes(
|
||||
specialization_types, parameter_types);
|
||||
TypeArgumentInference inference = InferSpecializationTypes(
|
||||
generic, specialization_types, parameter_types);
|
||||
if (inference.HasFailed()) {
|
||||
inapplicable_generics.push_back(
|
||||
std::make_pair(generic, inference.GetFailureReason()));
|
||||
@ -1861,8 +1880,8 @@ Callable* ImplementationVisitor::LookupCallable(
|
||||
|
||||
if (GenericCallable* generic =
|
||||
GenericCallable::DynamicCast(overloads[best])) {
|
||||
TypeArgumentInference inference = generic->InferSpecializationTypes(
|
||||
specialization_types, parameter_types);
|
||||
TypeArgumentInference inference = InferSpecializationTypes(
|
||||
generic, specialization_types, parameter_types);
|
||||
result = GetOrCreateSpecialization(
|
||||
SpecializationKey<GenericCallable>{generic, inference.GetResult()});
|
||||
} else {
|
||||
|
@ -682,6 +682,10 @@ class ImplementationVisitor {
|
||||
const Arguments& arguments,
|
||||
const TypeVector& specialization_types);
|
||||
|
||||
TypeArgumentInference InferSpecializationTypes(
|
||||
GenericCallable* generic, const TypeVector& explicit_specialization_types,
|
||||
const TypeVector& explicit_arguments);
|
||||
|
||||
const Type* GetCommonType(const Type* left, const Type* right);
|
||||
|
||||
VisitResult GenerateCopy(const VisitResult& to_copy);
|
||||
|
@ -12,7 +12,7 @@ TypeArgumentInference::TypeArgumentInference(
|
||||
const GenericParameters& type_parameters,
|
||||
const TypeVector& explicit_type_arguments,
|
||||
const std::vector<TypeExpression*>& term_parameters,
|
||||
const TypeVector& term_argument_types)
|
||||
const std::vector<base::Optional<const Type*>>& term_argument_types)
|
||||
: num_explicit_(explicit_type_arguments.size()),
|
||||
type_parameter_from_name_(type_parameters.size()),
|
||||
inferred_(type_parameters.size()) {
|
||||
@ -20,8 +20,8 @@ TypeArgumentInference::TypeArgumentInference(
|
||||
Fail("more explicit type arguments than expected");
|
||||
return;
|
||||
}
|
||||
if (term_parameters.size() != term_argument_types.size()) {
|
||||
Fail("number of term parameters does not match number of term arguments!");
|
||||
if (term_argument_types.size() > term_parameters.size()) {
|
||||
Fail("more arguments than expected");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -32,8 +32,9 @@ TypeArgumentInference::TypeArgumentInference(
|
||||
inferred_[i] = {explicit_type_arguments[i]};
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < term_parameters.size(); i++) {
|
||||
Match(term_parameters[i], term_argument_types[i]);
|
||||
for (size_t i = 0; i < term_argument_types.size(); i++) {
|
||||
if (term_argument_types[i])
|
||||
Match(term_parameters[i], *term_argument_types[i]);
|
||||
if (HasFailed()) return;
|
||||
}
|
||||
|
||||
|
@ -55,10 +55,11 @@ namespace torque {
|
||||
// should be instantiated in the appropriate scope.
|
||||
class TypeArgumentInference {
|
||||
public:
|
||||
TypeArgumentInference(const GenericParameters& type_parameters,
|
||||
TypeArgumentInference(
|
||||
const GenericParameters& type_parameters,
|
||||
const TypeVector& explicit_type_arguments,
|
||||
const std::vector<TypeExpression*>& term_parameters,
|
||||
const TypeVector& term_argument_types);
|
||||
const std::vector<base::Optional<const Type*>>& term_argument_types);
|
||||
|
||||
bool HasFailed() const { return failure_reason_.has_value(); }
|
||||
const std::string& GetFailureReason() { return *failure_reason_; }
|
||||
|
@ -500,9 +500,10 @@ const Type* TypeVisitor::ComputeTypeForStructExpression(
|
||||
}
|
||||
|
||||
CurrentScope::Scope generic_scope(generic_type->ParentScope());
|
||||
TypeArgumentInference inference(generic_type->generic_parameters(),
|
||||
explicit_type_arguments, term_parameters,
|
||||
term_argument_types);
|
||||
TypeArgumentInference inference(
|
||||
generic_type->generic_parameters(), explicit_type_arguments,
|
||||
term_parameters,
|
||||
TransformVector<base::Optional<const Type*>>(term_argument_types));
|
||||
|
||||
if (inference.HasFailed()) {
|
||||
ReportError("failed to infer type arguments for struct ", basic->name,
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef V8_TORQUE_UTILS_H_
|
||||
#define V8_TORQUE_UTILS_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
#include <queue>
|
||||
#include <streambuf>
|
||||
@ -523,6 +524,17 @@ class Worklist {
|
||||
std::unordered_set<T> contained_;
|
||||
};
|
||||
|
||||
template <class T, class U, class F>
|
||||
std::vector<T> TransformVector(const std::vector<U>& v, F f) {
|
||||
std::vector<T> result;
|
||||
std::transform(v.begin(), v.end(), std::back_inserter(result), f);
|
||||
return result;
|
||||
}
|
||||
template <class T, class U>
|
||||
std::vector<T> TransformVector(const std::vector<U>& v) {
|
||||
return TransformVector<T>(v, [](const U& x) -> T { return x; });
|
||||
}
|
||||
|
||||
} // namespace torque
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -915,6 +915,48 @@ TEST(Torque, UnusedImplicit) {
|
||||
"Test6(Smi): Smi\n Test6(implicit Smi)(Smi): Smi"));
|
||||
}
|
||||
|
||||
TEST(Torque, ImplicitTemplateParameterInference) {
|
||||
ExpectSuccessfulCompilation(R"(
|
||||
macro Foo(_x: Map) {}
|
||||
macro Foo(_x: Smi) {}
|
||||
macro GenericMacro<T: type>(implicit x: T)() {
|
||||
Foo(x);
|
||||
}
|
||||
@export
|
||||
macro Test1(implicit x: Smi)() { GenericMacro(); }
|
||||
@export
|
||||
macro Test2(implicit x: Map)() { GenericMacro(); }
|
||||
)");
|
||||
|
||||
ExpectFailingCompilation(
|
||||
R"(
|
||||
// Wrap in namespace to avoid redeclaration error.
|
||||
namespace foo {
|
||||
macro Foo(implicit x: Map)() {}
|
||||
}
|
||||
macro Foo(implicit x: Smi)() {}
|
||||
namespace foo{
|
||||
@export
|
||||
macro Test(implicit x: Smi)() { Foo(); }
|
||||
}
|
||||
)",
|
||||
HasSubstr("ambiguous callable"));
|
||||
|
||||
ExpectFailingCompilation(
|
||||
R"(
|
||||
// Wrap in namespace to avoid redeclaration error.
|
||||
namespace foo {
|
||||
macro Foo(implicit x: Map)() {}
|
||||
}
|
||||
macro Foo(implicit x: Smi)() {}
|
||||
namespace foo{
|
||||
@export
|
||||
macro Test(implicit x: Map)() { Foo(); }
|
||||
}
|
||||
)",
|
||||
HasSubstr("ambiguous callable"));
|
||||
}
|
||||
|
||||
} // namespace torque
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user