Commit a3dbc638 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] add bounded quantification to generics

This has two advantages:
- It improves error messages by avoiding wrong template instantiations.
- More flexible overloads by disabling generics for overload resolution
  when their constraints are violated.


Bug: v8:7793
Change-Id: I7d2b8ef736988e8de16d25a4a4b16b49e27c6a11
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1890097Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64676}
parent 04f07852
......@@ -11,7 +11,7 @@ namespace array {
ArrayBuiltinsAssembler::CallJSArrayArrayJoinConcatToSequentialString(
FixedArray, intptr, String, String): String;
transitioning builtin LoadJoinElement<T: type>(
transitioning builtin LoadJoinElement<T : type extends ElementsKind>(
context: Context, receiver: JSReceiver, k: uintptr): JSAny {
return GetProperty(receiver, Convert<Number>(k));
}
......@@ -50,7 +50,7 @@ namespace array {
return AllocateHeapNumberWithValue(element);
}
builtin LoadJoinTypedElement<T: type>(
builtin LoadJoinTypedElement<T : type extends ElementsKind>(
context: Context, receiver: JSReceiver, k: uintptr): JSAny {
const typedArray: JSTypedArray = UnsafeCast<JSTypedArray>(receiver);
assert(!IsDetachedBuffer(typedArray.buffer));
......
......@@ -3,7 +3,7 @@
// found in the LICENSE file.
namespace array {
macro LoadWithHoleCheck<Elements: type>(
macro LoadWithHoleCheck<Elements : type extends FixedArrayBase>(
elements: FixedArrayBase, index: Smi): JSAny
labels IfHole;
......@@ -25,7 +25,7 @@ namespace array {
return AllocateHeapNumberWithValue(element);
}
macro FastArrayLastIndexOf<Elements: type>(
macro FastArrayLastIndexOf<Elements : type extends FixedArrayBase>(
context: Context, array: JSArray, from: Smi, searchElement: JSAny): Smi {
const elements: FixedArrayBase = array.elements;
let k: Smi = from;
......
......@@ -3,7 +3,7 @@
// found in the LICENSE file.
namespace array {
macro LoadElement<ElementsAccessor: type, T: type>(
macro LoadElement<ElementsAccessor : type extends ElementsKind, T: type>(
elements: FixedArrayBase, index: Smi): T;
LoadElement<array::FastPackedSmiElements, Smi>(implicit context: Context)(
......@@ -28,7 +28,7 @@ namespace array {
otherwise unreachable;
}
macro StoreElement<ElementsAccessor: type, T: type>(
macro StoreElement<ElementsAccessor : type extends ElementsKind, T: type>(
implicit context:
Context)(elements: FixedArrayBase, index: Smi, value: T);
......
......@@ -7,7 +7,7 @@ namespace array {
// FixedArrayType. Most of this behavior is outsourced to ExtractFixedArray(),
// but the special case of wanting to have a FixedDoubleArray when given a
// zero-length input FixedArray is handled here.
macro Extract<FixedArrayType: type>(
macro Extract<FixedArrayType : type extends FixedArrayBase>(
elements: FixedArrayBase, first: Smi, count: Smi,
capacity: Smi): FixedArrayType;
......@@ -28,7 +28,7 @@ namespace array {
ExtractFixedArray(elements, first, count, capacity));
}
macro DoMoveElements<FixedArrayType: type>(
macro DoMoveElements<FixedArrayType : type extends FixedArrayBase>(
elements: FixedArrayType, dstIndex: Smi, srcIndex: Smi,
count: Smi): void {
TorqueMoveElements(
......@@ -36,14 +36,14 @@ namespace array {
Convert<intptr>(count));
}
macro StoreHoles<FixedArrayType: type>(
macro StoreHoles<FixedArrayType : type extends FixedArrayBase>(
elements: FixedArrayType, holeStartIndex: Smi, holeEndIndex: Smi): void {
for (let i: Smi = holeStartIndex; i < holeEndIndex; i++) {
array::StoreArrayHole(elements, i);
}
}
macro DoCopyElements<FixedArrayType: type>(
macro DoCopyElements<FixedArrayType : type extends FixedArrayBase>(
dstElements: FixedArrayType, dstIndex: Smi, srcElements: FixedArrayType,
srcIndex: Smi, count: Smi): void {
TorqueCopyElements(
......@@ -51,8 +51,9 @@ namespace array {
Convert<intptr>(srcIndex), Convert<intptr>(count));
}
macro FastSplice<FixedArrayType: type, ElementType: type>(implicit context:
Context)(
macro
FastSplice<FixedArrayType : type extends FixedArrayBase, ElementType: type>(
implicit context: Context)(
args: Arguments, a: JSArray, length: Smi, newLength: Smi,
actualStart: Smi, insertCount: Smi, actualDeleteCount: Smi): void {
// Make sure elements are writable.
......
......@@ -8,13 +8,13 @@ namespace array {
// Naming convention from elements.cc. We have a similar intent but implement
// fastpaths using generics instead of using a class hierarchy for elements
// kinds specific implementations.
type GenericElementsAccessor;
type FastPackedSmiElements;
type FastPackedObjectElements;
type FastPackedDoubleElements;
type FastSmiOrObjectElements;
type FastDoubleElements;
type DictionaryElements;
type GenericElementsAccessor extends ElementsKind;
type FastPackedSmiElements extends ElementsKind;
type FastPackedObjectElements extends ElementsKind;
type FastPackedDoubleElements extends ElementsKind;
type FastSmiOrObjectElements extends ElementsKind;
type FastDoubleElements extends ElementsKind;
type DictionaryElements extends ElementsKind;
macro EnsureWriteableFastElements(implicit context: Context)(array: JSArray) {
assert(IsFastElementsKind(array.map.elements_kind));
......
......@@ -342,8 +342,9 @@ extern class DescriptorArray extends HeapObject {
// These intrinsics should never be called from Torque code. They're used
// internally by the 'new' operator and only declared here because it's simpler
// than building the definition from C++.
intrinsic %GetAllocationBaseSize<Class: type>(map: Map): intptr;
intrinsic %Allocate<Class: type>(size: intptr): Class;
intrinsic %GetAllocationBaseSize<Class : type extends HeapObject>(map: Map):
intptr;
intrinsic %Allocate<Class : type extends HeapObject>(size: intptr): Class;
intrinsic %GetStructMap(instanceKind: constexpr InstanceType): Map;
intrinsic %AddIndexedFieldSizeToObjectSize<T: type>(
......@@ -2258,7 +2259,7 @@ extern macro HeapObjectToRegExpMatchInfo(HeapObject):
extern macro TaggedToNumber(Object): Number
labels CastError;
macro Cast<A: type>(implicit context: Context)(o: Object): A
macro Cast<A : type extends Object>(implicit context: Context)(o: Object): A
labels CastError {
return Cast<A>(TaggedToHeapObject(o) otherwise CastError)
otherwise CastError;
......@@ -2419,7 +2420,7 @@ Cast<Number|TheHole>(o: Object): Number|TheHole labels CastError {
}
}
macro Cast<A: type>(o: HeapObject): A
macro Cast<A : type extends HeapObject>(o: HeapObject): A
labels CastError;
Cast<HeapObject>(o: HeapObject): HeapObject
......@@ -2551,7 +2552,7 @@ Cast<Symbol>(o: HeapObject): Symbol
goto CastError;
}
macro Cast<T: type>(o: Symbol): T labels CastError;
macro Cast<T : type extends Symbol>(o: Symbol): T labels CastError;
Cast<PublicSymbol>(o: Symbol): PublicSymbol labels CastError {
if (IsPrivateSymbol(o)) goto CastError;
return %RawDownCast<PublicSymbol>(o);
......@@ -3079,12 +3080,14 @@ Convert<PromiseState, int32>(s: int32): PromiseState {
return %RawDownCast<PromiseState>(s);
}
macro Is<A: type, B: type>(implicit context: Context)(o: B): bool {
macro Is<A : type extends Object, B : type extends Object>(
implicit context: Context)(o: B): bool {
Cast<A>(o) otherwise return false;
return true;
}
macro UnsafeCast<A: type>(implicit context: Context)(o: Object): A {
macro UnsafeCast<A : type extends Object>(implicit context: Context)(o: Object):
A {
assert(Is<A>(o));
return %RawDownCast<A>(o);
}
......@@ -3349,7 +3352,8 @@ macro TorqueCopyElements(
count);
}
macro LoadElementNoHole<T: type>(a: JSArray, index: Smi): JSAny
macro LoadElementNoHole<T : type extends FixedArrayBase>(
a: JSArray, index: Smi): JSAny
labels IfHole;
LoadElementNoHole<FixedArray>(implicit context: Context)(
......
......@@ -8,17 +8,17 @@ namespace typed_array {
// Naming convention from elements.cc. We have a similar intent but implement
// fastpaths using generics instead of using a class hierarchy for elements
// kinds specific implementations.
type Uint8Elements;
type Int8Elements;
type Uint16Elements;
type Int16Elements;
type Uint32Elements;
type Int32Elements;
type Float32Elements;
type Float64Elements;
type Uint8ClampedElements;
type BigUint64Elements;
type BigInt64Elements;
type Uint8Elements extends ElementsKind;
type Int8Elements extends ElementsKind;
type Uint16Elements extends ElementsKind;
type Int16Elements extends ElementsKind;
type Uint32Elements extends ElementsKind;
type Int32Elements extends ElementsKind;
type Float32Elements extends ElementsKind;
type Float64Elements extends ElementsKind;
type Uint8ClampedElements extends ElementsKind;
type BigUint64Elements extends ElementsKind;
type BigInt64Elements extends ElementsKind;
@export
struct TypedArrayElementsInfo {
......@@ -165,7 +165,8 @@ namespace typed_array {
}
}
macro KindForArrayType<T: type>(): constexpr ElementsKind;
macro KindForArrayType<T : type extends ElementsKind>():
constexpr ElementsKind;
KindForArrayType<Uint8Elements>(): constexpr ElementsKind {
return UINT8_ELEMENTS;
}
......@@ -200,13 +201,13 @@ namespace typed_array {
return BIGINT64_ELEMENTS;
}
builtin LoadFixedElement<T: type>(
builtin LoadFixedElement<T : type extends ElementsKind>(
_context: Context, array: JSTypedArray, index: uintptr): JSAny {
return LoadFixedTypedArrayElementAsTagged(
array.data_ptr, index, KindForArrayType<T>());
}
builtin StoreFixedElement<T: type>(
builtin StoreFixedElement<T : type extends ElementsKind>(
context: Context, typedArray: JSTypedArray, index: uintptr,
value: JSAny): JSAny {
typed_array::StoreJSTypedArrayElementFromTagged(
......
......@@ -1018,6 +1018,13 @@ struct ConstDeclaration : Declaration {
Expression* expression;
};
struct GenericParameter {
Identifier* name;
base::Optional<TypeExpression*> constraint;
};
using GenericParameters = std::vector<GenericParameter>;
// The AST re-shuffles generics from the concrete syntax:
// Instead of the generic parameters being part of a normal declaration,
// a declaration with generic parameters gets wrapped in a generic declaration,
......@@ -1027,26 +1034,26 @@ struct ConstDeclaration : Declaration {
struct GenericCallableDeclaration : Declaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(GenericCallableDeclaration)
GenericCallableDeclaration(SourcePosition pos,
std::vector<Identifier*> generic_parameters,
GenericParameters generic_parameters,
CallableDeclaration* declaration)
: Declaration(kKind, pos),
generic_parameters(std::move(generic_parameters)),
declaration(declaration) {}
std::vector<Identifier*> generic_parameters;
GenericParameters generic_parameters;
CallableDeclaration* declaration;
};
struct GenericTypeDeclaration : Declaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(GenericTypeDeclaration)
GenericTypeDeclaration(SourcePosition pos,
std::vector<Identifier*> generic_parameters,
GenericParameters generic_parameters,
TypeDeclaration* declaration)
: Declaration(kKind, pos),
generic_parameters(std::move(generic_parameters)),
declaration(declaration) {}
std::vector<Identifier*> generic_parameters;
GenericParameters generic_parameters;
TypeDeclaration* declaration;
};
......
......@@ -58,14 +58,49 @@ std::ostream& operator<<(std::ostream& os, const RuntimeFunction& b) {
std::ostream& operator<<(std::ostream& os, const GenericCallable& g) {
os << "generic " << g.name() << "<";
PrintCommaSeparatedList(
os, g.generic_parameters(),
[](const Identifier* identifier) { return identifier->value; });
PrintCommaSeparatedList(os, g.generic_parameters(),
[](const GenericParameter& identifier) {
return identifier.name->value;
});
os << ">";
return os;
}
base::Optional<std::string> TypeConstraint::IsViolated(const Type* type) const {
if (upper_bound && !type->IsSubtypeOf(*upper_bound)) {
return {ToString("expected ", *type, " to be a subtype of ", *upper_bound)};
}
return base::nullopt;
}
base::Optional<std::string> FindConstraintViolation(
const std::vector<const Type*>& types,
const std::vector<TypeConstraint>& constraints) {
DCHECK_EQ(constraints.size(), types.size());
for (size_t i = 0; i < types.size(); ++i) {
if (auto violation = constraints[i].IsViolated(types[i])) {
return {"Could not instantiate generic, " + *violation + "."};
}
}
return base::nullopt;
}
std::vector<TypeConstraint> ComputeConstraints(
Scope* scope, const GenericParameters& parameters) {
CurrentScope::Scope scope_scope(scope);
std::vector<TypeConstraint> result;
for (const GenericParameter& parameter : parameters) {
if (parameter.constraint) {
result.push_back(TypeConstraint::SubtypeConstraint(
TypeVisitor::ComputeType(*parameter.constraint)));
} else {
result.push_back(TypeConstraint::Unconstrained());
}
}
return result;
}
TypeArgumentInference GenericCallable::InferSpecializationTypes(
const TypeVector& explicit_specialization_types,
const TypeVector& arguments) {
......@@ -79,6 +114,12 @@ TypeArgumentInference GenericCallable::InferSpecializationTypes(
TypeArgumentInference inference(generic_parameters(),
explicit_specialization_types,
explicit_parameters, arguments);
if (!inference.HasFailed()) {
if (auto violation =
FindConstraintViolation(inference.GetResult(), Constraints())) {
inference.Fail(*violation);
}
}
return inference;
}
......
......@@ -446,19 +446,46 @@ class Intrinsic : public Callable {
}
};
template <class T>
class SpecializationMap {
class TypeConstraint {
public:
base::Optional<std::string> IsViolated(const Type*) const;
static TypeConstraint Unconstrained() { return {}; }
static TypeConstraint SubtypeConstraint(const Type* upper_bound) {
TypeConstraint result;
result.upper_bound = {upper_bound};
return result;
}
private:
base::Optional<const Type*> upper_bound;
};
base::Optional<std::string> FindConstraintViolation(
const std::vector<const Type*>& types,
const std::vector<TypeConstraint>& constraints);
std::vector<TypeConstraint> ComputeConstraints(
Scope* scope, const GenericParameters& parameters);
template <class SpecializationType, class DeclarationType>
class GenericDeclarable : public Declarable {
private:
using Map = std::unordered_map<TypeVector, T*, base::hash<TypeVector>>;
using Map = std::unordered_map<TypeVector, SpecializationType,
base::hash<TypeVector>>;
public:
SpecializationMap() {}
void Add(const TypeVector& type_arguments, T* specialization) {
void AddSpecialization(const TypeVector& type_arguments,
SpecializationType specialization) {
DCHECK_EQ(0, specializations_.count(type_arguments));
if (auto violation =
FindConstraintViolation(type_arguments, Constraints())) {
Error(*violation).Throw();
}
specializations_[type_arguments] = specialization;
}
base::Optional<T*> Get(const TypeVector& type_arguments) const {
base::Optional<SpecializationType> GetSpecialization(
const TypeVector& type_arguments) const {
auto it = specializations_.find(type_arguments);
if (it != specializations_.end()) return it->second;
return base::nullopt;
......@@ -468,23 +495,39 @@ class SpecializationMap {
iterator begin() const { return specializations_.begin(); }
iterator end() const { return specializations_.end(); }
const std::string& name() const { return name_; }
auto declaration() const { return generic_declaration_->declaration; }
const GenericParameters& generic_parameters() const {
return generic_declaration_->generic_parameters;
}
const std::vector<TypeConstraint>& Constraints() {
if (!constraints_)
constraints_ = {ComputeConstraints(ParentScope(), generic_parameters())};
return *constraints_;
}
protected:
GenericDeclarable(Declarable::Kind kind, const std::string& name,
DeclarationType generic_declaration)
: Declarable(kind),
name_(name),
generic_declaration_(generic_declaration) {
DCHECK(!generic_declaration->generic_parameters.empty());
}
private:
std::string name_;
DeclarationType generic_declaration_;
Map specializations_;
base::Optional<std::vector<TypeConstraint>> constraints_;
};
class GenericCallable : public Declarable {
class GenericCallable
: public GenericDeclarable<Callable*, GenericCallableDeclaration*> {
public:
DECLARE_DECLARABLE_BOILERPLATE(GenericCallable, generic_callable)
const std::string& name() const { return name_; }
CallableDeclaration* declaration() const {
return generic_declaration_->declaration;
}
const std::vector<Identifier*> generic_parameters() const {
return generic_declaration_->generic_parameters;
}
SpecializationMap<Callable>& specializations() { return specializations_; }
base::Optional<Statement*> CallableBody();
TypeArgumentInference InferSpecializationTypes(
......@@ -495,42 +538,21 @@ class GenericCallable : public Declarable {
friend class Declarations;
GenericCallable(const std::string& name,
GenericCallableDeclaration* generic_declaration)
: Declarable(Declarable::kGenericCallable),
name_(name),
generic_declaration_(generic_declaration) {
DCHECK(!generic_declaration->generic_parameters.empty());
}
std::string name_;
GenericCallableDeclaration* generic_declaration_;
SpecializationMap<Callable> specializations_;
: GenericDeclarable<Callable*, GenericCallableDeclaration*>(
Declarable::kGenericCallable, name, generic_declaration) {}
};
class GenericType : public Declarable {
class GenericType
: public GenericDeclarable<const Type*, GenericTypeDeclaration*> {
public:
DECLARE_DECLARABLE_BOILERPLATE(GenericType, generic_type)
const std::string& name() const { return name_; }
TypeDeclaration* declaration() const {
return generic_declaration_->declaration;
}
const std::vector<Identifier*>& generic_parameters() const {
return generic_declaration_->generic_parameters;
}
SpecializationMap<const Type>& specializations() { return specializations_; }
private:
friend class Declarations;
GenericType(const std::string& name,
GenericTypeDeclaration* generic_declaration)
: Declarable(Declarable::kGenericType),
name_(name),
generic_declaration_(generic_declaration) {
DCHECK(!generic_declaration->generic_parameters.empty());
}
std::string name_;
GenericTypeDeclaration* generic_declaration_;
SpecializationMap<const Type> specializations_;
: GenericDeclarable<const Type*, GenericTypeDeclaration*>(
Declarable::kGenericType, name, generic_declaration) {}
};
class TypeAlias : public Declarable {
......
......@@ -6,6 +6,7 @@
#include "src/torque/ast.h"
#include "src/torque/server-data.h"
#include "src/torque/type-inference.h"
#include "src/torque/type-visitor.h"
namespace v8 {
......@@ -182,6 +183,12 @@ void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
GenericCallable* matching_generic = nullptr;
Signature signature_with_types = TypeVisitor::MakeSignature(decl);
for (GenericCallable* generic : generic_list) {
// 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;
Signature generic_signature_with_types =
MakeSpecializedSignature(SpecializationKey<GenericCallable>{
generic, TypeVisitor::ComputeTypeVector(decl->generic_parameters)});
......@@ -261,7 +268,7 @@ void DeclarationVisitor::DeclareSpecializedTypes(
}
for (auto type : key.specialized_types) {
Identifier* generic_type_name = key.generic->generic_parameters()[i++];
Identifier* generic_type_name = key.generic->generic_parameters()[i++].name;
TypeAlias* alias = Declarations::DeclareType(generic_type_name, type);
alias->SetIsUserDefined(false);
}
......@@ -312,7 +319,7 @@ Callable* DeclarationVisitor::Specialize(
<< std::to_string(generic_parameter_count) << ")";
ReportError(stream.str());
}
if (key.generic->specializations().Get(key.specialized_types)) {
if (key.generic->GetSpecialization(key.specialized_types)) {
ReportError("cannot redeclare specialization of ", key.generic->name(),
" with types <", key.specialized_types, ">");
}
......@@ -347,7 +354,7 @@ Callable* DeclarationVisitor::Specialize(
CreateBuiltin(builtin, GlobalContext::MakeUniqueName(generated_name),
readable_name.str(), type_signature, *body);
}
key.generic->specializations().Add(key.specialized_types, callable);
key.generic->AddSpecialization(key.specialized_types, callable);
return callable;
}
......
......@@ -84,6 +84,8 @@ enum class ParseResultHolderBase::TypeId {
kStdVectorOfTypeswitchCase,
kStdVectorOfIdentifierPtr,
kOptionalClassBody,
kGenericParameter,
kGenericParameters,
kJsonValue,
kJsonMember,
......
......@@ -1538,7 +1538,7 @@ void FailCallableLookup(
const TypeVector& parameter_types,
const std::vector<Binding<LocalLabel>*>& labels,
const std::vector<Signature>& candidates,
const std::vector<std::tuple<GenericCallable*, const char*>>
const std::vector<std::pair<GenericCallable*, std::string>>
inapplicable_generics) {
std::stringstream stream;
stream << "\n" << reason << ": \n " << name << "(" << parameter_types << ")";
......@@ -1556,9 +1556,8 @@ void FailCallableLookup(
if (inapplicable_generics.size() != 0) {
stream << "\nfailed to instantiate all of these generic declarations:";
for (auto& failure : inapplicable_generics) {
GenericCallable* generic;
const char* reason;
std::tie(generic, reason) = failure;
GenericCallable* generic = failure.first;
const std::string& reason = failure.second;
stream << "\n " << generic->name() << " defined at "
<< generic->Position() << ":\n " << reason << "\n";
}
......@@ -1569,7 +1568,7 @@ void FailCallableLookup(
Callable* GetOrCreateSpecialization(
const SpecializationKey<GenericCallable>& key) {
if (base::Optional<Callable*> specialization =
key.generic->specializations().Get(key.specialized_types)) {
key.generic->GetSpecialization(key.specialized_types)) {
return *specialization;
}
return DeclarationVisitor::SpecializeImplicit(key);
......@@ -1623,14 +1622,14 @@ Callable* ImplementationVisitor::LookupCallable(
std::vector<Declarable*> overloads;
std::vector<Signature> overload_signatures;
std::vector<std::tuple<GenericCallable*, const char*>> inapplicable_generics;
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);
if (inference.HasFailed()) {
inapplicable_generics.push_back(
std::make_tuple(generic, inference.GetFailureReason()));
std::make_pair(generic, inference.GetFailureReason()));
continue;
}
overloads.push_back(generic);
......
......@@ -21,7 +21,6 @@ namespace torque {
DEFINE_CONTEXTUAL_VARIABLE(CurrentAst)
using TypeList = std::vector<TypeExpression*>;
using GenericParameters = std::vector<Identifier*>;
struct ExpressionWithSource {
Expression* expression;
......@@ -218,6 +217,14 @@ template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<base::Optional<ClassBody*>>::id =
ParseResultTypeId::kOptionalClassBody;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<GenericParameter>::id =
ParseResultTypeId::kGenericParameter;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<GenericParameters>::id =
ParseResultTypeId::kGenericParameters;
namespace {
......@@ -245,8 +252,9 @@ void NamingConventionError(const std::string& type, const Identifier* name,
void LintGenericParameters(const GenericParameters& parameters) {
for (auto parameter : parameters) {
if (!IsUpperCamelCase(parameter->value)) {
NamingConventionError("Generic parameter", parameter, "UpperCamelCase");
if (!IsUpperCamelCase(parameter.name->value)) {
NamingConventionError("Generic parameter", parameter.name,
"UpperCamelCase");
}
}
}
......@@ -1012,6 +1020,13 @@ base::Optional<ParseResult> MakeUnionTypeExpression(
return ParseResult{result};
}
base::Optional<ParseResult> MakeGenericParameter(
ParseResultIterator* child_results) {
auto name = child_results->NextAs<Identifier*>();
auto constraint = child_results->NextAs<base::Optional<TypeExpression*>>();
return ParseResult{GenericParameter{name, constraint}};
}
base::Optional<ParseResult> MakeExpressionStatement(
ParseResultIterator* child_results) {
auto expression = child_results->NextAs<Expression*>();
......@@ -1662,18 +1677,22 @@ struct TorqueGrammar : Grammar {
Symbol type = {Rule({&simpleType}), Rule({&type, Token("|"), &simpleType},
MakeUnionTypeExpression)};
// Result: GenericParameter
Symbol genericParameter = {
Rule({&name, Token(":"), Token("type"),
Optional<TypeExpression*>(Sequence({Token("extends"), &type}))},
MakeGenericParameter)};
// Result: GenericParameters
Symbol genericParameters = {
Rule({Token("<"),
List<Identifier*>(Sequence({&name, Token(":"), Token("type")}),
Token(",")),
Rule({Token("<"), List<GenericParameter>(&genericParameter, Token(",")),
Token(">")})};
// Result: TypeList
Symbol genericSpecializationTypeList = {
Rule({Token("<"), typeList, Token(">")})};
// Result: base::Optional<TypeList>
// Result: base::Optional<GenericParameters>
Symbol* optionalGenericParameters = Optional<TypeList>(&genericParameters);
Symbol implicitParameterList{
......
......@@ -9,7 +9,7 @@ namespace internal {
namespace torque {
TypeArgumentInference::TypeArgumentInference(
const NameVector& type_parameters,
const GenericParameters& type_parameters,
const TypeVector& explicit_type_arguments,
const std::vector<TypeExpression*>& term_parameters,
const TypeVector& term_argument_types)
......@@ -26,7 +26,7 @@ TypeArgumentInference::TypeArgumentInference(
}
for (size_t i = 0; i < type_parameters.size(); i++) {
type_parameter_from_name_[type_parameters[i]->value] = i;
type_parameter_from_name_[type_parameters[i].name->value] = i;
}
for (size_t i = 0; i < num_explicit_; i++) {
inferred_[i] = {explicit_type_arguments[i]};
......
......@@ -55,25 +55,24 @@ namespace torque {
// should be instantiated in the appropriate scope.
class TypeArgumentInference {
public:
TypeArgumentInference(const NameVector& type_parameters,
TypeArgumentInference(const GenericParameters& type_parameters,
const TypeVector& explicit_type_arguments,
const std::vector<TypeExpression*>& term_parameters,
const TypeVector& term_argument_types);
bool HasFailed() const { return failure_reason_.has_value(); }
const char* GetFailureReason() { return *failure_reason_; }
const std::string& GetFailureReason() { return *failure_reason_; }
TypeVector GetResult() const;
void Fail(std::string reason) { failure_reason_ = {reason}; }
private:
void Fail(const char* reason) { failure_reason_ = {reason}; }
void Match(TypeExpression* parameter, const Type* argument_type);
void MatchGeneric(BasicTypeExpression* parameter, const Type* argument_type);
size_t num_explicit_;
std::unordered_map<std::string, size_t> type_parameter_from_name_;
std::vector<base::Optional<const Type*>> inferred_;
base::Optional<const char*> failure_reason_;
base::Optional<std::string> failure_reason_;
};
} // namespace torque
......
......@@ -28,20 +28,19 @@ void TypeOracle::FinalizeAggregateTypes() {
const Type* TypeOracle::GetGenericTypeInstance(GenericType* generic_type,
TypeVector arg_types) {
auto& params = generic_type->generic_parameters();
auto& specializations = generic_type->specializations();
if (params.size() != arg_types.size()) {
ReportError("Generic struct takes ", params.size(), " parameters, but ",
arg_types.size(), " were given");
}
if (auto specialization = specializations.Get(arg_types)) {
if (auto specialization = generic_type->GetSpecialization(arg_types)) {
return *specialization;
} else {
CurrentScope::Scope generic_scope(generic_type->ParentScope());
auto type = TypeVisitor::ComputeType(generic_type->declaration(),
{{generic_type, arg_types}});
specializations.Add(arg_types, type);
generic_type->AddSpecialization(arg_types, type);
return type;
}
}
......
......@@ -253,7 +253,7 @@ class TypeOracle : public ContextualClass<TypeOracle> {
for (GenericCallable* from_constexpr :
Declarations::LookupGeneric(kFromConstexprMacroName)) {
if (base::Optional<const Callable*> specialization =
from_constexpr->specializations().Get({to, from})) {
from_constexpr->GetSpecialization({to, from})) {
if ((*specialization)->signature().GetExplicitTypes() ==
TypeVector{from}) {
return true;
......
......@@ -27,7 +27,8 @@ const Type* TypeVisitor::ComputeType(TypeDeclaration* decl,
auto& params = specialized_from->generic->generic_parameters();
auto arg_types_iterator = specialized_from->specialized_types.begin();
for (auto param : params) {
TypeAlias* alias = Declarations::DeclareType(param, *arg_types_iterator);
TypeAlias* alias =
Declarations::DeclareType(param.name, *arg_types_iterator);
alias->SetIsUserDefined(false);
arg_types_iterator++;
}
......
......@@ -38,6 +38,13 @@ struct TorqueMessage {
DECLARE_CONTEXTUAL_VARIABLE(TorqueMessages, std::vector<TorqueMessage>);
template <class... Args>
std::string ToString(Args&&... args) {
std::stringstream stream;
USE((stream << std::forward<Args>(args))...);
return stream.str();
}
class V8_EXPORT_PRIVATE MessageBuilder {
public:
MessageBuilder(const std::string& message, TorqueMessage::Kind kind);
......@@ -67,9 +74,7 @@ struct TorqueAbortCompilation {};
template <class... Args>
static MessageBuilder Message(TorqueMessage::Kind kind, Args&&... args) {
std::stringstream stream;
USE((stream << std::forward<Args>(args))...);
return MessageBuilder(stream.str(), kind);
return MessageBuilder(ToString(std::forward<Args>(args)...), kind);
}
template <class... Args>
......@@ -298,18 +303,6 @@ inline std::ostream& operator<<(std::ostream& os, const Stack<T>& t) {
os << "}";
return os;
}
class ToString {
public:
template <class T>
ToString& operator<<(T&& x) {
s_ << std::forward<T>(x);
return *this;
}
operator std::string() { return s_.str(); }
private:
std::stringstream s_;
};
static const char* const kBaseNamespaceName = "base";
static const char* const kTestNamespaceName = "test";
......
......@@ -96,8 +96,8 @@ namespace array {
numberOfUndefined: Smi;
}
type FastSmiElements;
type FastObjectElements;
type FastSmiElements extends ElementsKind;
type FastObjectElements extends ElementsKind;
// With the pre-processing step in Torque, the exact number of elements
// to sort is unknown at the time the sort state is created.
......@@ -234,7 +234,7 @@ namespace array {
// copied values from the prototype chain to the receiver if they were visible
// through a hole.
transitioning builtin Load<ElementsAccessor: type>(
transitioning builtin Load<ElementsAccessor: type extends ElementsKind>(
context: Context, sortState: SortState, index: Smi): JSAny|TheHole {
const receiver = sortState.receiver;
if (!HasProperty_Inline(receiver, index)) return TheHole;
......@@ -268,7 +268,7 @@ namespace array {
}
}
transitioning builtin Store<ElementsAccessor: type>(
transitioning builtin Store<ElementsAccessor: type extends ElementsKind>(
context: Context, sortState: SortState, index: Smi, value: JSAny): Smi {
SetProperty(sortState.receiver, index, value);
return kSuccess;
......@@ -301,7 +301,7 @@ namespace array {
return kSuccess;
}
transitioning builtin Delete<ElementsAccessor: type>(
transitioning builtin Delete<ElementsAccessor: type extends ElementsKind>(
context: Context, sortState: SortState, index: Smi): Smi {
const receiver = sortState.receiver;
DeleteProperty(receiver, index, kStrict);
......@@ -381,7 +381,7 @@ namespace array {
return v;
}
builtin CanUseSameAccessor<ElementsAccessor: type>(
builtin CanUseSameAccessor<ElementsAccessor: type extends ElementsKind>(
context: Context, receiver: JSReceiver, initialReceiverMap: Map,
initialReceiverLength: Number): Boolean {
if (receiver.map != initialReceiverMap) return False;
......
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