Skip to content

Commit 5fd11d3

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm] Cleanup legacy differences between 'is' and 'as' checks
With sound null safety both 'is' and 'as' type checks use subtyping without any extra differences. Replace Instance::IsAssignableTo with IsInstanceOf (which is now the same as RuntimeTypeIsSubtypeOf). Remove Instance::NullIsInstanceOf as it is no longer used. Replace CompileType::IsAssignableTo and IsInstanceOf with IsSubtypeOf. TEST=ci Change-Id: I3a071d114c5f86d990255416b244961d506257a3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/401861 Commit-Queue: Alexander Markov <[email protected]> Reviewed-by: Slava Egorov <[email protected]>
1 parent da257d2 commit 5fd11d3

File tree

10 files changed

+15
-139
lines changed

10 files changed

+15
-139
lines changed

runtime/vm/compiler/backend/compile_type.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,6 @@ class CompileType : public ZoneAllocated {
101101
// Return true if this type is a subtype of the given type.
102102
bool IsSubtypeOf(const AbstractType& other);
103103

104-
// Return true if value of this type is assignable to a location of the
105-
// given type.
106-
bool IsAssignableTo(const AbstractType& other);
107-
108-
// Return true if value of this type always passes 'is' test
109-
// against given type.
110-
bool IsInstanceOf(const AbstractType& other);
111-
112104
// Return the non-nullable version of this type.
113105
CompileType CopyNonNullable() {
114106
if (IsNull()) {
@@ -278,7 +270,7 @@ class CompileType : public ZoneAllocated {
278270

279271
// Returns true if a value of this CompileType can contain a Smi.
280272
// Note that this is not the same as calling
281-
// CompileType::Smi().IsAssignableTo(this) - because this compile type
273+
// CompileType::Smi().IsSubtypeOf(this) - because this compile type
282274
// can be uninstantiated.
283275
bool CanBeSmi();
284276

runtime/vm/compiler/backend/constant_propagator.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ void ConstantPropagator::VisitAssertAssignable(AssertAssignableInstr* instr) {
460460
if (dst_type.IsAbstractType()) {
461461
// We are ignoring the instantiator and instantiator_type_arguments, but
462462
// still monotonic and safe.
463-
if (instr->value()->Type()->IsAssignableTo(AbstractType::Cast(dst_type))) {
463+
if (instr->value()->Type()->IsSubtypeOf(AbstractType::Cast(dst_type))) {
464464
SetValue(instr, value);
465465
return;
466466
}

runtime/vm/compiler/backend/flow_graph_compiler.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2714,7 +2714,6 @@ void FlowGraphCompiler::GenerateInstanceOf(const InstructionSource& source,
27142714
AbstractType::Handle(type.UnwrapFutureOr());
27152715
if (!unwrapped_type.IsTypeParameter() || unwrapped_type.IsNullable()) {
27162716
// Only nullable type parameter remains nullable after instantiation.
2717-
// See NullIsInstanceOf().
27182717
__ CompareObject(TypeTestABI::kInstanceReg, Object::null_object());
27192718
__ BranchIf(EQUAL,
27202719
unwrapped_type.IsNullable() ? &is_instance : &is_not_instance);

runtime/vm/compiler/backend/il.cc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3025,8 +3025,7 @@ Definition* AssertAssignableInstr::Canonicalize(FlowGraph* flow_graph) {
30253025
const auto& abs_type = AbstractType::Cast(dst_type()->BoundConstant());
30263026

30273027
if (abs_type.IsTopTypeForSubtyping() ||
3028-
(FLAG_eliminate_type_checks &&
3029-
value()->Type()->IsAssignableTo(abs_type))) {
3028+
(FLAG_eliminate_type_checks && value()->Type()->IsSubtypeOf(abs_type))) {
30303029
return value()->definition();
30313030
}
30323031
if (abs_type.IsInstantiated()) {
@@ -3111,7 +3110,7 @@ Definition* AssertAssignableInstr::Canonicalize(FlowGraph* flow_graph) {
31113110

31123111
if (new_dst_type.IsTopTypeForSubtyping() ||
31133112
(FLAG_eliminate_type_checks &&
3114-
value()->Type()->IsAssignableTo(new_dst_type))) {
3113+
value()->Type()->IsSubtypeOf(new_dst_type))) {
31153114
return value()->definition();
31163115
}
31173116
}
@@ -5148,7 +5147,7 @@ bool InstanceCallBaseInstr::CanReceiverBeSmiBasedOnInterfaceTarget(
51485147
// it would compute correctly whether or not receiver can be a smi.
51495148
const AbstractType& target_type = AbstractType::Handle(
51505149
zone, Class::Handle(zone, interface_target().Owner()).RareType());
5151-
if (!CompileType::Smi().IsAssignableTo(target_type)) {
5150+
if (!CompileType::Smi().IsSubtypeOf(target_type)) {
51525151
return false;
51535152
}
51545153
}

runtime/vm/compiler/backend/type_propagator.cc

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -865,18 +865,6 @@ bool CompileType::IsSubtypeOf(const AbstractType& other) {
865865
if (other.IsTopTypeForSubtyping()) {
866866
return true;
867867
}
868-
869-
if (IsNone()) {
870-
return false;
871-
}
872-
873-
return ToAbstractType()->IsSubtypeOf(other, Heap::kOld);
874-
}
875-
876-
bool CompileType::IsAssignableTo(const AbstractType& other) {
877-
if (other.IsTopTypeForSubtyping()) {
878-
return true;
879-
}
880868
// If we allow comparisons against an uninstantiated type, then we can
881869
// end up incorrectly optimizing away AssertAssignables where the incoming
882870
// value and outgoing value have CompileTypes that would return true to the
@@ -899,19 +887,6 @@ bool CompileType::IsAssignableTo(const AbstractType& other) {
899887
return ToAbstractType()->IsSubtypeOf(other, Heap::kOld);
900888
}
901889

902-
bool CompileType::IsInstanceOf(const AbstractType& other) {
903-
if (other.IsTopTypeForInstanceOf()) {
904-
return true;
905-
}
906-
if (IsNone() || !other.IsInstantiated()) {
907-
return false;
908-
}
909-
if (is_nullable() && !other.IsNullable()) {
910-
return false;
911-
}
912-
return ToAbstractType()->IsSubtypeOf(other, Heap::kOld);
913-
}
914-
915890
bool CompileType::Specialize(GrowableArray<intptr_t>* class_ids) {
916891
ToNullableCid();
917892
if (cid_ != kDynamicCid) {
@@ -939,7 +914,7 @@ bool CompileType::Specialize(GrowableArray<intptr_t>* class_ids) {
939914
// bounds.
940915
static bool CanPotentiallyBeSmi(const AbstractType& type, bool recurse) {
941916
if (type.IsInstantiated()) {
942-
return CompileType::Smi().IsAssignableTo(type);
917+
return CompileType::Smi().IsSubtypeOf(type);
943918
} else if (type.IsTypeParameter()) {
944919
// For type parameters look at their bounds (if recurse allows us).
945920
const auto& param = TypeParameter::Cast(type);

runtime/vm/compiler/call_specializer.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,7 @@ bool CallSpecializer::TryOptimizeInstanceOfUsingStaticTypes(
11791179
}
11801180

11811181
Value* left_value = call->Receiver();
1182-
if (left_value->Type()->IsInstanceOf(type)) {
1182+
if (left_value->Type()->IsSubtypeOf(type)) {
11831183
ConstantInstr* replacement = flow_graph()->GetConstant(Bool::True());
11841184
call->ReplaceUsesWith(replacement);
11851185
ASSERT(current_iterator()->Current() == call);
@@ -1507,7 +1507,7 @@ void TypedDataSpecializer::TryInlineCall(TemplateDartCall<0>* call) {
15071507

15081508
auto& type_class = Class::Handle(zone_);
15091509
for (auto& variant : typed_data_variants_) {
1510-
if (!receiver_type->IsAssignableTo(variant.array_type)) {
1510+
if (!receiver_type->IsSubtypeOf(variant.array_type)) {
15111511
continue;
15121512
}
15131513

@@ -1535,7 +1535,7 @@ void TypedDataSpecializer::TryInlineCall(TemplateDartCall<0>* call) {
15351535
type_class = variant.array_type.type_class();
15361536
ReplaceWithIndexGet(call, variant.array_cid);
15371537
} else {
1538-
if (!value_type->IsAssignableTo(variant.element_type)) {
1538+
if (!value_type->IsSubtypeOf(variant.element_type)) {
15391539
return;
15401540
}
15411541
type_class = variant.array_type.type_class();

runtime/vm/isolate_reload.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2386,8 +2386,8 @@ class FieldInvalidator {
23862386
}
23872387

23882388
instance_ ^= value.ptr();
2389-
if (instance_.IsAssignableTo(type, instantiator_type_arguments_,
2390-
function_type_arguments_)) {
2389+
if (instance_.IsInstanceOf(type, instantiator_type_arguments_,
2390+
function_type_arguments_)) {
23912391
// Do not add record instances to cache as they don't have a valid
23922392
// key (type of a record depends on types of all its fields).
23932393
if (cid != kRecordCid) {

runtime/vm/object.cc

Lines changed: 2 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -10011,12 +10011,8 @@ ObjectPtr Function::DoArgumentTypesMatch(
1001110011
const TypeArguments& function_type_args) -> bool {
1001210012
// If the argument type is the top type, no need to check.
1001310013
if (type.IsTopTypeForSubtyping()) return true;
10014-
if (argument.IsNull()) {
10015-
return Instance::NullIsAssignableTo(type, instantiator_type_args,
10016-
function_type_args);
10017-
}
10018-
return argument.IsAssignableTo(type, instantiator_type_args,
10019-
function_type_args);
10014+
return argument.IsInstanceOf(type, instantiator_type_args,
10015+
function_type_args);
1002010016
};
1002110017

1002210018
// Check types of the provided arguments against the expected parameter types.
@@ -21342,88 +21338,15 @@ void Instance::SetTypeArguments(const TypeArguments& value) const {
2134221338
SetFieldAtOffset(field_offset, value);
2134321339
}
2134421340

21345-
/*
21346-
Specification of instance checks (e is T) and casts (e as T), where e evaluates
21347-
to a value v and v has runtime type S:
21348-
21349-
Instance checks (e is T) in weak checking mode in a legacy or opted-in library:
21350-
If v == null and T is a legacy type
21351-
return LEGACY_SUBTYPE(T, Null) || LEGACY_SUBTYPE(Object, T)
21352-
If v == null and T is not a legacy type, return NNBD_SUBTYPE(Null, T)
21353-
Otherwise return LEGACY_SUBTYPE(S, T)
21354-
21355-
Instance checks (e is T) in strong checking mode in a legacy or opted-in lib:
21356-
If v == null and T is a legacy type
21357-
return LEGACY_SUBTYPE(T, Null) || LEGACY_SUBTYPE(Object, T)
21358-
Otherwise return NNBD_SUBTYPE(S, T)
21359-
21360-
Casts (e as T) in weak checking mode in a legacy or opted-in library:
21361-
If LEGACY_SUBTYPE(S, T) then e as T evaluates to v.
21362-
Otherwise a TypeError is thrown.
21363-
21364-
Casts (e as T) in strong checking mode in a legacy or opted-in library:
21365-
If NNBD_SUBTYPE(S, T) then e as T evaluates to v.
21366-
Otherwise a TypeError is thrown.
21367-
*/
21368-
2136921341
bool Instance::IsInstanceOf(
2137021342
const AbstractType& other,
2137121343
const TypeArguments& other_instantiator_type_arguments,
2137221344
const TypeArguments& other_function_type_arguments) const {
2137321345
ASSERT(!other.IsDynamicType());
21374-
if (IsNull()) {
21375-
return Instance::NullIsInstanceOf(other, other_instantiator_type_arguments,
21376-
other_function_type_arguments);
21377-
}
21378-
// In strong mode, compute NNBD_SUBTYPE(runtimeType, other).
21379-
// In weak mode, compute LEGACY_SUBTYPE(runtimeType, other).
21380-
return RuntimeTypeIsSubtypeOf(other, other_instantiator_type_arguments,
21381-
other_function_type_arguments);
21382-
}
21383-
21384-
bool Instance::IsAssignableTo(
21385-
const AbstractType& other,
21386-
const TypeArguments& other_instantiator_type_arguments,
21387-
const TypeArguments& other_function_type_arguments) const {
21388-
ASSERT(!other.IsDynamicType());
21389-
// In strong mode, compute NNBD_SUBTYPE(runtimeType, other).
21390-
// In weak mode, compute LEGACY_SUBTYPE(runtimeType, other).
2139121346
return RuntimeTypeIsSubtypeOf(other, other_instantiator_type_arguments,
2139221347
other_function_type_arguments);
2139321348
}
2139421349

21395-
// If 'other' type (once instantiated) is a legacy type:
21396-
// return LEGACY_SUBTYPE(other, Null) || LEGACY_SUBTYPE(Object, other).
21397-
// Otherwise return NNBD_SUBTYPE(Null, T).
21398-
// Ignore value of strong flag value.
21399-
bool Instance::NullIsInstanceOf(
21400-
const AbstractType& other,
21401-
const TypeArguments& other_instantiator_type_arguments,
21402-
const TypeArguments& other_function_type_arguments) {
21403-
ASSERT(other.IsFinalized());
21404-
if (other.IsNullable()) {
21405-
// This case includes top types (void, dynamic, Object?).
21406-
// The uninstantiated nullable type will remain nullable after
21407-
// instantiation.
21408-
return true;
21409-
}
21410-
if (other.IsFutureOrType()) {
21411-
const auto& type = AbstractType::Handle(other.UnwrapFutureOr());
21412-
return NullIsInstanceOf(type, other_instantiator_type_arguments,
21413-
other_function_type_arguments);
21414-
}
21415-
// No need to instantiate type, unless it is a type parameter.
21416-
// Note that a typeref cannot refer to a type parameter.
21417-
if (other.IsTypeParameter()) {
21418-
auto& type = AbstractType::Handle(other.InstantiateFrom(
21419-
other_instantiator_type_arguments, other_function_type_arguments,
21420-
kAllFree, Heap::kOld));
21421-
return Instance::NullIsInstanceOf(type, Object::null_type_arguments(),
21422-
Object::null_type_arguments());
21423-
}
21424-
return false;
21425-
}
21426-
2142721350
// Must be kept in sync with GenerateNullIsAssignableToType in
2142821351
// stub_code_compiler.cc if any changes are made.
2142921352
bool Instance::NullIsAssignableTo(const AbstractType& other) {

runtime/vm/object.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8348,12 +8348,6 @@ class Instance : public Object {
83488348
const TypeArguments& other_instantiator_type_arguments,
83498349
const TypeArguments& other_function_type_arguments) const;
83508350

8351-
// Check if this instance is assignable to the given other type.
8352-
// The type argument vectors are used to instantiate the other type if needed.
8353-
bool IsAssignableTo(const AbstractType& other,
8354-
const TypeArguments& other_instantiator_type_arguments,
8355-
const TypeArguments& other_function_type_arguments) const;
8356-
83578351
// Return true if the null instance can be assigned to a variable of [other]
83588352
// type. Return false if null cannot be assigned or we cannot tell (if
83598353
// [other] is a type parameter in NNBD strong mode). Only used for checks at
@@ -8477,12 +8471,6 @@ class Instance : public Object {
84778471
bool RuntimeTypeIsSubtypeOfFutureOr(Zone* zone,
84788472
const AbstractType& other) const;
84798473

8480-
// Return true if the null instance is an instance of other type.
8481-
static bool NullIsInstanceOf(
8482-
const AbstractType& other,
8483-
const TypeArguments& other_instantiator_type_arguments,
8484-
const TypeArguments& other_function_type_arguments);
8485-
84868474
CompressedObjectPtr* FieldAddrAtOffset(intptr_t offset) const {
84878475
ASSERT(IsValidFieldOffset(offset));
84888476
return reinterpret_cast<CompressedObjectPtr*>(raw_value() - kHeapObjectTag +

runtime/vm/runtime_entry.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,7 +1359,7 @@ DEFINE_RUNTIME_ENTRY(TypeCheck, 7) {
13591359
// This is guaranteed on the calling side.
13601360
ASSERT(!dst_type.IsDynamicType());
13611361

1362-
const bool is_instance_of = src_instance.IsAssignableTo(
1362+
const bool is_instance_of = src_instance.IsInstanceOf(
13631363
dst_type, instantiator_type_arguments, function_type_arguments);
13641364

13651365
if (FLAG_trace_type_checks) {
@@ -1433,7 +1433,7 @@ DEFINE_RUNTIME_ENTRY(TypeCheck, 7) {
14331433
if (result.IsError()) {
14341434
Exceptions::PropagateError(Error::Cast(result));
14351435
}
1436-
// IsAssignableTo returned false, so we should have thrown a type
1436+
// IsInstanceOf returned false, so we should have thrown a type
14371437
// error in DoArgumentsTypesMatch.
14381438
UNREACHABLE();
14391439
}

0 commit comments

Comments
 (0)