@@ -4858,56 +4858,94 @@ bool Class::IsFutureClass() const {
48584858 (library() == Library::AsyncLibrary());
48594859}
48604860
4861- // Checks if type S is a subtype of type T , assuming that S is non-nullable.
4862- // Type S is specified by class 'cls' parameterized with 'type_arguments', and
4863- // type T by class 'other' parameterized with 'other_type_arguments' .
4861+ // Checks if type T0 is a subtype of type T1 , assuming that T0 is non-nullable.
4862+ // Type T0 is specified by class 'cls' parameterized with 'type_arguments', and
4863+ // type T1 is specified by 'other' and must have a type class .
48644864// This class and class 'other' do not need to be finalized, however, they must
48654865// be resolved as well as their interfaces.
48664866bool Class::IsSubtypeOf(NNBDMode mode,
48674867 const Class& cls,
48684868 const TypeArguments& type_arguments,
4869- const Class& other,
4870- const TypeArguments& other_type_arguments,
4869+ const AbstractType& other,
48714870 Heap::Space space) {
4872- // This function does not support Null, dynamic, or void as type S.
4873- ASSERT(!cls.IsNullClass() && !cls.IsDynamicClass() && !cls.IsVoidClass());
4874- // Since we assume that S is non-nullable, the nullability of T is irrelevant.
4875- if (other.IsDynamicClass() || other.IsVoidClass() || other.IsObjectClass()) {
4871+ // This function does not support Null, Never, dynamic, or void as type T0.
4872+ classid_t this_cid = cls.id();
4873+ ASSERT(this_cid != kNullCid && this_cid != kNeverCid &&
4874+ this_cid != kDynamicCid && this_cid != kVoidCid);
4875+ // Type T1 must have a type class (e.g. not a type parameter).
4876+ ASSERT(other.HasTypeClass());
4877+ const classid_t other_cid = other.type_class_id();
4878+ // Since T0 is assumed non-nullable, the nullability of T1 is irrelevant.
4879+ if (other_cid == kDynamicCid || other_cid == kVoidCid ||
4880+ other_cid == kObjectCid) {
48764881 return true;
48774882 }
4878- // Use the 'this_class' object as if it was the receiver of this method, but
4879- // instead of recursing, reset it to the super class and loop.
48804883 Thread* thread = Thread::Current();
48814884 Zone* zone = thread->zone();
4885+ const Class& other_class = Class::Handle(zone, other.type_class());
4886+ const TypeArguments& other_type_arguments =
4887+ TypeArguments::Handle(zone, other.arguments());
4888+ // Use the 'this_class' object as if it was the receiver of this method, but
4889+ // instead of recursing, reset it to the super class and loop.
48824890 Class& this_class = Class::Handle(zone, cls.raw());
48834891 while (true) {
4884- // Apply additional subtyping rules if 'other' is 'FutureOr'.
4885- if (other.IsFutureOrClass()) {
4886- if (other_type_arguments.IsNull()) {
4887- return true;
4892+ // Apply additional subtyping rules if T0 or T1 are 'FutureOr'.
4893+
4894+ // Left FutureOr:
4895+ // if T0 is FutureOr<S0> then:
4896+ // T0 <: T1 iff Future<S0> <: T1 and S0 <: T1
4897+ if (this_cid == kFutureOrCid) {
4898+ // Check Future<S0> <: T1.
4899+ ObjectStore* object_store = Isolate::Current()->object_store();
4900+ const Class& future_class =
4901+ Class::Handle(zone, object_store->future_class());
4902+ ASSERT(!future_class.IsNull() && future_class.NumTypeParameters() == 1 &&
4903+ this_class.NumTypeParameters() == 1);
4904+ ASSERT(type_arguments.IsNull() || type_arguments.Length() >= 1);
4905+ if (Class::IsSubtypeOf(mode, future_class, type_arguments, other,
4906+ space)) {
4907+ // Check S0 <: T1.
4908+ const AbstractType& type_arg =
4909+ AbstractType::Handle(zone, type_arguments.TypeAtNullSafe(0));
4910+ if (type_arg.IsSubtypeOf(mode, other, space)) {
4911+ return true;
4912+ }
48884913 }
4914+ }
4915+
4916+ // Right FutureOr:
4917+ // if T1 is FutureOr<S1> then:
4918+ // T0 <: T1 iff any of the following hold:
4919+ // either T0 <: Future<S1>
4920+ // or T0 <: S1
4921+ // or T0 is X0 and X0 has bound S0 and S0 <: T1 (checked elsewhere)
4922+ if (other_cid == kFutureOrCid) {
48894923 const AbstractType& other_type_arg =
4890- AbstractType::Handle(zone, other_type_arguments.TypeAt(0));
4924+ AbstractType::Handle(zone, other_type_arguments.TypeAtNullSafe(0));
4925+ // Check if S1 is a top type.
48914926 if (other_type_arg.IsTopType()) {
48924927 return true;
48934928 }
4894- if (!type_arguments.IsNull() && this_class.IsFutureClass()) {
4929+ // Check T0 <: Future<S1> when T0 is Future<S0>.
4930+ if (this_class.IsFutureClass()) {
48954931 const AbstractType& type_arg =
4896- AbstractType::Handle(zone, type_arguments.TypeAt(0));
4932+ AbstractType::Handle(zone, type_arguments.TypeAtNullSafe(0));
4933+ // If T0 is Future<S0>, then T0 <: Future<S1>, iff S0 <: S1.
48974934 if (type_arg.IsSubtypeOf(mode, other_type_arg, space)) {
48984935 return true;
48994936 }
49004937 }
4938+ // Check T0 <: Future<S1> when T0 is FutureOr<S0> is already done.
4939+ // Check T0 <: S1.
49014940 if (other_type_arg.HasTypeClass() &&
4902- Class::IsSubtypeOf(
4903- mode, this_class, type_arguments,
4904- Class::Handle(zone, other_type_arg.type_class()),
4905- TypeArguments::Handle(zone, other_type_arg.arguments()), space)) {
4941+ Class::IsSubtypeOf(mode, this_class, type_arguments, other_type_arg,
4942+ space)) {
49064943 return true;
49074944 }
49084945 }
4946+
49094947 // Check for reflexivity.
4910- if (this_class.raw() == other .raw()) {
4948+ if (this_class.raw() == other_class .raw()) {
49114949 const intptr_t num_type_params = this_class.NumTypeParameters();
49124950 if (num_type_params == 0) {
49134951 return true;
@@ -4961,7 +4999,7 @@ bool Class::IsSubtypeOf(NNBDMode mode,
49614999 continue;
49625000 }
49635001 if (Class::IsSubtypeOf(mode, interface_class, interface_args, other,
4964- other_type_arguments, space)) {
5002+ space)) {
49655003 return true;
49665004 }
49675005 }
@@ -4970,6 +5008,7 @@ bool Class::IsSubtypeOf(NNBDMode mode,
49705008 if (this_class.IsNull()) {
49715009 return false;
49725010 }
5011+ this_cid = this_class.id();
49735012 }
49745013 UNREACHABLE();
49755014 return false;
@@ -17569,35 +17608,28 @@ bool Instance::RuntimeTypeIsSubtypeOf(
1756917608 }
1757017609 // RuntimeType of non-null instance is non-nullable, so there is no need to
1757117610 // check nullability of other type.
17572- return Class::IsSubtypeOf(
17573- mode, cls, type_arguments,
17574- Class::Handle(zone, instantiated_other.type_class()),
17575- TypeArguments::Handle(zone, instantiated_other.arguments()), Heap::kOld);
17611+ return Class::IsSubtypeOf(mode, cls, type_arguments, instantiated_other,
17612+ Heap::kOld);
1757617613}
1757717614
1757817615bool Instance::IsFutureOrInstanceOf(Zone* zone,
1757917616 NNBDMode mode,
1758017617 const AbstractType& other) const {
1758117618 if (other.IsType() && other.IsFutureOrType()) {
17582- if (other.arguments() == TypeArguments::null()) {
17583- return true;
17584- }
1758517619 const TypeArguments& other_type_arguments =
1758617620 TypeArguments::Handle(zone, other.arguments());
1758717621 const AbstractType& other_type_arg =
17588- AbstractType::Handle(zone, other_type_arguments.TypeAt (0));
17622+ AbstractType::Handle(zone, other_type_arguments.TypeAtNullSafe (0));
1758917623 if (other_type_arg.IsTopType()) {
1759017624 return true;
1759117625 }
1759217626 if (Class::Handle(zone, clazz()).IsFutureClass()) {
1759317627 const TypeArguments& type_arguments =
1759417628 TypeArguments::Handle(zone, GetTypeArguments());
17595- if (!type_arguments.IsNull()) {
17596- const AbstractType& type_arg =
17597- AbstractType::Handle(zone, type_arguments.TypeAt(0));
17598- if (type_arg.IsSubtypeOf(mode, other_type_arg, Heap::kOld)) {
17599- return true;
17600- }
17629+ const AbstractType& type_arg =
17630+ AbstractType::Handle(zone, type_arguments.TypeAtNullSafe(0));
17631+ if (type_arg.IsSubtypeOf(mode, other_type_arg, Heap::kOld)) {
17632+ return true;
1760117633 }
1760217634 }
1760317635 // Retry RuntimeTypeIsSubtypeOf after unwrapping type arg of FutureOr.
@@ -18396,26 +18428,22 @@ bool AbstractType::IsSubtypeOf(NNBDMode mode,
1839618428 return false;
1839718429 }
1839818430 return Class::IsSubtypeOf(
18399- mode, type_cls, TypeArguments::Handle(zone, arguments()), other_type_cls,
18400- TypeArguments::Handle(zone, other.arguments()), space);
18431+ mode, type_cls, TypeArguments::Handle(zone, arguments()), other, space);
1840118432}
1840218433
1840318434bool AbstractType::IsSubtypeOfFutureOr(Zone* zone,
1840418435 NNBDMode mode,
1840518436 const AbstractType& other,
1840618437 Heap::Space space) const {
1840718438 if (other.IsType() && other.IsFutureOrType()) {
18408- if (other.arguments() == TypeArguments::null()) {
18409- return true;
18410- }
1841118439 // This function is only called with a receiver that is either a function
1841218440 // type or an uninstantiated type parameter, therefore, it cannot be of
1841318441 // class Future and we can spare the check.
1841418442 ASSERT(IsFunctionType() || IsTypeParameter());
1841518443 const TypeArguments& other_type_arguments =
1841618444 TypeArguments::Handle(zone, other.arguments());
1841718445 const AbstractType& other_type_arg =
18418- AbstractType::Handle(zone, other_type_arguments.TypeAt (0));
18446+ AbstractType::Handle(zone, other_type_arguments.TypeAtNullSafe (0));
1841918447 if (other_type_arg.IsTopType()) {
1842018448 return true;
1842118449 }
0 commit comments