[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 <natebiggs@google.com>
Commit-Queue: Mayank Patke <fishythefish@google.com>
This commit is contained in:
Mayank Patke 2024-06-13 19:25:28 +00:00 committed by Commit Queue
parent cc073a0782
commit 0ddba91190
4 changed files with 153 additions and 155 deletions

View file

@ -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<FlatTypeMask> masks = List.from(result.classes.map(
(ClassEntity cls) =>
TypeMask.nonNullSubclass(cls, domain._closedWorld)));
List<FlatTypeMask> 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,

View file

@ -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;
}

View file

@ -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<ClassEntity> 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<ClassEntity>? _classes;
/// Subclasses of a set of classes in common.
class SetSubclassResult implements SubclassResult {
final List<ClassEntity> classes;
List<ClassEntity> 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)';
}

View file

@ -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<SetSubclassResult>(result1);
Expect.type<SetSubclassResult>(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 {