From 0ddba911905d2b692b027074ac6c6ee0df8e384e Mon Sep 17 00:00:00 2001 From: Mayank Patke Date: Thu, 13 Jun 2024 19:25:28 +0000 Subject: [PATCH] [dart2js] Convert SubclassResult to a sealed class hierarchy. Change-Id: I151c2f6f72dcecaff6a6976f058940b9ddf97f47 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/371461 Reviewed-by: Nate Biggs Commit-Queue: Mayank Patke --- .../inferrer/typemasks/flat_type_mask.dart | 29 ++- .../js_backend/runtime_types_resolution.dart | 20 +-- .../lib/src/universe/class_hierarchy.dart | 93 ++++------ pkg/compiler/test/model/world_test.dart | 166 ++++++++++-------- 4 files changed, 153 insertions(+), 155 deletions(-) diff --git a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart index 27cc8eb3e86..b0cde3a76cd 100644 --- a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart +++ b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart @@ -462,42 +462,42 @@ class FlatTypeMask extends TypeMask { SubclassResult result = domain._closedWorld.classHierarchy.commonSubclasses( base!, _classQuery, otherBase!, flatOther._classQuery); - switch (result.kind) { - case SubclassResultKind.EMPTY: + switch (result) { + case SimpleSubclassResult.empty: return includeNull ? TypeMask.empty(hasLateSentinel: includeLateSentinel) : TypeMask.nonNullEmpty(hasLateSentinel: includeLateSentinel); - case SubclassResultKind.EXACT1: + case SimpleSubclassResult.exact1: assert(isExact); return withFlags( isNullable: includeNull, hasLateSentinel: includeLateSentinel); - case SubclassResultKind.EXACT2: + case SimpleSubclassResult.exact2: assert(other.isExact); return other.withFlags( isNullable: includeNull, hasLateSentinel: includeLateSentinel); - case SubclassResultKind.SUBCLASS1: + case SimpleSubclassResult.subclass1: assert(isSubclass); return withFlags( isNullable: includeNull, hasLateSentinel: includeLateSentinel); - case SubclassResultKind.SUBCLASS2: + case SimpleSubclassResult.subclass2: assert(flatOther.isSubclass); return other.withFlags( isNullable: includeNull, hasLateSentinel: includeLateSentinel); - case SubclassResultKind.SUBTYPE1: + case SimpleSubclassResult.subtype1: assert(isSubtype); return withFlags( isNullable: includeNull, hasLateSentinel: includeLateSentinel); - case SubclassResultKind.SUBTYPE2: + case SimpleSubclassResult.subtype2: assert(flatOther.isSubtype); return other.withFlags( isNullable: includeNull, hasLateSentinel: includeLateSentinel); - case SubclassResultKind.SET: - if (result.classes.isEmpty) { + case SetSubclassResult(:final classes): + if (classes.isEmpty) { return includeNull ? TypeMask.empty(hasLateSentinel: includeLateSentinel) : TypeMask.nonNullEmpty(hasLateSentinel: includeLateSentinel); - } else if (result.classes.length == 1) { - ClassEntity cls = result.classes.first; + } else if (classes.length == 1) { + ClassEntity cls = classes.first; return includeNull ? TypeMask.subclass(cls, domain._closedWorld, hasLateSentinel: includeLateSentinel) @@ -505,9 +505,8 @@ class FlatTypeMask extends TypeMask { hasLateSentinel: includeLateSentinel); } - List masks = List.from(result.classes.map( - (ClassEntity cls) => - TypeMask.nonNullSubclass(cls, domain._closedWorld))); + List masks = List.from(classes.map((ClassEntity cls) => + TypeMask.nonNullSubclass(cls, domain._closedWorld))); if (masks.length > UnionTypeMask.MAX_UNION_LENGTH) { return UnionTypeMask.flatten(masks, domain, includeNull: includeNull, diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart index 4fc27245349..9efdcd2cda5 100644 --- a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart +++ b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart @@ -1271,21 +1271,21 @@ class RuntimeTypesNeedBuilderImpl implements RuntimeTypesNeedBuilder { SubclassResult result = closedWorld.classHierarchy .commonSubclasses(receiverClass, ClassQuery.SUBTYPE, argumentClass, ClassQuery.SUBTYPE); - switch (result.kind) { - case SubclassResultKind.EMPTY: + switch (result) { + case SimpleSubclassResult.empty: break; - case SubclassResultKind.EXACT1: - case SubclassResultKind.SUBCLASS1: - case SubclassResultKind.SUBTYPE1: + case SimpleSubclassResult.exact1: + case SimpleSubclassResult.subclass1: + case SimpleSubclassResult.subtype1: addClass(receiverClass); break; - case SubclassResultKind.EXACT2: - case SubclassResultKind.SUBCLASS2: - case SubclassResultKind.SUBTYPE2: + case SimpleSubclassResult.exact2: + case SimpleSubclassResult.subclass2: + case SimpleSubclassResult.subtype2: addClass(argumentClass); break; - case SubclassResultKind.SET: - for (ClassEntity cls in result.classes) { + case SetSubclassResult(:final classes): + for (ClassEntity cls in classes) { addClass(cls); if (neededOnAll) break; } diff --git a/pkg/compiler/lib/src/universe/class_hierarchy.dart b/pkg/compiler/lib/src/universe/class_hierarchy.dart index 21a29eba5da..b9b7f49043a 100644 --- a/pkg/compiler/lib/src/universe/class_hierarchy.dart +++ b/pkg/compiler/lib/src/universe/class_hierarchy.dart @@ -402,61 +402,61 @@ class ClassHierarchyImpl implements ClassHierarchy { // Exact classes [cls1] and [cls2] must be identical to have any classes // in common. if (cls1 != cls2) { - return SubclassResult.EMPTY; + return SimpleSubclassResult.empty; } - return SubclassResult.EXACT1; + return SimpleSubclassResult.exact1; } else if (query1 == ClassQuery.EXACT) { if (query2 == ClassQuery.SUBCLASS) { // Exact [cls1] must be a subclass of [cls2] to have any classes in // common. if (isSubclassOf(cls1, cls2)) { - return SubclassResult.EXACT1; + return SimpleSubclassResult.exact1; } } else if (query2 == ClassQuery.SUBTYPE) { // Exact [cls1] must be a subtype of [cls2] to have any classes in // common. if (isSubtypeOf(cls1, cls2)) { - return SubclassResult.EXACT1; + return SimpleSubclassResult.exact1; } } - return SubclassResult.EMPTY; + return SimpleSubclassResult.empty; } else if (query2 == ClassQuery.EXACT) { if (query1 == ClassQuery.SUBCLASS) { // Exact [cls2] must be a subclass of [cls1] to have any classes in // common. if (isSubclassOf(cls2, cls1)) { - return SubclassResult.EXACT2; + return SimpleSubclassResult.exact2; } } else if (query1 == ClassQuery.SUBTYPE) { // Exact [cls2] must be a subtype of [cls1] to have any classes in // common. if (isSubtypeOf(cls2, cls1)) { - return SubclassResult.EXACT2; + return SimpleSubclassResult.exact2; } } - return SubclassResult.EMPTY; + return SimpleSubclassResult.empty; } else if (query1 == ClassQuery.SUBCLASS && query2 == ClassQuery.SUBCLASS) { // [cls1] must be a subclass of [cls2] or vice versa to have any classes // in common. if (cls1 == cls2 || isSubclassOf(cls1, cls2)) { // The subclasses of [cls1] are contained within the subclasses of // [cls2]. - return SubclassResult.SUBCLASS1; + return SimpleSubclassResult.subclass1; } else if (isSubclassOf(cls2, cls1)) { // The subclasses of [cls2] are contained within the subclasses of // [cls1]. - return SubclassResult.SUBCLASS2; + return SimpleSubclassResult.subclass2; } - return SubclassResult.EMPTY; + return SimpleSubclassResult.empty; } else if (query1 == ClassQuery.SUBCLASS) { if (isSubtypeOf(cls1, cls2)) { // The subclasses of [cls1] are all subtypes of [cls2]. - return SubclassResult.SUBCLASS1; + return SimpleSubclassResult.subclass1; } if (cls1 == _commonElements.objectClass) { // Since [cls1] is `Object` all subtypes of [cls2] are contained within // the subclasses of [cls1]. - return SubclassResult.SUBTYPE2; + return SimpleSubclassResult.subtype2; } // Find all the root subclasses of [cls1] of that implement [cls2]. // @@ -481,16 +481,16 @@ class ClassHierarchyImpl implements ClassHierarchy { } return IterationStep.CONTINUE; }); - return SubclassResult(classes); + return SetSubclassResult(classes); } else if (query2 == ClassQuery.SUBCLASS) { if (isSubtypeOf(cls2, cls1)) { // The subclasses of [cls2] are all subtypes of [cls1]. - return SubclassResult.SUBCLASS2; + return SimpleSubclassResult.subclass2; } if (cls2 == _commonElements.objectClass) { // Since [cls2] is `Object` all subtypes of [cls1] are contained within // the subclasses of [cls2]. - return SubclassResult.SUBTYPE1; + return SimpleSubclassResult.subtype1; } // Find all the root subclasses of [cls2] of that implement [cls1]. List classes = []; @@ -503,14 +503,14 @@ class ClassHierarchyImpl implements ClassHierarchy { } return IterationStep.CONTINUE; }); - return SubclassResult(classes); + return SetSubclassResult(classes); } else { if (cls1 == cls2 || isSubtypeOf(cls1, cls2)) { // The subtypes of [cls1] are contained within the subtypes of [cls2]. - return SubclassResult.SUBTYPE1; + return SimpleSubclassResult.subtype1; } else if (isSubtypeOf(cls2, cls1)) { // The subtypes of [cls2] are contained within the subtypes of [cls1]. - return SubclassResult.SUBTYPE2; + return SimpleSubclassResult.subtype2; } // Find all the root subclasses of [cls1] of that implement [cls2]. // @@ -537,7 +537,7 @@ class ClassHierarchyImpl implements ClassHierarchy { } return IterationStep.CONTINUE; }); - return SubclassResult(classes); + return SetSubclassResult(classes); } } @@ -935,59 +935,38 @@ enum ClassQuery { SUBTYPE, } -/// Result kind for [ClassHierarchy.commonSubclasses]. -enum SubclassResultKind { +/// Result computed in [ClassHierarchy.commonSubclasses]. +sealed class SubclassResult {} + +enum SimpleSubclassResult implements SubclassResult { /// No common subclasses. - EMPTY, + empty, /// Exactly the first class in common. - EXACT1, + exact1, /// Exactly the second class in common. - EXACT2, + exact2, /// Subclasses of the first class in common. - SUBCLASS1, + subclass1, /// Subclasses of the second class in common. - SUBCLASS2, + subclass2, /// Subtypes of the first class in common. - SUBTYPE1, + subtype1, /// Subtypes of the second class in common. - SUBTYPE2, - - /// Subclasses of a set of classes in common. - SET + subtype2, } -/// Result computed in [ClassHierarchy.commonSubclasses]. -class SubclassResult { - final SubclassResultKind kind; - final List? _classes; +/// Subclasses of a set of classes in common. +class SetSubclassResult implements SubclassResult { + final List classes; - List get classes => _classes!; - - SubclassResult(this._classes) : kind = SubclassResultKind.SET; - - const SubclassResult.internal(this.kind) : _classes = null; - - static const SubclassResult EMPTY = - SubclassResult.internal(SubclassResultKind.EMPTY); - static const SubclassResult EXACT1 = - SubclassResult.internal(SubclassResultKind.EXACT1); - static const SubclassResult EXACT2 = - SubclassResult.internal(SubclassResultKind.EXACT2); - static const SubclassResult SUBCLASS1 = - SubclassResult.internal(SubclassResultKind.SUBCLASS1); - static const SubclassResult SUBCLASS2 = - SubclassResult.internal(SubclassResultKind.SUBCLASS2); - static const SubclassResult SUBTYPE1 = - SubclassResult.internal(SubclassResultKind.SUBTYPE1); - static const SubclassResult SUBTYPE2 = - SubclassResult.internal(SubclassResultKind.SUBTYPE2); + SetSubclassResult(this.classes); @override - String toString() => 'SubclassResult($kind,classes=$_classes)'; + String toString() => 'SetSubclassResult(classes=$classes)'; } diff --git a/pkg/compiler/test/model/world_test.dart b/pkg/compiler/test/model/world_test.dart index c26d9aa7537..1b1e07a8838 100644 --- a/pkg/compiler/test/model/world_test.dart +++ b/pkg/compiler/test/model/world_test.dart @@ -569,47 +569,47 @@ testCommonSubclasses() async { final I = env.getElement("I") as ClassEntity; final J = env.getElement("J") as ClassEntity; - ClassQuery? toClassQuery(SubclassResultKind kind, ClassEntity cls1, + ClassQuery? toClassQuery(SubclassResult result, ClassEntity cls1, ClassQuery query1, ClassEntity cls2, ClassQuery query2) { - switch (kind) { - case SubclassResultKind.EMPTY: + switch (result) { + case SimpleSubclassResult.empty: return null; - case SubclassResultKind.EXACT1: + case SimpleSubclassResult.exact1: return ClassQuery.EXACT; - case SubclassResultKind.EXACT2: + case SimpleSubclassResult.exact2: return ClassQuery.EXACT; - case SubclassResultKind.SUBCLASS1: + case SimpleSubclassResult.subclass1: return ClassQuery.SUBCLASS; - case SubclassResultKind.SUBCLASS2: + case SimpleSubclassResult.subclass2: return ClassQuery.SUBCLASS; - case SubclassResultKind.SUBTYPE1: + case SimpleSubclassResult.subtype1: return ClassQuery.SUBTYPE; - case SubclassResultKind.SUBTYPE2: + case SimpleSubclassResult.subtype2: return ClassQuery.SUBTYPE; - case SubclassResultKind.SET: + case SetSubclassResult(): default: return null; } } - ClassEntity? toClassEntity(SubclassResultKind kind, ClassEntity cls1, + ClassEntity? toClassEntity(SubclassResult result, ClassEntity cls1, ClassQuery query1, ClassEntity cls2, ClassQuery query2) { - switch (kind) { - case SubclassResultKind.EMPTY: + switch (result) { + case SimpleSubclassResult.empty: return null; - case SubclassResultKind.EXACT1: + case SimpleSubclassResult.exact1: return cls1; - case SubclassResultKind.EXACT2: + case SimpleSubclassResult.exact2: return cls2; - case SubclassResultKind.SUBCLASS1: + case SimpleSubclassResult.subclass1: return cls1; - case SubclassResultKind.SUBCLASS2: + case SimpleSubclassResult.subclass2: return cls2; - case SubclassResultKind.SUBTYPE1: + case SimpleSubclassResult.subtype1: return cls1; - case SubclassResultKind.SUBTYPE2: + case SimpleSubclassResult.subtype2: return cls2; - case SubclassResultKind.SET: + case SetSubclassResult(): default: return null; } @@ -622,75 +622,95 @@ testCommonSubclasses() async { SubclassResult result2 = closedWorld.classHierarchy.commonSubclasses(cls2, query2, cls1, query1); Expect.equals( - toClassQuery(result1.kind, cls1, query1, cls2, query2), - toClassQuery(result2.kind, cls2, query2, cls1, query1), + toClassQuery(result1, cls1, query1, cls2, query2), + toClassQuery(result2, cls2, query2, cls1, query1), "Asymmetric results for ($cls1,$query1) vs ($cls2,$query2):" "\n a vs b: $result1\n b vs a: $result2"); Expect.equals( - toClassEntity(result1.kind, cls1, query1, cls2, query2), - toClassEntity(result2.kind, cls2, query2, cls1, query1), + toClassEntity(result1, cls1, query1, cls2, query2), + toClassEntity(result2, cls2, query2, cls1, query1), "Asymmetric results for ($cls1,$query1) vs ($cls2,$query2):" "\n a vs b: $result1\n b vs a: $result2"); - Expect.equals( - expectedResult.kind, - result1.kind, - "Unexpected results for ($cls1,$query1) vs ($cls2,$query2):" - "\n expected: $expectedResult\n actual: $result1"); - if (expectedResult.kind == SubclassResultKind.SET) { - Expect.setEquals( - result1.classes, - result2.classes, - "Asymmetric results for ($cls1,$query1) vs ($cls2,$query2):" - "\n a vs b: $result1\n b vs a: $result2"); - Expect.setEquals( - expectedResult.classes, - result1.classes, - "Unexpected results for ($cls1,$query1) vs ($cls2,$query2):" - "\n expected: $expectedResult\n actual: $result1"); + switch (expectedResult) { + case SimpleSubclassResult(): + Expect.equals( + expectedResult, + result1, + "Unexpected results for ($cls1,$query1) vs ($cls2,$query2):" + "\n expected: $expectedResult\n actual: $result1"); + case SetSubclassResult(): + Expect.type(result1); + Expect.type(result2); + result1 as SetSubclassResult; + result2 as SetSubclassResult; + Expect.setEquals( + result1.classes, + result2.classes, + "Asymmetric results for ($cls1,$query1) vs ($cls2,$query2):" + "\n a vs b: $result1\n b vs a: $result2"); + Expect.setEquals( + expectedResult.classes, + result1.classes, + "Unexpected results for ($cls1,$query1) vs ($cls2,$query2):" + "\n expected: $expectedResult\n actual: $result1"); } } - check(A, ClassQuery.EXACT, A, ClassQuery.EXACT, SubclassResult.EXACT1); - check(A, ClassQuery.EXACT, A, ClassQuery.SUBCLASS, SubclassResult.EXACT1); - check(A, ClassQuery.EXACT, A, ClassQuery.SUBTYPE, SubclassResult.EXACT1); + check(A, ClassQuery.EXACT, A, ClassQuery.EXACT, SimpleSubclassResult.exact1); check( - A, ClassQuery.SUBCLASS, A, ClassQuery.SUBCLASS, SubclassResult.SUBCLASS1); + A, ClassQuery.EXACT, A, ClassQuery.SUBCLASS, SimpleSubclassResult.exact1); check( - A, ClassQuery.SUBCLASS, A, ClassQuery.SUBTYPE, SubclassResult.SUBCLASS1); - check(A, ClassQuery.SUBTYPE, A, ClassQuery.SUBTYPE, SubclassResult.SUBTYPE1); + A, ClassQuery.EXACT, A, ClassQuery.SUBTYPE, SimpleSubclassResult.exact1); + check(A, ClassQuery.SUBCLASS, A, ClassQuery.SUBCLASS, + SimpleSubclassResult.subclass1); + check(A, ClassQuery.SUBCLASS, A, ClassQuery.SUBTYPE, + SimpleSubclassResult.subclass1); + check(A, ClassQuery.SUBTYPE, A, ClassQuery.SUBTYPE, + SimpleSubclassResult.subtype1); - check(A, ClassQuery.EXACT, B, ClassQuery.EXACT, SubclassResult.EMPTY); - check(A, ClassQuery.EXACT, B, ClassQuery.SUBCLASS, SubclassResult.EMPTY); - check(A, ClassQuery.SUBCLASS, B, ClassQuery.EXACT, SubclassResult.EMPTY); - check(A, ClassQuery.EXACT, B, ClassQuery.SUBTYPE, SubclassResult.EMPTY); - check(A, ClassQuery.SUBTYPE, B, ClassQuery.EXACT, SubclassResult.EMPTY); - check(A, ClassQuery.SUBCLASS, B, ClassQuery.SUBCLASS, SubclassResult.EMPTY); - check(A, ClassQuery.SUBCLASS, B, ClassQuery.SUBTYPE, SubclassResult([G])); - check(A, ClassQuery.SUBTYPE, B, ClassQuery.SUBCLASS, SubclassResult([J])); + check(A, ClassQuery.EXACT, B, ClassQuery.EXACT, SimpleSubclassResult.empty); + check( + A, ClassQuery.EXACT, B, ClassQuery.SUBCLASS, SimpleSubclassResult.empty); + check( + A, ClassQuery.SUBCLASS, B, ClassQuery.EXACT, SimpleSubclassResult.empty); + check(A, ClassQuery.EXACT, B, ClassQuery.SUBTYPE, SimpleSubclassResult.empty); + check(A, ClassQuery.SUBTYPE, B, ClassQuery.EXACT, SimpleSubclassResult.empty); + check(A, ClassQuery.SUBCLASS, B, ClassQuery.SUBCLASS, + SimpleSubclassResult.empty); + check(A, ClassQuery.SUBCLASS, B, ClassQuery.SUBTYPE, SetSubclassResult([G])); + check(A, ClassQuery.SUBTYPE, B, ClassQuery.SUBCLASS, SetSubclassResult([J])); check(A, ClassQuery.SUBTYPE, B, ClassQuery.SUBTYPE, - SubclassResult([F, G, I, J])); + SetSubclassResult([F, G, I, J])); - check(A, ClassQuery.EXACT, C, ClassQuery.EXACT, SubclassResult.EMPTY); - check(A, ClassQuery.EXACT, C, ClassQuery.SUBCLASS, SubclassResult.EMPTY); - check(A, ClassQuery.SUBCLASS, C, ClassQuery.EXACT, SubclassResult.EXACT2); - check(A, ClassQuery.EXACT, C, ClassQuery.SUBTYPE, SubclassResult.EMPTY); - check(A, ClassQuery.SUBTYPE, C, ClassQuery.EXACT, SubclassResult.EXACT2); + check(A, ClassQuery.EXACT, C, ClassQuery.EXACT, SimpleSubclassResult.empty); check( - A, ClassQuery.SUBCLASS, C, ClassQuery.SUBCLASS, SubclassResult.SUBCLASS2); - check(A, ClassQuery.SUBCLASS, C, ClassQuery.SUBTYPE, SubclassResult([C])); + A, ClassQuery.EXACT, C, ClassQuery.SUBCLASS, SimpleSubclassResult.empty); check( - A, ClassQuery.SUBTYPE, C, ClassQuery.SUBCLASS, SubclassResult.SUBCLASS2); - check(A, ClassQuery.SUBTYPE, C, ClassQuery.SUBTYPE, SubclassResult.SUBTYPE2); + A, ClassQuery.SUBCLASS, C, ClassQuery.EXACT, SimpleSubclassResult.exact2); + check(A, ClassQuery.EXACT, C, ClassQuery.SUBTYPE, SimpleSubclassResult.empty); + check( + A, ClassQuery.SUBTYPE, C, ClassQuery.EXACT, SimpleSubclassResult.exact2); + check(A, ClassQuery.SUBCLASS, C, ClassQuery.SUBCLASS, + SimpleSubclassResult.subclass2); + check(A, ClassQuery.SUBCLASS, C, ClassQuery.SUBTYPE, SetSubclassResult([C])); + check(A, ClassQuery.SUBTYPE, C, ClassQuery.SUBCLASS, + SimpleSubclassResult.subclass2); + check(A, ClassQuery.SUBTYPE, C, ClassQuery.SUBTYPE, + SimpleSubclassResult.subtype2); - check(B, ClassQuery.EXACT, C, ClassQuery.EXACT, SubclassResult.EMPTY); - check(B, ClassQuery.EXACT, C, ClassQuery.SUBCLASS, SubclassResult.EMPTY); - check(B, ClassQuery.SUBCLASS, C, ClassQuery.EXACT, SubclassResult.EMPTY); - check(B, ClassQuery.EXACT, C, ClassQuery.SUBTYPE, SubclassResult.EMPTY); - check(B, ClassQuery.SUBTYPE, C, ClassQuery.EXACT, SubclassResult.EMPTY); - check(B, ClassQuery.SUBCLASS, C, ClassQuery.SUBCLASS, SubclassResult.EMPTY); - check(B, ClassQuery.SUBCLASS, C, ClassQuery.SUBTYPE, SubclassResult([])); - check(B, ClassQuery.SUBTYPE, C, ClassQuery.SUBCLASS, SubclassResult([G])); - check(B, ClassQuery.SUBTYPE, C, ClassQuery.SUBTYPE, SubclassResult([F, G])); + check(B, ClassQuery.EXACT, C, ClassQuery.EXACT, SimpleSubclassResult.empty); + check( + B, ClassQuery.EXACT, C, ClassQuery.SUBCLASS, SimpleSubclassResult.empty); + check( + B, ClassQuery.SUBCLASS, C, ClassQuery.EXACT, SimpleSubclassResult.empty); + check(B, ClassQuery.EXACT, C, ClassQuery.SUBTYPE, SimpleSubclassResult.empty); + check(B, ClassQuery.SUBTYPE, C, ClassQuery.EXACT, SimpleSubclassResult.empty); + check(B, ClassQuery.SUBCLASS, C, ClassQuery.SUBCLASS, + SimpleSubclassResult.empty); + check(B, ClassQuery.SUBCLASS, C, ClassQuery.SUBTYPE, SetSubclassResult([])); + check(B, ClassQuery.SUBTYPE, C, ClassQuery.SUBCLASS, SetSubclassResult([G])); + check( + B, ClassQuery.SUBTYPE, C, ClassQuery.SUBTYPE, SetSubclassResult([F, G])); } testLiveMembers() async {