blob: bf49a4ff891ee8ebdc88b289a87eb12d2d3442dd [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart = 2.7
library world_test;
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/common/names.dart';
import 'package:compiler/src/common_elements.dart';
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/universe/class_hierarchy.dart';
import 'package:compiler/src/universe/class_set.dart';
import 'package:compiler/src/world.dart' show JClosedWorld;
import '../helpers/type_test_helper.dart';
void main() {
runTests() async {
await testClassSets();
await testProperties();
await testNativeClasses();
await testCommonSubclasses();
}
asyncTest(() async {
print('--test from kernel------------------------------------------------');
await runTests();
});
}
testClassSets() async {
var env = await TypeEnvironment.create(r"""
import 'dart:html' as html;
class A implements X {}
class B {}
class C_Super extends A {}
class C extends C_Super {}
class D implements A {}
class E extends B implements A {}
class F extends Object with A implements B {}
class G extends Object with B, A {}
class X {}
main() {
new A();
new B();
new C();
new D();
new E();
new F();
new G();
html.window;
new html.Worker('');
}
""", testBackendWorld: true);
JClosedWorld closedWorld = env.jClosedWorld;
ElementEnvironment elementEnvironment = closedWorld.elementEnvironment;
ClassEntity Object_ = env.getElement("Object");
ClassEntity A = env.getElement("A");
ClassEntity B = env.getElement("B");
ClassEntity C = env.getElement("C");
ClassEntity D = env.getElement("D");
ClassEntity E = env.getElement("E");
ClassEntity F = env.getElement("F");
ClassEntity G = env.getElement("G");
ClassEntity X = env.getElement("X");
void checkClasses(String property, ClassEntity cls,
Iterable<ClassEntity> foundClasses, List<ClassEntity> expectedClasses,
{bool exact: true}) {
for (ClassEntity expectedClass in expectedClasses) {
Expect.isTrue(
foundClasses.contains(expectedClass),
"Expect $expectedClass in '$property' on $cls. "
"Found:\n ${foundClasses.join('\n ')}\n"
"${closedWorld.classHierarchy.dump(cls)}");
}
if (exact) {
Expect.equals(
expectedClasses.length,
foundClasses.length,
"Unexpected classes "
"${foundClasses.where((c) => !expectedClasses.contains(c))} "
"in '$property' on $cls.\n"
"${closedWorld.classHierarchy.dump(cls)}");
}
}
void check(String property, ClassEntity cls,
Iterable<ClassEntity> foundClasses, List<ClassEntity> expectedClasses,
{bool exact: true,
void forEach(ClassEntity cls, ForEachFunction f),
int getCount(ClassEntity cls)}) {
checkClasses(property, cls, foundClasses, expectedClasses, exact: exact);
if (forEach != null) {
List<ClassEntity> visited = <ClassEntity>[];
forEach(cls, (ClassEntity c) {
visited.add(c);
return IterationStep.CONTINUE;
});
checkClasses('forEach($property)', cls, visited, expectedClasses,
exact: exact);
}
if (getCount != null && exact) {
int count = getCount(cls);
Expect.equals(
expectedClasses.length,
count,
"Unexpected class count in '$property' on $cls.\n"
"${closedWorld.classHierarchy.dump(cls)}");
}
}
void testSubclasses(ClassEntity cls, List<ClassEntity> expectedClasses,
{bool exact: true}) {
check('subclassesOf', cls, closedWorld.classHierarchy.subclassesOf(cls),
expectedClasses,
exact: exact);
}
void testStrictSubclasses(ClassEntity cls, List<ClassEntity> expectedClasses,
{bool exact: true}) {
check('strictSubclassesOf', cls,
closedWorld.classHierarchy.strictSubclassesOf(cls), expectedClasses,
exact: exact,
forEach: closedWorld.classHierarchy.forEachStrictSubclassOf,
getCount: closedWorld.classHierarchy.strictSubclassCount);
}
void testStrictSubtypes(ClassEntity cls, List<ClassEntity> expectedClasses,
{bool exact: true}) {
check('strictSubtypesOf', cls,
closedWorld.classHierarchy.strictSubtypesOf(cls), expectedClasses,
exact: exact,
forEach: closedWorld.classHierarchy.forEachStrictSubtypeOf,
getCount: closedWorld.classHierarchy.strictSubtypeCount);
}
void testMixinUses(ClassEntity cls, List<ClassEntity> expectedClasses,
{bool exact: true}) {
check('mixinUsesOf', cls, closedWorld.mixinUsesOf(cls), expectedClasses,
exact: exact);
}
testSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
testSubclasses(A, [A, C]);
testSubclasses(B, [B, E]);
testSubclasses(C, [C]);
testSubclasses(D, [D]);
testSubclasses(E, [E]);
testSubclasses(F, [F]);
testSubclasses(G, [G]);
testSubclasses(X, []);
testStrictSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
testStrictSubclasses(A, [C]);
testStrictSubclasses(B, [E]);
testStrictSubclasses(C, []);
testStrictSubclasses(D, []);
testStrictSubclasses(E, []);
testStrictSubclasses(F, []);
testStrictSubclasses(G, []);
testStrictSubclasses(X, []);
testStrictSubtypes(Object_, [A, B, C, D, E, F, G], exact: false);
testStrictSubtypes(A, [C, D, E, F, G]);
testStrictSubtypes(B, [E, F, G]);
testStrictSubtypes(C, []);
testStrictSubtypes(D, []);
testStrictSubtypes(E, []);
testStrictSubtypes(F, []);
testStrictSubtypes(G, []);
testStrictSubtypes(X, [A, C, D, E, F, G]);
testMixinUses(Object_, []);
testMixinUses(A, [
elementEnvironment.getSuperClass(F),
elementEnvironment.getSuperClass(G)
]);
testMixinUses(B,
[elementEnvironment.getSuperClass(elementEnvironment.getSuperClass(G))]);
testMixinUses(C, []);
testMixinUses(D, []);
testMixinUses(E, []);
testMixinUses(F, []);
testMixinUses(G, []);
testMixinUses(X, []);
}
testProperties() async {
var env = await TypeEnvironment.create(r"""
class A {}
class A1 extends A {}
class A2 implements A {}
class A3 extends Object with A {}
class B {}
class B1 extends B {}
class B2 implements B {}
class B3 extends Object with B {}
class C {}
class C1 extends C {}
class C2 implements C {}
class C3 extends Object with C {}
class D {}
class D1 extends D {}
class D2 implements D {}
class D3 extends Object with D {}
class E {}
class E1 extends E {}
class E2 implements E {}
class E3 extends Object with E {}
class F {}
class F1 extends F {}
class F2 implements F {}
class F3 extends Object with F {}
class G {}
class G1 extends G {}
class G2 extends G1 {}
class G3 extends G2 implements G {}
class G4 extends G2 with G {}
class H {}
class H1 extends H {}
class H2 extends H1 {}
class H3 extends H2 implements H {}
class H4 extends H2 with H {}
main() {
new B();
new C1();
new D2();
new E3();
new F1();
new F2();
new G2();
new G3();
new H4();
}
""", testBackendWorld: true);
JClosedWorld closedWorld = env.jClosedWorld;
check(String name, {bool hasStrictSubtype, bool hasOnlySubclasses}) {
ClassEntity cls = env.getElement(name);
Expect.equals(
hasStrictSubtype,
closedWorld.classHierarchy.hasAnyStrictSubtype(cls),
"Unexpected hasAnyStrictSubtype property on $cls.");
Expect.equals(
hasOnlySubclasses,
closedWorld.classHierarchy.hasOnlySubclasses(cls),
"Unexpected hasOnlySubclasses property on $cls.");
}
check("Object", hasStrictSubtype: true, hasOnlySubclasses: true);
// No instantiated Ax classes.
check("A", hasStrictSubtype: false, hasOnlySubclasses: true);
check("A1", hasStrictSubtype: false, hasOnlySubclasses: true);
check("A2", hasStrictSubtype: false, hasOnlySubclasses: true);
check("A3", hasStrictSubtype: false, hasOnlySubclasses: true);
// class B instantiated
check("B", hasStrictSubtype: false, hasOnlySubclasses: true);
check("B1", hasStrictSubtype: false, hasOnlySubclasses: true);
check("B2", hasStrictSubtype: false, hasOnlySubclasses: true);
check("B3", hasStrictSubtype: false, hasOnlySubclasses: true);
// class C1 extends C instantiated
check("C", hasStrictSubtype: true, hasOnlySubclasses: true);
check("C1", hasStrictSubtype: false, hasOnlySubclasses: true);
check("C2", hasStrictSubtype: false, hasOnlySubclasses: true);
check("C3", hasStrictSubtype: false, hasOnlySubclasses: true);
// class D2 implements D instantiated
check("D", hasStrictSubtype: true, hasOnlySubclasses: false);
check("D1", hasStrictSubtype: false, hasOnlySubclasses: true);
check("D2", hasStrictSubtype: false, hasOnlySubclasses: true);
check("D3", hasStrictSubtype: false, hasOnlySubclasses: true);
// class E2 extends Object with E instantiated
check("E", hasStrictSubtype: true, hasOnlySubclasses: false);
check("E1", hasStrictSubtype: false, hasOnlySubclasses: true);
check("E2", hasStrictSubtype: false, hasOnlySubclasses: true);
check("E3", hasStrictSubtype: false, hasOnlySubclasses: true);
// class F1 extends F instantiated
// class F2 implements F instantiated
check("F", hasStrictSubtype: true, hasOnlySubclasses: false);
check("F1", hasStrictSubtype: false, hasOnlySubclasses: true);
check("F2", hasStrictSubtype: false, hasOnlySubclasses: true);
check("F3", hasStrictSubtype: false, hasOnlySubclasses: true);
// class G2 extends G1 extends G instantiated
// class G3 extends G2 extends G1 extends G instantiated
check("G", hasStrictSubtype: true, hasOnlySubclasses: true);
check("G1", hasStrictSubtype: true, hasOnlySubclasses: true);
check("G2", hasStrictSubtype: true, hasOnlySubclasses: true);
check("G3", hasStrictSubtype: false, hasOnlySubclasses: true);
check("G4", hasStrictSubtype: false, hasOnlySubclasses: true);
// class H4 extends H2 with H extends H1 extends H instantiated
check("H", hasStrictSubtype: true, hasOnlySubclasses: true);
check("H1", hasStrictSubtype: true, hasOnlySubclasses: true);
check("H2", hasStrictSubtype: true, hasOnlySubclasses: true);
check("H3", hasStrictSubtype: false, hasOnlySubclasses: true);
check("H4", hasStrictSubtype: false, hasOnlySubclasses: true);
}
testNativeClasses() async {
var env = await TypeEnvironment.create(r"""
import 'dart:html' as html;
main() {
html.window; // Creates 'Window'.
new html.Worker(''); // Creates 'Worker'.
new html.CanvasElement() // Creates CanvasElement
..getContext(''); // Creates CanvasRenderingContext2D
}
""", testBackendWorld: true);
JClosedWorld closedWorld = env.jClosedWorld;
ElementEnvironment elementEnvironment = closedWorld.elementEnvironment;
LibraryEntity dart_html = elementEnvironment.lookupLibrary(Uris.dart_html);
ClassEntity clsEventTarget =
elementEnvironment.lookupClass(dart_html, 'EventTarget');
ClassEntity clsWindow = elementEnvironment.lookupClass(dart_html, 'Window');
ClassEntity clsAbstractWorker =
elementEnvironment.lookupClass(dart_html, 'AbstractWorker');
ClassEntity clsWorker = elementEnvironment.lookupClass(dart_html, 'Worker');
ClassEntity clsCanvasElement =
elementEnvironment.lookupClass(dart_html, 'CanvasElement');
ClassEntity clsCanvasRenderingContext =
elementEnvironment.lookupClass(dart_html, 'CanvasRenderingContext');
ClassEntity clsCanvasRenderingContext2D =
elementEnvironment.lookupClass(dart_html, 'CanvasRenderingContext2D');
List<ClassEntity> allClasses = [
clsEventTarget,
clsWindow,
clsAbstractWorker,
clsWorker,
clsCanvasElement,
clsCanvasRenderingContext,
clsCanvasRenderingContext2D
];
check(ClassEntity cls,
{bool isDirectlyInstantiated,
bool isAbstractlyInstantiated,
bool isIndirectlyInstantiated,
bool hasStrictSubtype,
bool hasOnlySubclasses,
ClassEntity lubOfInstantiatedSubclasses,
ClassEntity lubOfInstantiatedSubtypes,
int instantiatedSubclassCount,
int instantiatedSubtypeCount,
List<ClassEntity> subclasses: const <ClassEntity>[],
List<ClassEntity> subtypes: const <ClassEntity>[]}) {
ClassSet classSet = closedWorld.classHierarchy.getClassSet(cls);
ClassHierarchyNode node = classSet.node;
String dumpText = '\n${closedWorld.classHierarchy.dump(cls)}';
Expect.equals(
isDirectlyInstantiated,
closedWorld.classHierarchy.isDirectlyInstantiated(cls),
"Unexpected isDirectlyInstantiated property on $cls.$dumpText");
Expect.equals(
isAbstractlyInstantiated,
closedWorld.classHierarchy.isAbstractlyInstantiated(cls),
"Unexpected isAbstractlyInstantiated property on $cls.$dumpText");
Expect.equals(
isIndirectlyInstantiated,
closedWorld.classHierarchy.isIndirectlyInstantiated(cls),
"Unexpected isIndirectlyInstantiated property on $cls.$dumpText");
Expect.equals(
hasStrictSubtype,
closedWorld.classHierarchy.hasAnyStrictSubtype(cls),
"Unexpected hasAnyStrictSubtype property on $cls.$dumpText");
Expect.equals(
hasOnlySubclasses,
closedWorld.classHierarchy.hasOnlySubclasses(cls),
"Unexpected hasOnlySubclasses property on $cls.$dumpText");
Expect.equals(
lubOfInstantiatedSubclasses,
node.getLubOfInstantiatedSubclasses(),
"Unexpected getLubOfInstantiatedSubclasses() result on $cls.$dumpText");
Expect.equals(
lubOfInstantiatedSubtypes,
classSet.getLubOfInstantiatedSubtypes(),
"Unexpected getLubOfInstantiatedSubtypes() result on $cls.$dumpText");
if (instantiatedSubclassCount != null) {
Expect.equals(instantiatedSubclassCount, node.instantiatedSubclassCount,
"Unexpected instantiatedSubclassCount property on $cls.$dumpText");
}
if (instantiatedSubtypeCount != null) {
Expect.equals(instantiatedSubtypeCount, classSet.instantiatedSubtypeCount,
"Unexpected instantiatedSubtypeCount property on $cls.$dumpText");
}
for (ClassEntity other in allClasses) {
if (other == cls) continue;
if (!closedWorld.classHierarchy.isExplicitlyInstantiated(other)) continue;
Expect.equals(
subclasses.contains(other),
closedWorld.classHierarchy.isSubclassOf(other, cls),
"Unexpected subclass relation between $other and $cls.");
Expect.equals(
subtypes.contains(other),
closedWorld.classHierarchy.isSubtypeOf(other, cls),
"Unexpected subtype relation between $other and $cls.");
}
Set<ClassEntity> strictSubclasses = new Set<ClassEntity>();
closedWorld.classHierarchy.forEachStrictSubclassOf(cls,
(ClassEntity other) {
if (allClasses.contains(other)) {
strictSubclasses.add(other);
}
return IterationStep.CONTINUE;
});
Expect.setEquals(subclasses, strictSubclasses,
"Unexpected strict subclasses of $cls: ${strictSubclasses}.");
Set<ClassEntity> strictSubtypes = new Set<ClassEntity>();
closedWorld.classHierarchy.forEachStrictSubtypeOf(cls, (ClassEntity other) {
if (allClasses.contains(other)) {
strictSubtypes.add(other);
}
return IterationStep.CONTINUE;
});
Expect.setEquals(subtypes, strictSubtypes,
"Unexpected strict subtypes of $cls: $strictSubtypes.");
}
// Extended by Window.
check(clsEventTarget,
isDirectlyInstantiated: false,
isAbstractlyInstantiated: false,
isIndirectlyInstantiated: true,
hasStrictSubtype: true,
hasOnlySubclasses: true,
lubOfInstantiatedSubclasses: clsEventTarget,
lubOfInstantiatedSubtypes: clsEventTarget,
// May vary with implementation, do no test.
instantiatedSubclassCount: null,
instantiatedSubtypeCount: null,
subclasses: [clsWindow, clsCanvasElement, clsWorker],
subtypes: [clsWindow, clsCanvasElement, clsWorker]);
// Created by 'html.window'.
check(clsWindow,
isDirectlyInstantiated: false,
isAbstractlyInstantiated: true,
isIndirectlyInstantiated: false,
hasStrictSubtype: false,
hasOnlySubclasses: true,
lubOfInstantiatedSubclasses: clsWindow,
lubOfInstantiatedSubtypes: clsWindow,
instantiatedSubclassCount: 0,
instantiatedSubtypeCount: 0);
// Implemented by 'Worker'.
check(clsAbstractWorker,
isDirectlyInstantiated: false,
isAbstractlyInstantiated: false,
isIndirectlyInstantiated: false,
hasStrictSubtype: true,
hasOnlySubclasses: false,
lubOfInstantiatedSubclasses: null,
lubOfInstantiatedSubtypes: clsWorker,
instantiatedSubclassCount: 0,
instantiatedSubtypeCount: 1,
subtypes: [clsWorker]);
// Created by 'new html.Worker'.
check(clsWorker,
isDirectlyInstantiated: false,
isAbstractlyInstantiated: true,
isIndirectlyInstantiated: false,
hasStrictSubtype: false,
hasOnlySubclasses: true,
lubOfInstantiatedSubclasses: clsWorker,
lubOfInstantiatedSubtypes: clsWorker,
instantiatedSubclassCount: 0,
instantiatedSubtypeCount: 0);
// Created by 'new html.CanvasElement'.
check(clsCanvasElement,
isDirectlyInstantiated: false,
isAbstractlyInstantiated: true,
isIndirectlyInstantiated: false,
hasStrictSubtype: false,
hasOnlySubclasses: true,
lubOfInstantiatedSubclasses: clsCanvasElement,
lubOfInstantiatedSubtypes: clsCanvasElement,
instantiatedSubclassCount: 0,
instantiatedSubtypeCount: 0);
// Implemented by CanvasRenderingContext2D and RenderingContext.
check(clsCanvasRenderingContext,
isDirectlyInstantiated: false,
isAbstractlyInstantiated: false,
isIndirectlyInstantiated: false,
hasStrictSubtype: true,
hasOnlySubclasses: false,
lubOfInstantiatedSubclasses: null,
lubOfInstantiatedSubtypes: clsCanvasRenderingContext,
instantiatedSubclassCount: 0,
instantiatedSubtypeCount: 2,
subtypes: [clsCanvasRenderingContext2D]);
// Created by 'html.CanvasElement.getContext'.
check(clsCanvasRenderingContext2D,
isDirectlyInstantiated: false,
isAbstractlyInstantiated: true,
isIndirectlyInstantiated: false,
hasStrictSubtype: false,
hasOnlySubclasses: true,
lubOfInstantiatedSubclasses: clsCanvasRenderingContext2D,
lubOfInstantiatedSubtypes: clsCanvasRenderingContext2D,
instantiatedSubclassCount: 0,
instantiatedSubtypeCount: 0);
}
testCommonSubclasses() async {
var env = await TypeEnvironment.create(r"""
class A {}
class B {}
class C extends A {}
class D implements A {}
class E extends B {}
class F implements C, E {}
class G extends C implements E {}
class H implements C {}
class I extends D implements E {}
class J extends E implements D {}
main() {
new A();
new B();
new C();
new D();
new E();
new F();
new G();
new H();
new I();
new J();
}
""", testBackendWorld: true);
JClosedWorld closedWorld = env.jClosedWorld;
ClassEntity A = env.getElement("A");
ClassEntity B = env.getElement("B");
ClassEntity C = env.getElement("C");
ClassEntity F = env.getElement("F");
ClassEntity G = env.getElement("G");
ClassEntity I = env.getElement("I");
ClassEntity J = env.getElement("J");
ClassQuery toClassQuery(SubclassResultKind kind, ClassEntity cls1,
ClassQuery query1, ClassEntity cls2, ClassQuery query2) {
switch (kind) {
case SubclassResultKind.EMPTY:
return null;
case SubclassResultKind.EXACT1:
return ClassQuery.EXACT;
case SubclassResultKind.EXACT2:
return ClassQuery.EXACT;
case SubclassResultKind.SUBCLASS1:
return ClassQuery.SUBCLASS;
case SubclassResultKind.SUBCLASS2:
return ClassQuery.SUBCLASS;
case SubclassResultKind.SUBTYPE1:
return ClassQuery.SUBTYPE;
case SubclassResultKind.SUBTYPE2:
return ClassQuery.SUBTYPE;
case SubclassResultKind.SET:
default:
return null;
}
}
ClassEntity toClassEntity(SubclassResultKind kind, ClassEntity cls1,
ClassQuery query1, ClassEntity cls2, ClassQuery query2) {
switch (kind) {
case SubclassResultKind.EMPTY:
return null;
case SubclassResultKind.EXACT1:
return cls1;
case SubclassResultKind.EXACT2:
return cls2;
case SubclassResultKind.SUBCLASS1:
return cls1;
case SubclassResultKind.SUBCLASS2:
return cls2;
case SubclassResultKind.SUBTYPE1:
return cls1;
case SubclassResultKind.SUBTYPE2:
return cls2;
case SubclassResultKind.SET:
default:
return null;
}
}
void check(ClassEntity cls1, ClassQuery query1, ClassEntity cls2,
ClassQuery query2, SubclassResult expectedResult) {
SubclassResult result1 =
closedWorld.classHierarchy.commonSubclasses(cls1, query1, cls2, query2);
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),
"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),
"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");
}
}
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.SUBCLASS, A, ClassQuery.SUBCLASS, SubclassResult.SUBCLASS1);
check(
A, ClassQuery.SUBCLASS, A, ClassQuery.SUBTYPE, SubclassResult.SUBCLASS1);
check(A, ClassQuery.SUBTYPE, A, ClassQuery.SUBTYPE, SubclassResult.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, new SubclassResult([G]));
check(A, ClassQuery.SUBTYPE, B, ClassQuery.SUBCLASS, new SubclassResult([J]));
check(A, ClassQuery.SUBTYPE, B, ClassQuery.SUBTYPE,
new SubclassResult([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.SUBCLASS, C, ClassQuery.SUBCLASS, SubclassResult.SUBCLASS2);
check(A, ClassQuery.SUBCLASS, C, ClassQuery.SUBTYPE, new SubclassResult([C]));
check(
A, ClassQuery.SUBTYPE, C, ClassQuery.SUBCLASS, SubclassResult.SUBCLASS2);
check(A, ClassQuery.SUBTYPE, C, ClassQuery.SUBTYPE, SubclassResult.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, new SubclassResult([]));
check(B, ClassQuery.SUBTYPE, C, ClassQuery.SUBCLASS, new SubclassResult([G]));
check(
B, ClassQuery.SUBTYPE, C, ClassQuery.SUBTYPE, new SubclassResult([F, G]));
}