// 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 foundClasses, List 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 foundClasses, List 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 visited = []; 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 expectedClasses, {bool exact: true}) { check('subclassesOf', cls, closedWorld.classHierarchy.subclassesOf(cls), expectedClasses, exact: exact); } void testStrictSubclasses(ClassEntity cls, List 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 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 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 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 subclasses: const [], List subtypes: const []}) { 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 strictSubclasses = new Set(); 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 strictSubtypes = new Set(); 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])); }