Commit 50d5c2bb authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[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: 's avatarSeth Brenith <seth.brenith@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#69177}
parent 09db7cf9
......@@ -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,
const TypeVector& explicit_type_arguments,
const std::vector<TypeExpression*>& term_parameters,
const TypeVector& term_argument_types);
TypeArgumentInference(
const GenericParameters& type_parameters,
const TypeVector& explicit_type_arguments,
const std::vector<TypeExpression*>& term_parameters,
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
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