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