mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:00:09 +00:00
[VM/nnbd] Implement syntactic type equality.
Legacy types are considered equal to their non-nullable variant. Type hash is modified to be consistent with the new definition. Change-Id: If90f7f13cf77e519d5b90b57d9dbf4988f71be13 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/126283 Commit-Queue: Régis Crelier <regis@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
cb94390c63
commit
8894b88467
|
@ -109,7 +109,9 @@ DEFINE_NATIVE_ENTRY(Object_haveSameRuntimeType, 0, 2) {
|
|||
AbstractType::Handle(left.GetType(Heap::kNew));
|
||||
const AbstractType& right_type =
|
||||
AbstractType::Handle(right.GetType(Heap::kNew));
|
||||
return Bool::Get(left_type.raw() == right_type.raw()).raw();
|
||||
return Bool::Get(
|
||||
left_type.IsEquivalent(right_type, /* syntactically = */ true))
|
||||
.raw();
|
||||
}
|
||||
|
||||
if (!cls.IsGeneric()) {
|
||||
|
@ -127,7 +129,7 @@ DEFINE_NATIVE_ENTRY(Object_haveSameRuntimeType, 0, 2) {
|
|||
const intptr_t num_type_params = cls.NumTypeParameters();
|
||||
return Bool::Get(left_type_arguments.IsSubvectorEquivalent(
|
||||
right_type_arguments, num_type_args - num_type_params,
|
||||
num_type_params))
|
||||
num_type_params, /* syntactically = */ true))
|
||||
.raw();
|
||||
}
|
||||
|
||||
|
@ -186,6 +188,16 @@ DEFINE_NATIVE_ENTRY(Type_getHashCode, 0, 1) {
|
|||
return Smi::New(hash_val);
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(Type_equality, 0, 2) {
|
||||
const Type& type = Type::CheckedHandle(zone, arguments->NativeArgAt(0));
|
||||
const Instance& other =
|
||||
Instance::CheckedHandle(zone, arguments->NativeArgAt(1));
|
||||
if (type.raw() == other.raw()) {
|
||||
return Bool::True().raw();
|
||||
}
|
||||
return Bool::Get(type.IsEquivalent(other, /* syntactically = */ true)).raw();
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(Internal_inquireIs64Bit, 0, 0) {
|
||||
#if defined(ARCH_IS_64_BIT)
|
||||
return Bool::True().raw();
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace dart {
|
|||
V(Closure_clone, 1) \
|
||||
V(AbstractType_toString, 1) \
|
||||
V(Type_getHashCode, 1) \
|
||||
V(Type_equality, 2) \
|
||||
V(Identical_comparison, 2) \
|
||||
V(Integer_bitAndFromInteger, 2) \
|
||||
V(Integer_bitOrFromInteger, 2) \
|
||||
|
|
|
@ -378,8 +378,9 @@ void ClassFinalizer::CheckRecursiveType(const Class& cls,
|
|||
if ((pending_type.raw() != type.raw()) && pending_type.IsType() &&
|
||||
(pending_type.type_class() == type_cls.raw())) {
|
||||
pending_arguments = pending_type.arguments();
|
||||
if (!pending_arguments.IsSubvectorEquivalent(arguments, first_type_param,
|
||||
num_type_params) &&
|
||||
if (!pending_arguments.IsSubvectorEquivalent(
|
||||
arguments, first_type_param, num_type_params,
|
||||
/* syntactically = */ true) &&
|
||||
!pending_arguments.IsSubvectorInstantiated(first_type_param,
|
||||
num_type_params)) {
|
||||
const TypeArguments& instantiated_arguments = TypeArguments::Handle(
|
||||
|
@ -394,7 +395,8 @@ void ClassFinalizer::CheckRecursiveType(const Class& cls,
|
|||
Object::null_type_arguments(), kNoneFree, NULL,
|
||||
Heap::kNew));
|
||||
if (!instantiated_pending_arguments.IsSubvectorEquivalent(
|
||||
instantiated_arguments, first_type_param, num_type_params)) {
|
||||
instantiated_arguments, first_type_param, num_type_params,
|
||||
/* syntactically = */ true)) {
|
||||
const String& type_name = String::Handle(zone, type.Name());
|
||||
ReportError(cls, type.token_pos(), "illegal recursive type '%s'",
|
||||
type_name.ToCString());
|
||||
|
|
|
@ -1688,6 +1688,22 @@ void AsmIntrinsifier::Type_getHashCode(Assembler* assembler,
|
|||
__ Bind(normal_ir_body);
|
||||
}
|
||||
|
||||
void AsmIntrinsifier::Type_equality(Assembler* assembler,
|
||||
Label* normal_ir_body) {
|
||||
// TODO(regis): Add more fast cases. See ObjectHaveSameRuntimeType.
|
||||
__ ldr(R0, Address(SP, 0 * target::kWordSize));
|
||||
__ ldr(R1, Address(SP, 1 * target::kWordSize));
|
||||
__ cmp(R0, Operand(R1));
|
||||
__ b(normal_ir_body, NE);
|
||||
|
||||
// Types are strictly equal.
|
||||
__ LoadObject(R0, CastHandle<Object>(TrueObject()));
|
||||
__ Ret();
|
||||
|
||||
// Check if types are syntactically equal.
|
||||
__ Bind(normal_ir_body);
|
||||
}
|
||||
|
||||
void GenerateSubstringMatchesSpecialization(Assembler* assembler,
|
||||
intptr_t receiver_cid,
|
||||
intptr_t other_cid,
|
||||
|
|
|
@ -1758,6 +1758,22 @@ void AsmIntrinsifier::Type_getHashCode(Assembler* assembler,
|
|||
__ Bind(normal_ir_body);
|
||||
}
|
||||
|
||||
void AsmIntrinsifier::Type_equality(Assembler* assembler,
|
||||
Label* normal_ir_body) {
|
||||
// TODO(regis): Add more fast cases. See ObjectHaveSameRuntimeType.
|
||||
__ ldr(R0, Address(SP, 0 * target::kWordSize));
|
||||
__ ldr(R1, Address(SP, 1 * target::kWordSize));
|
||||
__ cmp(R0, Operand(R1));
|
||||
__ b(normal_ir_body, NE);
|
||||
|
||||
// Types are strictly equal.
|
||||
__ LoadObject(R0, CastHandle<Object>(TrueObject()));
|
||||
__ ret();
|
||||
|
||||
// Check if types are syntactically equal.
|
||||
__ Bind(normal_ir_body);
|
||||
}
|
||||
|
||||
void AsmIntrinsifier::Object_getHash(Assembler* assembler,
|
||||
Label* normal_ir_body) {
|
||||
__ ldr(R0, Address(SP, 0 * target::kWordSize));
|
||||
|
|
|
@ -1807,6 +1807,22 @@ void AsmIntrinsifier::Type_getHashCode(Assembler* assembler,
|
|||
// Hash not yet computed.
|
||||
}
|
||||
|
||||
void AsmIntrinsifier::Type_equality(Assembler* assembler,
|
||||
Label* normal_ir_body) {
|
||||
// TODO(regis): Add more fast cases. See ObjectHaveSameRuntimeType.
|
||||
__ movl(EAX, Address(ESP, +1 * target::kWordSize));
|
||||
__ movl(EBX, Address(ESP, +2 * target::kWordSize));
|
||||
__ cmpl(EAX, EBX);
|
||||
__ j(NOT_EQUAL, normal_ir_body, Assembler::kNearJump);
|
||||
|
||||
// Types are strictly equal.
|
||||
__ LoadObject(EAX, CastHandle<Object>(TrueObject()));
|
||||
__ ret();
|
||||
|
||||
// Check if types are syntactically equal.
|
||||
__ Bind(normal_ir_body);
|
||||
}
|
||||
|
||||
// bool _substringMatches(int start, String other)
|
||||
void AsmIntrinsifier::StringBaseSubstringMatches(Assembler* assembler,
|
||||
Label* normal_ir_body) {
|
||||
|
|
|
@ -1723,6 +1723,22 @@ void AsmIntrinsifier::Type_getHashCode(Assembler* assembler,
|
|||
// Hash not yet computed.
|
||||
}
|
||||
|
||||
void AsmIntrinsifier::Type_equality(Assembler* assembler,
|
||||
Label* normal_ir_body) {
|
||||
// TODO(regis): Add more fast cases. See ObjectHaveSameRuntimeType.
|
||||
__ movq(RAX, Address(RSP, +1 * target::kWordSize));
|
||||
__ movq(RCX, Address(RSP, +2 * target::kWordSize));
|
||||
__ cmpq(RAX, RCX);
|
||||
__ j(NOT_EQUAL, normal_ir_body);
|
||||
|
||||
// Types are strictly equal.
|
||||
__ LoadObject(RAX, CastHandle<Object>(TrueObject()));
|
||||
__ ret();
|
||||
|
||||
// Check if types are syntactically equal.
|
||||
__ Bind(normal_ir_body);
|
||||
}
|
||||
|
||||
void AsmIntrinsifier::Object_getHash(Assembler* assembler,
|
||||
Label* normal_ir_body) {
|
||||
__ movq(RAX, Address(RSP, +1 * target::kWordSize)); // Object.
|
||||
|
|
|
@ -387,7 +387,7 @@ bool HierarchyInfo::CanUseSubtypeRangeCheckFor(const AbstractType& type) {
|
|||
// arguments are not "dynamic" but instantiated-to-bounds.
|
||||
const Type& rare_type =
|
||||
Type::Handle(zone, Type::RawCast(type_class.RareType()));
|
||||
if (!rare_type.Equals(type)) {
|
||||
if (!rare_type.IsEquivalent(type, /* syntactically = */ true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -380,7 +380,7 @@ bool SimpleInstanceOfType(const AbstractType& type) {
|
|||
// type arguments, then we can still use the _simpleInstanceOf
|
||||
// implementation (see also runtime/lib/object.cc:Object_SimpleInstanceOf).
|
||||
const auto& rare_type = AbstractType::Handle(type_class.RareType());
|
||||
return rare_type.Equals(type);
|
||||
return rare_type.IsEquivalent(type, /* syntactically = */ true);
|
||||
}
|
||||
|
||||
// Finally a simple class for instance of checking.
|
||||
|
|
|
@ -222,6 +222,7 @@ namespace dart {
|
|||
V(_OneByteString, ==, OneByteString_equality, 0xe1ea0c11) \
|
||||
V(_TwoByteString, ==, TwoByteString_equality, 0xe1ea0c11) \
|
||||
V(_Type, get:hashCode, Type_getHashCode, 0x22a75237) \
|
||||
V(_Type, ==, Type_equality, 0x91ead098) \
|
||||
V(::, _getHash, Object_getHash, 0xb05aa13f) \
|
||||
V(::, _setHash, Object_setHash, 0xcb404dd2) \
|
||||
|
||||
|
|
|
@ -5252,6 +5252,7 @@ RawString* TypeArguments::SubvectorName(intptr_t from_index,
|
|||
bool TypeArguments::IsSubvectorEquivalent(const TypeArguments& other,
|
||||
intptr_t from_index,
|
||||
intptr_t len,
|
||||
bool syntactically,
|
||||
TrailPtr trail) const {
|
||||
if (this->raw() == other.raw()) {
|
||||
return true;
|
||||
|
@ -5269,7 +5270,7 @@ bool TypeArguments::IsSubvectorEquivalent(const TypeArguments& other,
|
|||
type = TypeAt(i);
|
||||
other_type = other.TypeAt(i);
|
||||
// Still unfinalized vectors should not be considered equivalent.
|
||||
if (type.IsNull() || !type.IsEquivalent(other_type, trail)) {
|
||||
if (type.IsNull() || !type.IsEquivalent(other_type, syntactically, trail)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -17202,7 +17203,9 @@ void AbstractType::SetIsBeingFinalized() const {
|
|||
UNREACHABLE();
|
||||
}
|
||||
|
||||
bool AbstractType::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
||||
bool AbstractType::IsEquivalent(const Instance& other,
|
||||
bool syntactically,
|
||||
TrailPtr trail) const {
|
||||
// AbstractType is an abstract class.
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
|
@ -17983,7 +17986,9 @@ RawAbstractType* Type::InstantiateFrom(
|
|||
return instantiated_type.raw();
|
||||
}
|
||||
|
||||
bool Type::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
||||
bool Type::IsEquivalent(const Instance& other,
|
||||
bool syntactically,
|
||||
TrailPtr trail) const {
|
||||
ASSERT(!IsNull());
|
||||
if (raw() == other.raw()) {
|
||||
return true;
|
||||
|
@ -17993,7 +17998,7 @@ bool Type::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
|||
const AbstractType& other_ref_type =
|
||||
AbstractType::Handle(TypeRef::Cast(other).type());
|
||||
ASSERT(!other_ref_type.IsTypeRef());
|
||||
return IsEquivalent(other_ref_type, trail);
|
||||
return IsEquivalent(other_ref_type, syntactically, trail);
|
||||
}
|
||||
if (!other.IsType()) {
|
||||
return false;
|
||||
|
@ -18005,7 +18010,17 @@ bool Type::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
|||
if (type_class_id() != other_type.type_class_id()) {
|
||||
return false;
|
||||
}
|
||||
if (nullability() != other_type.nullability()) {
|
||||
Nullability this_type_nullability = nullability();
|
||||
Nullability other_type_nullability = other_type.nullability();
|
||||
if (syntactically) {
|
||||
if (this_type_nullability == Nullability::kLegacy) {
|
||||
this_type_nullability = Nullability::kNonNullable;
|
||||
}
|
||||
if (other_type_nullability == Nullability::kLegacy) {
|
||||
other_type_nullability = Nullability::kNonNullable;
|
||||
}
|
||||
}
|
||||
if (this_type_nullability != other_type_nullability) {
|
||||
return false;
|
||||
}
|
||||
if (!IsFinalized() || !other_type.IsFinalized()) {
|
||||
|
@ -18038,7 +18053,8 @@ bool Type::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
|||
return false;
|
||||
}
|
||||
} else if (!type_args.IsSubvectorEquivalent(other_type_args, from_index,
|
||||
num_type_params, trail)) {
|
||||
num_type_params,
|
||||
syntactically, trail)) {
|
||||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
|
@ -18054,7 +18070,7 @@ bool Type::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
|||
for (intptr_t i = 0; i < from_index; i++) {
|
||||
type_arg = type_args.TypeAt(i);
|
||||
other_type_arg = other_type_args.TypeAt(i);
|
||||
ASSERT(type_arg.IsEquivalent(other_type_arg, trail));
|
||||
ASSERT(type_arg.IsEquivalent(other_type_arg, syntactically, trail));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -18117,7 +18133,7 @@ bool Type::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
|||
for (intptr_t i = 0; i < num_params; i++) {
|
||||
param_type = sig_fun.ParameterTypeAt(i);
|
||||
other_param_type = other_sig_fun.ParameterTypeAt(i);
|
||||
if (!param_type.Equals(other_param_type)) {
|
||||
if (!param_type.IsEquivalent(other_param_type, syntactically)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -18129,6 +18145,7 @@ bool Type::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
|||
if (sig_fun.ParameterNameAt(i) != other_sig_fun.ParameterNameAt(i)) {
|
||||
return false;
|
||||
}
|
||||
// TODO(regis): Check 'required' annotation.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -18354,7 +18371,13 @@ intptr_t Type::ComputeHash() const {
|
|||
ASSERT(IsFinalized());
|
||||
uint32_t result = 1;
|
||||
result = CombineHashes(result, type_class_id());
|
||||
result = CombineHashes(result, static_cast<uint32_t>(nullability()));
|
||||
// A legacy type should have the same hash as its non-nullable version to be
|
||||
// consistent with the definition of type equality in Dart code.
|
||||
Nullability type_nullability = nullability();
|
||||
if (type_nullability == Nullability::kLegacy) {
|
||||
type_nullability = Nullability::kNonNullable;
|
||||
}
|
||||
result = CombineHashes(result, static_cast<uint32_t>(type_nullability));
|
||||
result = CombineHashes(result, TypeArguments::Handle(arguments()).Hash());
|
||||
if (IsFunctionType()) {
|
||||
const Function& sig_fun = Function::Handle(signature());
|
||||
|
@ -18469,7 +18492,9 @@ bool TypeRef::IsInstantiated(Genericity genericity,
|
|||
ref_type.IsInstantiated(genericity, num_free_fun_type_params, trail);
|
||||
}
|
||||
|
||||
bool TypeRef::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
||||
bool TypeRef::IsEquivalent(const Instance& other,
|
||||
bool syntactically,
|
||||
TrailPtr trail) const {
|
||||
if (raw() == other.raw()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -18480,7 +18505,8 @@ bool TypeRef::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
|||
return true;
|
||||
}
|
||||
const AbstractType& ref_type = AbstractType::Handle(type());
|
||||
return !ref_type.IsNull() && ref_type.IsEquivalent(other, trail);
|
||||
return !ref_type.IsNull() &&
|
||||
ref_type.IsEquivalent(other, syntactically, trail);
|
||||
}
|
||||
|
||||
RawTypeRef* TypeRef::InstantiateFrom(
|
||||
|
@ -18644,7 +18670,9 @@ bool TypeParameter::IsInstantiated(Genericity genericity,
|
|||
return (genericity == kCurrentClass) || (index() >= num_free_fun_type_params);
|
||||
}
|
||||
|
||||
bool TypeParameter::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
||||
bool TypeParameter::IsEquivalent(const Instance& other,
|
||||
bool syntactically,
|
||||
TrailPtr trail) const {
|
||||
if (raw() == other.raw()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -18653,7 +18681,7 @@ bool TypeParameter::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
|||
const AbstractType& other_ref_type =
|
||||
AbstractType::Handle(TypeRef::Cast(other).type());
|
||||
ASSERT(!other_ref_type.IsTypeRef());
|
||||
return IsEquivalent(other_ref_type, trail);
|
||||
return IsEquivalent(other_ref_type, syntactically, trail);
|
||||
}
|
||||
if (!other.IsTypeParameter()) {
|
||||
return false;
|
||||
|
@ -18666,7 +18694,17 @@ bool TypeParameter::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
|||
if (parameterized_function() != other_type_param.parameterized_function()) {
|
||||
return false;
|
||||
}
|
||||
if (nullability() != other_type_param.nullability()) {
|
||||
Nullability this_type_param_nullability = nullability();
|
||||
Nullability other_type_param_nullability = other_type_param.nullability();
|
||||
if (syntactically) {
|
||||
if (this_type_param_nullability == Nullability::kLegacy) {
|
||||
this_type_param_nullability = Nullability::kNonNullable;
|
||||
}
|
||||
if (other_type_param_nullability == Nullability::kLegacy) {
|
||||
other_type_param_nullability = Nullability::kNonNullable;
|
||||
}
|
||||
}
|
||||
if (this_type_param_nullability != other_type_param_nullability) {
|
||||
return false;
|
||||
}
|
||||
if (IsFinalized() == other_type_param.IsFinalized()) {
|
||||
|
@ -18792,7 +18830,13 @@ intptr_t TypeParameter::ComputeHash() const {
|
|||
// No need to include the hash of the bound, since the type parameter is fully
|
||||
// identified by its class and index.
|
||||
result = CombineHashes(result, index());
|
||||
result = CombineHashes(result, static_cast<uint32_t>(nullability()));
|
||||
// A legacy type should have the same hash as its non-nullable version to be
|
||||
// consistent with the definition of type equality in Dart code.
|
||||
Nullability type_param_nullability = nullability();
|
||||
if (type_param_nullability == Nullability::kLegacy) {
|
||||
type_param_nullability = Nullability::kNonNullable;
|
||||
}
|
||||
result = CombineHashes(result, static_cast<uint32_t>(type_param_nullability));
|
||||
result = FinalizeHash(result, kHashBits);
|
||||
SetHash(result);
|
||||
return result;
|
||||
|
|
|
@ -6763,15 +6763,20 @@ class TypeArguments : public Instance {
|
|||
|
||||
// Check if the vectors are equal (they may be null).
|
||||
bool Equals(const TypeArguments& other) const {
|
||||
return IsSubvectorEquivalent(other, 0, IsNull() ? 0 : Length());
|
||||
return IsSubvectorEquivalent(other, 0, IsNull() ? 0 : Length(),
|
||||
/* syntactically = */ false);
|
||||
}
|
||||
|
||||
bool IsEquivalent(const TypeArguments& other, TrailPtr trail = NULL) const {
|
||||
return IsSubvectorEquivalent(other, 0, IsNull() ? 0 : Length(), trail);
|
||||
bool IsEquivalent(const TypeArguments& other,
|
||||
bool syntactically,
|
||||
TrailPtr trail = NULL) const {
|
||||
return IsSubvectorEquivalent(other, 0, IsNull() ? 0 : Length(),
|
||||
syntactically, trail);
|
||||
}
|
||||
bool IsSubvectorEquivalent(const TypeArguments& other,
|
||||
intptr_t from_index,
|
||||
intptr_t len,
|
||||
bool syntactically,
|
||||
TrailPtr trail = NULL) const;
|
||||
|
||||
// Check if the vector is instantiated (it must not be null).
|
||||
|
@ -6943,9 +6948,11 @@ class AbstractType : public Instance {
|
|||
}
|
||||
virtual uint32_t CanonicalizeHash() const { return Hash(); }
|
||||
virtual bool Equals(const Instance& other) const {
|
||||
return IsEquivalent(other);
|
||||
return IsEquivalent(other, /* syntactically = */ false);
|
||||
}
|
||||
virtual bool IsEquivalent(const Instance& other, TrailPtr trail = NULL) const;
|
||||
virtual bool IsEquivalent(const Instance& other,
|
||||
bool syntactically,
|
||||
TrailPtr trail = NULL) const;
|
||||
virtual bool IsRecursive() const;
|
||||
|
||||
// Check if this type represents a function type.
|
||||
|
@ -7179,7 +7186,9 @@ class Type : public AbstractType {
|
|||
virtual bool IsInstantiated(Genericity genericity = kAny,
|
||||
intptr_t num_free_fun_type_params = kAllFree,
|
||||
TrailPtr trail = NULL) const;
|
||||
virtual bool IsEquivalent(const Instance& other, TrailPtr trail = NULL) const;
|
||||
virtual bool IsEquivalent(const Instance& other,
|
||||
bool syntactically,
|
||||
TrailPtr trail = NULL) const;
|
||||
virtual bool IsRecursive() const;
|
||||
// If signature is not null, this type represents a function type. Note that
|
||||
// the signature fully represents the type and type arguments can be ignored.
|
||||
|
@ -7334,7 +7343,9 @@ class TypeRef : public AbstractType {
|
|||
virtual bool IsInstantiated(Genericity genericity = kAny,
|
||||
intptr_t num_free_fun_type_params = kAllFree,
|
||||
TrailPtr trail = NULL) const;
|
||||
virtual bool IsEquivalent(const Instance& other, TrailPtr trail = NULL) const;
|
||||
virtual bool IsEquivalent(const Instance& other,
|
||||
bool syntactically,
|
||||
TrailPtr trail = NULL) const;
|
||||
virtual bool IsRecursive() const { return true; }
|
||||
virtual bool IsFunctionType() const {
|
||||
const AbstractType& ref_type = AbstractType::Handle(type());
|
||||
|
@ -7417,7 +7428,9 @@ class TypeParameter : public AbstractType {
|
|||
virtual bool IsInstantiated(Genericity genericity = kAny,
|
||||
intptr_t num_free_fun_type_params = kAllFree,
|
||||
TrailPtr trail = NULL) const;
|
||||
virtual bool IsEquivalent(const Instance& other, TrailPtr trail = NULL) const;
|
||||
virtual bool IsEquivalent(const Instance& other,
|
||||
bool syntactically,
|
||||
TrailPtr trail = NULL) const;
|
||||
virtual bool IsRecursive() const { return false; }
|
||||
virtual RawAbstractType* InstantiateFrom(
|
||||
NNBDMode mode,
|
||||
|
|
|
@ -95,30 +95,29 @@ const char* TypeTestingStubNamer::AssemblerSafeName(char* cname) {
|
|||
RawCode* TypeTestingStubGenerator::DefaultCodeForType(
|
||||
const AbstractType& type,
|
||||
bool lazy_specialize /* = true */) {
|
||||
if (type.IsTypeRef()) {
|
||||
return StubCode::TypeRefTypeTest().raw();
|
||||
}
|
||||
|
||||
const intptr_t cid = type.type_class_id();
|
||||
// During bootstrapping we have no access to stubs yet, so we'll just return
|
||||
// `null` and patch these later in `Object::FinishInit()`.
|
||||
if (!StubCode::HasBeenInitialized()) {
|
||||
ASSERT(type.IsType());
|
||||
const intptr_t cid = Type::Cast(type).type_class_id();
|
||||
ASSERT(cid == kDynamicCid || cid == kVoidCid | cid == kNeverCid);
|
||||
return Code::null();
|
||||
}
|
||||
|
||||
// TODO(regis): Revisit when type checking mode is not kLegacy anymore.
|
||||
if (type.raw() == Type::ObjectType() || type.raw() == Type::DynamicType() ||
|
||||
type.raw() == Type::VoidType()) {
|
||||
if (cid == kDynamicCid || cid == kVoidCid || cid == kInstanceCid) {
|
||||
return StubCode::TopTypeTypeTest().raw();
|
||||
}
|
||||
|
||||
if (type.raw() == Type::NeverType()) {
|
||||
if (cid == kNeverCid) {
|
||||
// TODO(regis): Revisit.
|
||||
return StubCode::StubCode::DefaultTypeTest().raw();
|
||||
}
|
||||
|
||||
if (type.IsTypeRef()) {
|
||||
return StubCode::TypeRefTypeTest().raw();
|
||||
}
|
||||
|
||||
if (type.IsType() || type.IsTypeParameter()) {
|
||||
const bool should_specialize = !FLAG_precompiled_mode && lazy_specialize;
|
||||
return should_specialize ? StubCode::LazySpecializeTypeTest().raw()
|
||||
|
@ -151,7 +150,8 @@ RawCode* TypeTestingStubGenerator::OptimizedCodeForType(
|
|||
return StubCode::TypeRefTypeTest().raw();
|
||||
}
|
||||
|
||||
if (type.raw() == Type::ObjectType() || type.raw() == Type::DynamicType()) {
|
||||
const intptr_t cid = type.type_class_id();
|
||||
if (cid == kDynamicCid || cid == kVoidCid || cid == kInstanceCid) {
|
||||
return StubCode::TopTypeTypeTest().raw();
|
||||
}
|
||||
|
||||
|
@ -245,11 +245,10 @@ void TypeTestingStubGenerator::BuildOptimizedTypeTestStubFastCases(
|
|||
Register instance_reg,
|
||||
Register class_id_reg) {
|
||||
// These are handled via the TopTypeTypeTestStub!
|
||||
ASSERT(
|
||||
!(type.raw() == Type::ObjectType() || type.raw() == Type::DynamicType()));
|
||||
ASSERT(!(type.IsDynamicType() || type.IsVoidType() || type.IsObjectType()));
|
||||
|
||||
// Fast case for 'int'.
|
||||
if (type.raw() == Type::IntType()) {
|
||||
if (type.IsIntType()) {
|
||||
compiler::Label non_smi_value;
|
||||
__ BranchIfNotSmi(instance_reg, &non_smi_value);
|
||||
__ Ret();
|
||||
|
@ -411,8 +410,8 @@ void TypeTestingStubGenerator::BuildOptimizedTypeArgumentValueCheck(
|
|||
const Register function_type_args_reg,
|
||||
const Register own_type_arg_reg,
|
||||
compiler::Label* check_failed) {
|
||||
if (type_arg.raw() != Type::ObjectType() &&
|
||||
type_arg.raw() != Type::DynamicType()) {
|
||||
const intptr_t cid = type_arg.type_class_id();
|
||||
if (!(cid == kDynamicCid || cid == kVoidCid || cid == kInstanceCid)) {
|
||||
// TODO(kustermann): Even though it should be safe to use TMP here, we
|
||||
// should avoid using TMP outside the assembler. Try to find a free
|
||||
// register to use here!
|
||||
|
|
|
@ -22,6 +22,9 @@ class _Type extends _AbstractType {
|
|||
|
||||
@pragma("vm:exact-result-type", "dart:core#_Smi")
|
||||
int get hashCode native "Type_getHashCode";
|
||||
|
||||
@pragma("vm:exact-result-type", bool)
|
||||
bool operator ==(other) native "Type_equality";
|
||||
}
|
||||
|
||||
// Equivalent of RawTypeRef.
|
||||
|
|
|
@ -22,6 +22,9 @@ class _Type extends _AbstractType {
|
|||
|
||||
@pragma("vm:exact-result-type", "dart:core#_Smi")
|
||||
int get hashCode native "Type_getHashCode";
|
||||
|
||||
@pragma("vm:exact-result-type", bool)
|
||||
bool operator ==(other) native "Type_equality";
|
||||
}
|
||||
|
||||
// Equivalent of RawTypeRef.
|
||||
|
|
|
@ -35,5 +35,5 @@ MINOR 8
|
|||
PATCH 0
|
||||
PRERELEASE 0
|
||||
PRERELEASE_PATCH 0
|
||||
ABI_VERSION 24
|
||||
OLDEST_SUPPORTED_ABI_VERSION 23
|
||||
ABI_VERSION 25
|
||||
OLDEST_SUPPORTED_ABI_VERSION 25
|
||||
|
|
Loading…
Reference in a new issue