Move remaining functionality from ClassWorld to ClosedWorld

... and rename ClassWorld to World.

R=het@google.com

Review URL: https://codereview.chromium.org/2366363002 .
This commit is contained in:
Johnni Winther 2016-09-27 10:23:03 +02:00
parent ce596133ad
commit a1cd695612
28 changed files with 212 additions and 228 deletions

View file

@ -1352,7 +1352,7 @@ class SimpleTypeInferrerVisitor<T>
// In erroneous code the number of arguments in the selector might not
// match the function element.
// TODO(polux): return nonNullEmpty and check it doesn't break anything
if (!selector.applies(target, compiler.backend) ||
if (!selector.applies(target) ||
(mask != null &&
!mask.canHit(target, selector, compiler.closedWorld))) {
return types.dynamicType;

View file

@ -24,7 +24,7 @@ import '../types/masks.dart'
ValueTypeMask;
import '../universe/selector.dart' show Selector;
import '../util/util.dart' show ImmutableEmptySet, Setlet;
import '../world.dart' show ClassWorld;
import '../world.dart' show ClosedWorld;
import 'debug.dart' as debug;
import 'inferrer_visitor.dart' show ArgumentsTypes;
import 'type_graph_inferrer.dart'
@ -867,26 +867,27 @@ class DynamicCallSiteTypeInformation extends CallSiteTypeInformation {
*/
TypeInformation handleIntrisifiedSelector(
Selector selector, TypeMask mask, TypeGraphInferrerEngine inferrer) {
ClassWorld classWorld = inferrer.closedWorld;
if (!classWorld.backend.intImplementation.isResolved) return null;
ClosedWorld closedWorld = inferrer.closedWorld;
if (!closedWorld.backend.intImplementation.isResolved) return null;
if (mask == null) return null;
if (!mask.containsOnlyInt(classWorld)) {
if (!mask.containsOnlyInt(closedWorld)) {
return null;
}
if (!selector.isCall && !selector.isOperator) return null;
if (!arguments.named.isEmpty) return null;
if (arguments.positional.length > 1) return null;
ClassElement uint31Implementation = classWorld.backend.uint31Implementation;
bool isInt(info) => info.type.containsOnlyInt(classWorld);
ClassElement uint31Implementation =
closedWorld.backend.uint31Implementation;
bool isInt(info) => info.type.containsOnlyInt(closedWorld);
bool isEmpty(info) => info.type.isEmpty;
bool isUInt31(info) {
return info.type.satisfies(uint31Implementation, classWorld);
return info.type.satisfies(uint31Implementation, closedWorld);
}
bool isPositiveInt(info) {
return info.type
.satisfies(classWorld.backend.positiveIntImplementation, classWorld);
return info.type.satisfies(
closedWorld.backend.positiveIntImplementation, closedWorld);
}
TypeInformation tryLater() => inferrer.types.nonNullEmptyType;

View file

@ -925,7 +925,7 @@ class JavaScriptBackend extends Backend {
if (elements == null) return false;
if (elements.isEmpty) return false;
return elements.any((element) {
return selector.applies(element, this) &&
return selector.applies(element) &&
(mask == null ||
mask.canHit(element, selector, compiler.closedWorld));
});

View file

@ -88,7 +88,7 @@ class CodegenEnqueuer implements Enqueuer {
Registry get mirrorDependencies => _compiler.mirrorDependencies;
ClassWorld get _world => _compiler.closedWorld;
ClosedWorld get _world => _compiler.closedWorld;
bool get queueIsEmpty => queue.isEmpty;

View file

@ -92,7 +92,7 @@ class ClassStubGenerator {
Set<Selector> generatedSelectors = new Set<Selector>();
for (Selector selector in selectors.keys) {
if (generatedSelectors.contains(selector)) continue;
if (!selector.appliesUnnamed(member, backend)) continue;
if (!selector.appliesUnnamed(member)) continue;
if (selectors[selector].applies(member, selector, compiler.closedWorld)) {
generatedSelectors.add(selector);

View file

@ -248,7 +248,7 @@ class ParameterStubGenerator {
new Selector.call(member.memberName, selector.callStructure);
renamedCallSelectors.add(renamedSelector);
if (!renamedSelector.appliesUnnamed(member, compiler.backend)) {
if (!renamedSelector.appliesUnnamed(member)) {
continue;
}
@ -266,7 +266,7 @@ class ParameterStubGenerator {
// call-selectors (and they are in the renamedCallSelectors set.
for (Selector selector in selectors.keys) {
if (renamedCallSelectors.contains(selector)) continue;
if (!selector.appliesUnnamed(member, backend)) continue;
if (!selector.appliesUnnamed(member)) continue;
if (!selectors[selector]
.applies(member, selector, compiler.closedWorld)) {
continue;

View file

@ -332,7 +332,7 @@ class SsaBuilder extends ast.Visitor
*/
List<HInstruction> completeDynamicSendArgumentsList(Selector selector,
FunctionElement function, List<HInstruction> providedArguments) {
assert(selector.applies(function, backend));
assert(selector.applies(function));
FunctionSignature signature = function.functionSignature;
List<HInstruction> compiledArguments = new List<HInstruction>(
signature.parameterCount + 1); // Plus one for receiver.
@ -426,7 +426,7 @@ class SsaBuilder extends ast.Visitor
element.isGenerativeConstructorBody,
message: "Missing selector for inlining of $element."));
if (selector != null) {
if (!selector.applies(function, backend)) return false;
if (!selector.applies(function)) return false;
if (mask != null &&
!mask.canHit(function, selector, compiler.closedWorld)) {
return false;
@ -3201,7 +3201,7 @@ class SsaBuilder extends ast.Visitor
// TODO(5347): Try to avoid the need for calling [implementation] before
// calling [makeStaticArgumentList].
Selector selector = elements.getSelector(node);
assert(invariant(node, selector.applies(function.implementation, backend),
assert(invariant(node, selector.applies(function.implementation),
message: "$selector does not apply to ${function.implementation}"));
List<HInstruction> inputs = makeStaticArgumentList(
selector.callStructure, node.arguments, function.implementation);
@ -4453,8 +4453,7 @@ class SsaBuilder extends ast.Visitor
List<HInstruction> setterInputs = <HInstruction>[];
void generateSuperSendSet() {
Selector setterSelector = elements.getSelector(node);
if (Elements.isUnresolved(element) ||
!setterSelector.applies(element, compiler.backend)) {
if (Elements.isUnresolved(element) || !setterSelector.applies(element)) {
generateSuperNoSuchMethodSend(node, setterSelector, setterInputs);
pop();
} else {

View file

@ -11,7 +11,7 @@ import '../js_backend/backend_helpers.dart' show BackendHelpers;
import '../js_backend/js_backend.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show ClassWorld;
import '../world.dart' show ClosedWorld;
import 'nodes.dart';
import 'optimize.dart';
@ -49,7 +49,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor
BackendHelpers get helpers => backend.helpers;
ClassWorld get classWorld => compiler.closedWorld;
ClosedWorld get closedWorld => compiler.closedWorld;
void visitGraph(HGraph graph) {
this.graph = graph;
@ -109,8 +109,8 @@ class SsaSimplifyInterceptors extends HBaseVisitor
// All intercepted classes extend `Interceptor`, so if the receiver can't be
// a class extending `Interceptor` then it can be called directly.
return new TypeMask.nonNullSubclass(helpers.jsInterceptorClass, classWorld)
.isDisjoint(receiver.instructionType, classWorld);
return new TypeMask.nonNullSubclass(helpers.jsInterceptorClass, closedWorld)
.isDisjoint(receiver.instructionType, closedWorld);
}
HInstruction tryComputeConstantInterceptor(
@ -145,17 +145,17 @@ class SsaSimplifyInterceptors extends HBaseVisitor
if (type.isNull) {
return helpers.jsNullClass;
}
} else if (type.containsOnlyInt(classWorld)) {
} else if (type.containsOnlyInt(closedWorld)) {
return helpers.jsIntClass;
} else if (type.containsOnlyDouble(classWorld)) {
} else if (type.containsOnlyDouble(closedWorld)) {
return helpers.jsDoubleClass;
} else if (type.containsOnlyBool(classWorld)) {
} else if (type.containsOnlyBool(closedWorld)) {
return helpers.jsBoolClass;
} else if (type.containsOnlyString(classWorld)) {
} else if (type.containsOnlyString(closedWorld)) {
return helpers.jsStringClass;
} else if (type.satisfies(helpers.jsArrayClass, classWorld)) {
} else if (type.satisfies(helpers.jsArrayClass, closedWorld)) {
return helpers.jsArrayClass;
} else if (type.containsOnlyNum(classWorld) &&
} else if (type.containsOnlyNum(closedWorld) &&
!interceptedClasses.contains(helpers.jsIntClass) &&
!interceptedClasses.contains(helpers.jsDoubleClass)) {
// If the method being intercepted is not defined in [int] or [double] we
@ -174,7 +174,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor
// for a subclass or call methods defined on a subclass. Provided the
// code is completely insensitive to the specific instance subclasses, we
// can use the non-leaf class directly.
ClassElement element = type.singleClass(classWorld);
ClassElement element = type.singleClass(closedWorld);
if (element != null && backend.isNative(element)) {
return element;
}

View file

@ -378,7 +378,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
ClosedWorld world = compiler.closedWorld;
bool applies(Element element) {
return selector.applies(element, backend) &&
return selector.applies(element) &&
(mask == null || mask.canHit(element, selector, world));
}
@ -427,7 +427,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
return result;
}
} else if (selector.isGetter) {
if (selector.applies(helpers.jsIndexableLength, backend)) {
if (selector.applies(helpers.jsIndexableLength)) {
HInstruction optimized = tryOptimizeLengthInterceptedGetter(node);
if (optimized != null) return optimized;
}

View file

@ -9,7 +9,7 @@ import '../native/native.dart' as native;
import '../tree/tree.dart' as ast;
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show ClassWorld;
import '../world.dart' show ClosedWorld;
class TypeMaskFactory {
static TypeMask inferredReturnTypeForElement(
@ -34,7 +34,7 @@ class TypeMaskFactory {
var typesReturned = nativeBehavior.typesReturned;
if (typesReturned.isEmpty) return compiler.commonMasks.dynamicType;
ClassWorld world = compiler.closedWorld;
ClosedWorld world = compiler.closedWorld;
CommonMasks commonMasks = compiler.commonMasks;
CoreClasses coreClasses = compiler.coreClasses;

View file

@ -7,7 +7,7 @@ import '../elements/elements.dart';
import '../js_backend/js_backend.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show ClassWorld;
import '../world.dart' show ClosedWorld;
import 'nodes.dart';
import 'optimize.dart';
@ -18,13 +18,13 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
new Map<HInstruction, Function>();
final Compiler compiler;
final ClassWorld classWorld;
final ClosedWorld closedWorld;
JavaScriptBackend get backend => compiler.backend;
String get name => 'type propagator';
SsaTypePropagator(Compiler compiler)
: this.compiler = compiler,
this.classWorld = compiler.closedWorld;
this.closedWorld = compiler.closedWorld;
TypeMask computeType(HInstruction instruction) {
return instruction.accept(this);
@ -160,7 +160,7 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
TypeMask candidateType = backend.emptyType;
for (int i = 0, length = phi.inputs.length; i < length; i++) {
TypeMask inputType = phi.inputs[i].instructionType;
candidateType = candidateType.union(inputType, classWorld);
candidateType = candidateType.union(inputType, closedWorld);
}
return candidateType;
}
@ -173,25 +173,25 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
// We must make sure a type conversion for receiver or argument check
// does not try to do an int check, because an int check is not enough.
// We only do an int check if the input is integer or null.
if (checkedType.containsOnlyNum(classWorld) &&
!checkedType.containsOnlyDouble(classWorld) &&
if (checkedType.containsOnlyNum(closedWorld) &&
!checkedType.containsOnlyDouble(closedWorld) &&
input.isIntegerOrNull(compiler)) {
instruction.checkedType = backend.intType;
} else if (checkedType.containsOnlyInt(classWorld) &&
} else if (checkedType.containsOnlyInt(closedWorld) &&
!input.isIntegerOrNull(compiler)) {
instruction.checkedType = backend.numType;
}
}
TypeMask outputType = checkedType.intersection(inputType, classWorld);
TypeMask outputType = checkedType.intersection(inputType, closedWorld);
if (outputType.isEmpty) {
// Intersection of double and integer conflicts (is empty), but JS numbers
// can be both int and double at the same time. For example, the input
// can be a literal double '8.0' that is marked as an integer (because 'is
// int' will return 'true'). What we really need to do is make the
// overlap between int and double values explicit in the TypeMask system.
if (inputType.containsOnlyInt(classWorld) &&
checkedType.containsOnlyDouble(classWorld)) {
if (inputType.containsOnlyInt(closedWorld) &&
checkedType.containsOnlyDouble(closedWorld)) {
if (inputType.isNullable && checkedType.isNullable) {
outputType = backend.doubleType.nullable();
} else {
@ -221,7 +221,7 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
HInstruction input = instruction.checkedInput;
TypeMask inputType = input.instructionType;
TypeMask outputType =
instruction.knownType.intersection(inputType, classWorld);
instruction.knownType.intersection(inputType, closedWorld);
if (inputType != outputType) {
input.replaceAllUsersDominatedBy(instruction.next, instruction);
}
@ -244,7 +244,7 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
// In some cases, we want the receiver to be an integer,
// but that does not mean we will get a NoSuchMethodError
// if it's not: the receiver could be a double.
if (type.containsOnlyInt(classWorld)) {
if (type.containsOnlyInt(closedWorld)) {
// If the instruction's type is integer or null, the codegen
// will emit a null check, which is enough to know if it will
// hit a noSuchMethod.
@ -274,12 +274,12 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
Element target = targets.first;
ClassElement cls = target.enclosingClass;
TypeMask type =
new TypeMask.nonNullSubclass(cls.declaration, classWorld);
new TypeMask.nonNullSubclass(cls.declaration, closedWorld);
// TODO(ngeoffray): We currently only optimize on primitive
// types.
if (!type.satisfies(backend.helpers.jsIndexableClass, classWorld) &&
!type.containsOnlyNum(classWorld) &&
!type.containsOnlyBool(classWorld)) {
if (!type.satisfies(backend.helpers.jsIndexableClass, closedWorld) &&
!type.containsOnlyNum(closedWorld) &&
!type.containsOnlyBool(closedWorld)) {
return false;
}
if (!isCheckEnoughForNsmOrAe(receiver, type)) return false;
@ -373,7 +373,7 @@ class SsaTypePropagator extends HBaseVisitor implements OptimizationPhase {
TypeMask computeNewType() {
newType = compiler.closedWorld.allFunctions
.receiverType(instruction.selector, instruction.mask);
newType = newType.intersection(receiverType, classWorld);
newType = newType.intersection(receiverType, closedWorld);
return newType;
}

View file

@ -50,13 +50,13 @@ class ContainerTypeMask extends ForwardingTypeMask {
length == other.length;
}
TypeMask intersection(TypeMask other, ClassWorld classWorld) {
TypeMask forwardIntersection = forwardTo.intersection(other, classWorld);
TypeMask intersection(TypeMask other, ClosedWorld closedWorld) {
TypeMask forwardIntersection = forwardTo.intersection(other, closedWorld);
if (forwardIntersection.isEmptyOrNull) return forwardIntersection;
return forwardIntersection.isNullable ? nullable() : nonNullable();
}
TypeMask union(other, ClassWorld classWorld) {
TypeMask union(other, ClosedWorld closedWorld) {
if (this == other) {
return this;
} else if (equalsDisregardNull(other)) {
@ -67,9 +67,9 @@ class ContainerTypeMask extends ForwardingTypeMask {
elementType != null &&
other.elementType != null) {
TypeMask newElementType =
elementType.union(other.elementType, classWorld);
elementType.union(other.elementType, closedWorld);
int newLength = (length == other.length) ? length : null;
TypeMask newForwardTo = forwardTo.union(other.forwardTo, classWorld);
TypeMask newForwardTo = forwardTo.union(other.forwardTo, closedWorld);
return new ContainerTypeMask(
newForwardTo,
allocationNode == other.allocationNode ? allocationNode : null,
@ -79,7 +79,7 @@ class ContainerTypeMask extends ForwardingTypeMask {
newElementType,
newLength);
} else {
return forwardTo.union(other, classWorld);
return forwardTo.union(other, closedWorld);
}
}

View file

@ -47,13 +47,13 @@ class DictionaryTypeMask extends MapTypeMask {
(k) => typeMap.containsKey(k) && typeMap[k] == other.typeMap[k]);
}
TypeMask intersection(TypeMask other, ClassWorld classWorld) {
TypeMask forwardIntersection = forwardTo.intersection(other, classWorld);
TypeMask intersection(TypeMask other, ClosedWorld closedWorld) {
TypeMask forwardIntersection = forwardTo.intersection(other, closedWorld);
if (forwardIntersection.isEmptyOrNull) return forwardIntersection;
return forwardIntersection.isNullable ? nullable() : nonNullable();
}
TypeMask union(other, ClassWorld classWorld) {
TypeMask union(other, ClosedWorld closedWorld) {
if (this == other) {
return this;
} else if (equalsDisregardNull(other)) {
@ -61,9 +61,9 @@ class DictionaryTypeMask extends MapTypeMask {
} else if (other.isEmptyOrNull) {
return other.isNullable ? this.nullable() : this;
} else if (other.isDictionary) {
TypeMask newForwardTo = forwardTo.union(other.forwardTo, classWorld);
TypeMask newKeyType = keyType.union(other.keyType, classWorld);
TypeMask newValueType = valueType.union(other.valueType, classWorld);
TypeMask newForwardTo = forwardTo.union(other.forwardTo, closedWorld);
TypeMask newKeyType = keyType.union(other.keyType, closedWorld);
TypeMask newValueType = valueType.union(other.valueType, closedWorld);
Map<String, TypeMask> mappings = <String, TypeMask>{};
typeMap.forEach((k, v) {
if (!other.typeMap.containsKey(k)) {
@ -72,7 +72,7 @@ class DictionaryTypeMask extends MapTypeMask {
});
other.typeMap.forEach((k, v) {
if (typeMap.containsKey(k)) {
mappings[k] = v.union(typeMap[k], classWorld);
mappings[k] = v.union(typeMap[k], closedWorld);
} else {
mappings[k] = v.nullable();
}
@ -82,13 +82,13 @@ class DictionaryTypeMask extends MapTypeMask {
} else if (other.isMap &&
(other.keyType != null) &&
(other.valueType != null)) {
TypeMask newForwardTo = forwardTo.union(other.forwardTo, classWorld);
TypeMask newKeyType = keyType.union(other.keyType, classWorld);
TypeMask newValueType = valueType.union(other.valueType, classWorld);
TypeMask newForwardTo = forwardTo.union(other.forwardTo, closedWorld);
TypeMask newKeyType = keyType.union(other.keyType, closedWorld);
TypeMask newValueType = valueType.union(other.valueType, closedWorld);
return new MapTypeMask(
newForwardTo, null, null, newKeyType, newValueType);
} else {
return forwardTo.union(other, classWorld);
return forwardTo.union(other, closedWorld);
}
}

View file

@ -565,13 +565,11 @@ class FlatTypeMask implements TypeMask {
} else if (isExact) {
return hasElementIn(self, selector, element);
} else if (isSubclass) {
assert(closedWorld.isClosed);
return hasElementIn(self, selector, element) ||
other.isSubclassOf(self) ||
closedWorld.hasAnySubclassThatMixes(self, other);
} else {
assert(isSubtype);
assert(closedWorld.isClosed);
bool result = hasElementIn(self, selector, element) ||
other.implementsInterface(self) ||
closedWorld.hasAnySubclassThatImplements(other, base) ||
@ -602,7 +600,7 @@ class FlatTypeMask implements TypeMask {
ClassElement enclosingClass = element.enclosingClass;
return hasConcreteMatch(enclosingClass.superclass, selector, world);
}
return selector.appliesUntyped(element, world.backend);
return selector.appliesUntyped(element);
}
bool needsNoSuchMethodHandling(Selector selector, ClosedWorld closedWorld) {

View file

@ -26,55 +26,55 @@ abstract class ForwardingTypeMask implements TypeMask {
bool get isValue => false;
bool get isForwarding => true;
bool isInMask(TypeMask other, ClassWorld classWorld) {
return forwardTo.isInMask(other, classWorld);
bool isInMask(TypeMask other, ClosedWorld closedWorld) {
return forwardTo.isInMask(other, closedWorld);
}
bool containsMask(TypeMask other, ClassWorld classWorld) {
return forwardTo.containsMask(other, classWorld);
bool containsMask(TypeMask other, ClosedWorld closedWorld) {
return forwardTo.containsMask(other, closedWorld);
}
bool containsOnlyInt(ClassWorld classWorld) {
return forwardTo.containsOnlyInt(classWorld);
bool containsOnlyInt(ClosedWorld closedWorld) {
return forwardTo.containsOnlyInt(closedWorld);
}
bool containsOnlyDouble(ClassWorld classWorld) {
return forwardTo.containsOnlyDouble(classWorld);
bool containsOnlyDouble(ClosedWorld closedWorld) {
return forwardTo.containsOnlyDouble(closedWorld);
}
bool containsOnlyNum(ClassWorld classWorld) {
return forwardTo.containsOnlyNum(classWorld);
bool containsOnlyNum(ClosedWorld closedWorld) {
return forwardTo.containsOnlyNum(closedWorld);
}
bool containsOnlyBool(ClassWorld classWorld) {
return forwardTo.containsOnlyBool(classWorld);
bool containsOnlyBool(ClosedWorld closedWorld) {
return forwardTo.containsOnlyBool(closedWorld);
}
bool containsOnlyString(ClassWorld classWorld) {
return forwardTo.containsOnlyString(classWorld);
bool containsOnlyString(ClosedWorld closedWorld) {
return forwardTo.containsOnlyString(closedWorld);
}
bool containsOnly(ClassElement element) {
return forwardTo.containsOnly(element);
}
bool satisfies(ClassElement cls, ClassWorld classWorld) {
return forwardTo.satisfies(cls, classWorld);
bool satisfies(ClassElement cls, ClosedWorld closedWorld) {
return forwardTo.satisfies(cls, closedWorld);
}
bool contains(ClassElement type, ClassWorld classWorld) {
return forwardTo.contains(type, classWorld);
bool contains(ClassElement type, ClosedWorld closedWorld) {
return forwardTo.contains(type, closedWorld);
}
bool containsAll(ClassWorld classWorld) {
return forwardTo.containsAll(classWorld);
bool containsAll(ClosedWorld closedWorld) {
return forwardTo.containsAll(closedWorld);
}
ClassElement singleClass(ClassWorld classWorld) {
return forwardTo.singleClass(classWorld);
ClassElement singleClass(ClosedWorld closedWorld) {
return forwardTo.singleClass(closedWorld);
}
TypeMask union(other, ClassWorld classWorld) {
TypeMask union(other, ClosedWorld closedWorld) {
if (this == other) {
return this;
} else if (equalsDisregardNull(other)) {
@ -82,23 +82,23 @@ abstract class ForwardingTypeMask implements TypeMask {
} else if (other.isEmptyOrNull) {
return other.isNullable ? this.nullable() : this;
}
return forwardTo.union(other, classWorld);
return forwardTo.union(other, closedWorld);
}
bool isDisjoint(TypeMask other, ClassWorld classWorld) {
return forwardTo.isDisjoint(other, classWorld);
bool isDisjoint(TypeMask other, ClosedWorld closedWorld) {
return forwardTo.isDisjoint(other, closedWorld);
}
TypeMask intersection(TypeMask other, ClassWorld classWorld) {
return forwardTo.intersection(other, classWorld);
TypeMask intersection(TypeMask other, ClosedWorld closedWorld) {
return forwardTo.intersection(other, closedWorld);
}
bool needsNoSuchMethodHandling(Selector selector, ClassWorld classWorld) {
return forwardTo.needsNoSuchMethodHandling(selector, classWorld);
bool needsNoSuchMethodHandling(Selector selector, ClosedWorld closedWorld) {
return forwardTo.needsNoSuchMethodHandling(selector, closedWorld);
}
bool canHit(Element element, Selector selector, ClassWorld classWorld) {
return forwardTo.canHit(element, selector, classWorld);
bool canHit(Element element, Selector selector, ClosedWorld closedWorld) {
return forwardTo.canHit(element, selector, closedWorld);
}
Element locateSingleElement(Selector selector, Compiler compiler) {

View file

@ -53,13 +53,13 @@ class MapTypeMask extends ForwardingTypeMask {
valueType == other.valueType;
}
TypeMask intersection(TypeMask other, ClassWorld classWorld) {
TypeMask forwardIntersection = forwardTo.intersection(other, classWorld);
TypeMask intersection(TypeMask other, ClosedWorld closedWorld) {
TypeMask forwardIntersection = forwardTo.intersection(other, closedWorld);
if (forwardIntersection.isEmptyOrNull) return forwardIntersection;
return forwardIntersection.isNullable ? nullable() : nonNullable();
}
TypeMask union(other, ClassWorld classWorld) {
TypeMask union(other, ClosedWorld closedWorld) {
if (this == other) {
return this;
} else if (equalsDisregardNull(other)) {
@ -71,20 +71,20 @@ class MapTypeMask extends ForwardingTypeMask {
other.keyType != null &&
valueType != null &&
other.valueType != null) {
TypeMask newKeyType = keyType.union(other.keyType, classWorld);
TypeMask newValueType = valueType.union(other.valueType, classWorld);
TypeMask newForwardTo = forwardTo.union(other.forwardTo, classWorld);
TypeMask newKeyType = keyType.union(other.keyType, closedWorld);
TypeMask newValueType = valueType.union(other.valueType, closedWorld);
TypeMask newForwardTo = forwardTo.union(other.forwardTo, closedWorld);
return new MapTypeMask(
newForwardTo, null, null, newKeyType, newValueType);
} else if (other.isDictionary) {
// TODO(johnniwinther): Find another way to check this invariant that
// doesn't need the compiler.
assert(
other.keyType == classWorld.backend.compiler.commonMasks.stringType);
TypeMask newKeyType = keyType.union(other.keyType, classWorld);
other.keyType == closedWorld.backend.compiler.commonMasks.stringType);
TypeMask newKeyType = keyType.union(other.keyType, closedWorld);
TypeMask newValueType =
other.typeMap.values.fold(keyType, (p, n) => p.union(n, classWorld));
TypeMask newForwardTo = forwardTo.union(other.forwardTo, classWorld);
other.typeMap.values.fold(keyType, (p, n) => p.union(n, closedWorld));
TypeMask newForwardTo = forwardTo.union(other.forwardTo, closedWorld);
MapTypeMask newMapTypeMask = new MapTypeMask(
newForwardTo,
allocationNode == other.allocationNode ? allocationNode : null,
@ -95,7 +95,7 @@ class MapTypeMask extends ForwardingTypeMask {
newValueType);
return newMapTypeMask;
} else {
return forwardTo.union(other, classWorld);
return forwardTo.union(other, closedWorld);
}
}

View file

@ -18,7 +18,7 @@ import '../universe/universe.dart'
UniverseSelectorConstraints,
SelectorConstraintsStrategy;
import '../util/util.dart';
import '../world.dart' show ClassWorld, ClosedWorld;
import '../world.dart' show ClosedWorld, ClosedWorld;
import 'abstract_value_domain.dart' show AbstractValue;
part 'container_type_mask.dart';
@ -37,7 +37,7 @@ class CommonMasks {
CommonMasks(this.compiler);
ClassWorld get classWorld => compiler.closedWorld;
ClosedWorld get closedWorld => compiler.closedWorld;
TypeMask _dynamicType;
TypeMask _nonNullType;
@ -63,72 +63,72 @@ class CommonMasks {
TypeMask _asyncStarStreamType;
TypeMask get dynamicType => _dynamicType ??=
new TypeMask.subclass(classWorld.coreClasses.objectClass, classWorld);
new TypeMask.subclass(closedWorld.coreClasses.objectClass, closedWorld);
TypeMask get nonNullType => _nonNullType ??= new TypeMask.nonNullSubclass(
classWorld.coreClasses.objectClass, classWorld);
closedWorld.coreClasses.objectClass, closedWorld);
TypeMask get intType => _intType ??= new TypeMask.nonNullSubclass(
compiler.backend.intImplementation, classWorld);
compiler.backend.intImplementation, closedWorld);
TypeMask get uint32Type => _uint32Type ??= new TypeMask.nonNullSubclass(
compiler.backend.uint32Implementation, classWorld);
compiler.backend.uint32Implementation, closedWorld);
TypeMask get uint31Type => _uint31Type ??= new TypeMask.nonNullExact(
compiler.backend.uint31Implementation, classWorld);
compiler.backend.uint31Implementation, closedWorld);
TypeMask get positiveIntType =>
_positiveIntType ??= new TypeMask.nonNullSubclass(
compiler.backend.positiveIntImplementation, classWorld);
compiler.backend.positiveIntImplementation, closedWorld);
TypeMask get doubleType => _doubleType ??= new TypeMask.nonNullExact(
compiler.backend.doubleImplementation, classWorld);
compiler.backend.doubleImplementation, closedWorld);
TypeMask get numType => _numType ??= new TypeMask.nonNullSubclass(
compiler.backend.numImplementation, classWorld);
compiler.backend.numImplementation, closedWorld);
TypeMask get boolType => _boolType ??= new TypeMask.nonNullExact(
compiler.backend.boolImplementation, classWorld);
compiler.backend.boolImplementation, closedWorld);
TypeMask get functionType => _functionType ??= new TypeMask.nonNullSubtype(
compiler.backend.functionImplementation, classWorld);
compiler.backend.functionImplementation, closedWorld);
TypeMask get listType => _listType ??= new TypeMask.nonNullExact(
compiler.backend.listImplementation, classWorld);
compiler.backend.listImplementation, closedWorld);
TypeMask get constListType => _constListType ??= new TypeMask.nonNullExact(
compiler.backend.constListImplementation, classWorld);
compiler.backend.constListImplementation, closedWorld);
TypeMask get fixedListType => _fixedListType ??= new TypeMask.nonNullExact(
compiler.backend.fixedListImplementation, classWorld);
compiler.backend.fixedListImplementation, closedWorld);
TypeMask get growableListType =>
_growableListType ??= new TypeMask.nonNullExact(
compiler.backend.growableListImplementation, classWorld);
compiler.backend.growableListImplementation, closedWorld);
TypeMask get mapType => _mapType ??= new TypeMask.nonNullSubtype(
compiler.backend.mapImplementation, classWorld);
compiler.backend.mapImplementation, closedWorld);
TypeMask get constMapType => _constMapType ??= new TypeMask.nonNullSubtype(
compiler.backend.constMapImplementation, classWorld);
compiler.backend.constMapImplementation, closedWorld);
TypeMask get stringType => _stringType ??= new TypeMask.nonNullExact(
compiler.backend.stringImplementation, classWorld);
compiler.backend.stringImplementation, closedWorld);
TypeMask get typeType => _typeType ??= new TypeMask.nonNullExact(
compiler.backend.typeImplementation, classWorld);
compiler.backend.typeImplementation, closedWorld);
TypeMask get syncStarIterableType =>
_syncStarIterableType ??= new TypeMask.nonNullExact(
compiler.backend.syncStarIterableImplementation, classWorld);
compiler.backend.syncStarIterableImplementation, closedWorld);
TypeMask get asyncFutureType =>
_asyncFutureType ??= new TypeMask.nonNullExact(
compiler.backend.asyncFutureImplementation, classWorld);
compiler.backend.asyncFutureImplementation, closedWorld);
TypeMask get asyncStarStreamType =>
_asyncStarStreamType ??= new TypeMask.nonNullExact(
compiler.backend.asyncStarStreamImplementation, classWorld);
compiler.backend.asyncStarStreamImplementation, closedWorld);
// TODO(johnniwinther): Assert that the null type has been resolved.
TypeMask get nullType => _nullType ??= const TypeMask.empty();

View file

@ -27,8 +27,8 @@ class ValueTypeMask extends ForwardingTypeMask {
return super.equalsDisregardNull(other) && value == other.value;
}
TypeMask intersection(TypeMask other, ClassWorld classWorld) {
TypeMask forwardIntersection = forwardTo.intersection(other, classWorld);
TypeMask intersection(TypeMask other, ClosedWorld closedWorld) {
TypeMask forwardIntersection = forwardTo.intersection(other, closedWorld);
if (forwardIntersection.isEmptyOrNull) return forwardIntersection;
return forwardIntersection.isNullable ? nullable() : nonNullable();
}

View file

@ -19,7 +19,7 @@ enum Instantiation {
/// Node for [cls] in a tree forming the subclass relation of [ClassElement]s.
///
/// This is used by the [ClassWorld] to perform queries on subclass and subtype
/// This is used by the [ClosedWorld] to perform queries on subclass and subtype
/// relations.
///
/// For this class hierarchy:

View file

@ -125,7 +125,7 @@ class SelectorMask {
String get name => selector.name;
bool applies(Element element, ClosedWorld closedWorld) {
if (!selector.appliesUnnamed(element, closedWorld.backend)) return false;
if (!selector.appliesUnnamed(element)) return false;
return constraint.canHit(element, selector, closedWorld);
}

View file

@ -217,12 +217,12 @@ class Selector {
return kind;
}
bool appliesUnnamed(Element element, Target target) {
bool appliesUnnamed(Element element) {
assert(sameNameHack(element));
return appliesUntyped(element, target);
return appliesUntyped(element);
}
bool appliesUntyped(Element element, Target target) {
bool appliesUntyped(Element element) {
assert(sameNameHack(element));
if (Elements.isUnresolved(element)) return false;
if (memberName.isPrivate && memberName.library != element.library) {
@ -230,7 +230,6 @@ class Selector {
// `memberName != element.memberName`.
return false;
}
if (target.isForeign(element)) return true;
if (element.isSetter) return isSetter;
if (element.isGetter) return isGetter || isCall;
if (element.isField) {
@ -253,9 +252,9 @@ class Selector {
return element.isConstructor || name == element.name;
}
bool applies(Element element, Target target) {
bool applies(Element element) {
if (!sameNameHack(element)) return false;
return appliesUnnamed(element, target);
return appliesUnnamed(element);
}
bool match(SelectorKind kind, Name memberName, CallStructure callStructure) {

View file

@ -11,7 +11,7 @@ import '../compiler.dart' show Compiler;
import '../dart_types.dart';
import '../elements/elements.dart';
import '../util/util.dart';
import '../world.dart' show ClassWorld, ClosedWorld, OpenWorld;
import '../world.dart' show World, ClosedWorld, OpenWorld;
import 'selector.dart' show Selector;
import 'use.dart' show DynamicUse, DynamicUseKind, StaticUse, StaticUseKind;
@ -29,11 +29,11 @@ abstract class ReceiverConstraint {
/// Returns whether [element] is a potential target when being
/// invoked on a receiver with this constraint. [selector] is used to ensure
/// library privacy is taken into account.
bool canHit(Element element, Selector selector, ClassWorld classWorld);
bool canHit(Element element, Selector selector, World world);
/// Returns whether this [TypeMask] applied to [selector] can hit a
/// [noSuchMethod].
bool needsNoSuchMethodHandling(Selector selector, ClassWorld classWorld);
bool needsNoSuchMethodHandling(Selector selector, World world);
}
/// The combined constraints on receivers all the dynamic call sites of the same
@ -71,7 +71,7 @@ abstract class SelectorConstraints {
///
/// Ideally the selector constraints for calls `foo` with two positional
/// arguments apply to `A.foo` but `B.foo`.
bool applies(Element element, Selector selector, ClassWorld world);
bool applies(Element element, Selector selector, World world);
/// Returns `true` if at least one of the receivers matching these constraints
/// in the closed [world] have no implementation matching [selector].
@ -84,7 +84,7 @@ abstract class SelectorConstraints {
///
/// the potential receiver `new A()` has no implementation of `foo` and thus
/// needs to handle the call through its `noSuchMethod` handler.
bool needsNoSuchMethodHandling(Selector selector, ClassWorld world);
bool needsNoSuchMethodHandling(Selector selector, World world);
}
/// A mutable [SelectorConstraints] used in [Universe].
@ -103,7 +103,7 @@ abstract class SelectorConstraintsStrategy {
}
/// The [Universe] is an auxiliary class used in the process of computing the
/// [ClassWorld]. The concepts here and in [ClassWorld] are very similar -- in
/// [ClosedWorld]. The concepts here and in [ClosedWorld] are very similar -- in
/// the same way that the "universe expands" you can think of this as a mutable
/// world that is expanding as we visit and discover parts of the program.
// TODO(sigmund): rename to "growing/expanding/mutable world"?
@ -129,7 +129,7 @@ abstract class Universe {
Iterable<DartType> get instantiatedTypes;
/// Returns `true` if [member] is invoked as a setter.
bool hasInvokedSetter(Element member, ClassWorld world);
bool hasInvokedSetter(Element member, World world);
}
abstract class ResolutionUniverse implements Universe {
@ -299,10 +299,10 @@ class ResolutionUniverseImpl implements ResolutionUniverse {
}
bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors,
Element member, ClassWorld world) {
Element member, OpenWorld world) {
if (selectors == null) return false;
for (Selector selector in selectors.keys) {
if (selector.appliesUnnamed(member, world.backend)) {
if (selector.appliesUnnamed(member)) {
SelectorConstraints masks = selectors[selector];
if (masks.applies(member, selector, world)) {
return true;
@ -542,7 +542,7 @@ class CodegenUniverseImpl implements CodegenUniverse {
Element member, ClosedWorld world) {
if (selectors == null) return false;
for (Selector selector in selectors.keys) {
if (selector.appliesUnnamed(member, world.backend)) {
if (selector.appliesUnnamed(member)) {
SelectorConstraints masks = selectors[selector];
if (masks.applies(member, selector, world)) {
return true;

View file

@ -21,7 +21,7 @@ import '../common.dart';
import '../dart_types.dart';
import '../elements/elements.dart';
import '../util/util.dart' show Hashing;
import '../world.dart' show ClassWorld;
import '../world.dart' show World;
import 'call_structure.dart' show CallStructure;
import 'selector.dart' show Selector;
import 'universe.dart' show ReceiverConstraint;
@ -37,8 +37,8 @@ class DynamicUse {
DynamicUse(this.selector, this.mask);
bool appliesUnnamed(Element element, ClassWorld world) {
return selector.appliesUnnamed(element, world.backend) &&
bool appliesUnnamed(Element element, World world) {
return selector.appliesUnnamed(element) &&
(mask == null || mask.canHit(element, selector, world));
}

View file

@ -17,7 +17,7 @@ import 'use.dart' show DynamicUse, StaticUse, TypeUse;
///
/// The impact object can be computed locally by inspecting just the resolution
/// information of that element alone. The compiler uses [Universe] and
/// [ClassWorld] to combine the information discovered in the impact objects of
/// [World] to combine the information discovered in the impact objects of
/// all elements reachable in an application.
class WorldImpact {
const WorldImpact();

View file

@ -27,7 +27,10 @@ import 'universe/selector.dart' show Selector;
import 'universe/side_effects.dart' show SideEffects;
import 'util/util.dart' show Link;
/// The [ClassWorld] represents the information known about a program when
/// Common superinterface for [OpenWorld] and [ClosedWorld].
abstract class World {}
/// The [ClosedWorld] represents the information known about a program when
/// compiling with closed-world semantics.
///
/// Given the entrypoint of an application, we can track what's reachable from
@ -35,49 +38,12 @@ import 'util/util.dart' show Link;
/// JavaScript types are touched, what language features are used, and so on.
/// This precise knowledge about what's live in the program is later used in
/// optimizations and other compiler decisions during code generation.
abstract class ClassWorld {
abstract class ClosedWorld implements World {
// TODO(johnniwinther): Refine this into a `BackendClasses` interface.
Backend get backend;
CoreClasses get coreClasses;
/// Returns `true` if the class world is closed.
bool get isClosed;
/// Returns `true` if closed-world assumptions can be made, that is,
/// incremental compilation isn't enabled.
bool get hasClosedWorldAssumption;
/// Returns a string representation of the closed world.
///
/// If [cls] is provided, the dump will contain only classes related to [cls].
String dump([ClassElement cls]);
/// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies
/// of known classes.
///
/// This method is only provided for testing. For queries on classes, use the
/// methods defined in [ClassWorld].
ClassHierarchyNode getClassHierarchyNode(ClassElement cls);
/// Returns [ClassSet] for [cls] used to model the extends and implements
/// relations of known classes.
///
/// This method is only provided for testing. For queries on classes, use the
/// methods defined in [ClassWorld].
ClassSet getClassSet(ClassElement cls);
// TODO(johnniwinther): Find a better strategy for caching these.
@deprecated
List<Map<ClassElement, TypeMask>> get canonicalizedTypeMasks;
}
/// The [ClosedWorld] represents the information known about a program when
/// compiling with closed-world semantics.
///
/// This expands [ClassWorld] with information about live functions,
/// side effects, and selectors with known single targets.
abstract class ClosedWorld extends ClassWorld {
/// Returns `true` if [cls] is either directly or indirectly instantiated.
bool isInstantiated(ClassElement cls);
@ -189,6 +155,24 @@ abstract class ClosedWorld extends ClassWorld {
/// Returns `true` if any subclass of [superclass] implements [type].
bool hasAnySubclassThatImplements(ClassElement superclass, ClassElement type);
/// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies
/// of known classes.
///
/// This method is only provided for testing. For queries on classes, use the
/// methods defined in [ClosedWorld].
ClassHierarchyNode getClassHierarchyNode(ClassElement cls);
/// Returns [ClassSet] for [cls] used to model the extends and implements
/// relations of known classes.
///
/// This method is only provided for testing. For queries on classes, use the
/// methods defined in [ClosedWorld].
ClassSet getClassSet(ClassElement cls);
// TODO(johnniwinther): Find a better strategy for caching these.
@deprecated
List<Map<ClassElement, TypeMask>> get canonicalizedTypeMasks;
/// Returns the [FunctionSet] containing all live functions in the closed
/// world.
FunctionSet get allFunctions;
@ -230,6 +214,11 @@ abstract class ClosedWorld extends ClassWorld {
// TODO(johnniwinther): Is this 'passed invocation target` or
// `passed as argument`?
bool getMightBePassedToApply(Element element);
/// Returns a string representation of the closed world.
///
/// If [cls] is provided, the dump will contain only classes related to [cls].
String dump([ClassElement cls]);
}
/// Interface for computing side effects and uses of elements. This is used
@ -265,7 +254,7 @@ abstract class ClosedWorldRefiner {
void registerClosureClass(ClassElement cls);
}
abstract class OpenWorld implements ClassWorld {
abstract class OpenWorld implements World {
/// Called to add [cls] to the set of known classes.
///
/// This ensures that class hierarchy queries can be performed on [cls] and
@ -749,7 +738,7 @@ class WorldImpl implements ClosedWorld, ClosedWorldRefiner, OpenWorld {
/// of known classes.
///
/// This method is only provided for testing. For queries on classes, use the
/// methods defined in [ClassWorld].
/// methods defined in [ClosedWorld].
ClassHierarchyNode getClassHierarchyNode(ClassElement cls) {
return _classHierarchyNodes[cls.declaration];
}
@ -769,7 +758,7 @@ class WorldImpl implements ClosedWorld, ClosedWorldRefiner, OpenWorld {
/// relations of known classes.
///
/// This method is only provided for testing. For queries on classes, use the
/// methods defined in [ClassWorld].
/// methods defined in [ClosedWorld].
ClassSet getClassSet(ClassElement cls) {
return _classSets[cls.declaration];
}
@ -1024,6 +1013,4 @@ class WorldImpl implements ClosedWorld, ClosedWorldRefiner, OpenWorld {
bool getCurrentlyKnownMightBePassedToApply(Element element) {
return getMightBePassedToApply(element);
}
bool get hasClosedWorldAssumption => !_compiler.options.hasIncrementalSupport;
}

View file

@ -211,7 +211,7 @@ void doTest(String allocation, [String keyElement, String valueElement]) {
Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(generateTest(allocation), uri,
expectedErrors: 0, expectedWarnings: 1);
var classWorld = compiler.openWorld.closeWorld();
var closedWorld = compiler.openWorld.closeWorld();
asyncTest(() => compiler.run(uri).then((_) {
var keyType, valueType;
var commonMasks = compiler.commonMasks;
@ -238,9 +238,9 @@ void doTest(String allocation, [String keyElement, String valueElement]) {
}
K(TypeMask other) =>
simplify(keyType.union(other, classWorld), compiler);
simplify(keyType.union(other, closedWorld), compiler);
V(TypeMask other) =>
simplify(valueType.union(other, classWorld), compiler).nullable();
simplify(valueType.union(other, closedWorld), compiler).nullable();
checkType('mapInField', K(aKeyType), V(commonMasks.numType));
checkType('mapPassedToMethod', K(aKeyType), V(commonMasks.numType));

View file

@ -942,7 +942,7 @@ Future testPatchAndSelector() async {
TypeMask typeMask = new TypeMask.exact(cls, world);
FunctionElement method = cls.implementation.lookupLocalMember('method');
method.computeType(compiler.resolution);
Expect.isTrue(selector.applies(method, world.backend));
Expect.isTrue(selector.applies(method));
Expect.isTrue(typeMask.canHit(method, selector, world));
// Check that the declaration method in the declaration class is a target
@ -952,7 +952,7 @@ Future testPatchAndSelector() async {
typeMask = new TypeMask.exact(cls, world);
method = cls.lookupLocalMember('clear');
method.computeType(compiler.resolution);
Expect.isTrue(selector.applies(method, world.backend));
Expect.isTrue(selector.applies(method));
Expect.isTrue(typeMask.canHit(method, selector, world));
// Check that the declaration method in the declaration class is a target
@ -960,7 +960,7 @@ Future testPatchAndSelector() async {
cls = ensure(compiler, "B", compiler.commonElements.coreLibrary.find);
cls.ensureResolved(compiler.resolution);
typeMask = new TypeMask.exact(cls, world);
Expect.isTrue(selector.applies(method, world.backend));
Expect.isTrue(selector.applies(method));
Expect.isTrue(typeMask.canHit(method, selector, world));
}

View file

@ -21,7 +21,7 @@ main() {
main() {
Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(CODE, uri);
var classWorld = compiler.openWorld.closeWorld();
var closedWorld = compiler.openWorld.closeWorld();
asyncTest(() => compiler.run(uri).then((_) {
var classA = findElement(compiler, 'A');
@ -29,37 +29,37 @@ main() {
var classC = findElement(compiler, 'C');
var classD = findElement(compiler, 'D');
var exactA = new TypeMask.nonNullExact(classA, classWorld);
var exactB = new TypeMask.nonNullExact(classB, classWorld);
var exactC = new TypeMask.nonNullExact(classC, classWorld);
var exactD = new TypeMask.nonNullExact(classD, classWorld);
var exactA = new TypeMask.nonNullExact(classA, closedWorld);
var exactB = new TypeMask.nonNullExact(classB, closedWorld);
var exactC = new TypeMask.nonNullExact(classC, closedWorld);
var exactD = new TypeMask.nonNullExact(classD, closedWorld);
var subclassA = new TypeMask.nonNullSubclass(classA, classWorld);
var subtypeA = new TypeMask.nonNullSubtype(classA, classWorld);
var subclassA = new TypeMask.nonNullSubclass(classA, closedWorld);
var subtypeA = new TypeMask.nonNullSubtype(classA, closedWorld);
var subclassObject = new TypeMask.nonNullSubclass(
compiler.coreClasses.objectClass, classWorld);
compiler.coreClasses.objectClass, closedWorld);
var unionABC =
UnionTypeMask.unionOf([exactA, exactB, exactC], classWorld);
UnionTypeMask.unionOf([exactA, exactB, exactC], closedWorld);
var unionABnC = UnionTypeMask
.unionOf([exactA, exactB.nullable(), exactC], classWorld);
var unionAB = UnionTypeMask.unionOf([exactA, exactB], classWorld);
.unionOf([exactA, exactB.nullable(), exactC], closedWorld);
var unionAB = UnionTypeMask.unionOf([exactA, exactB], closedWorld);
var unionSubtypeAC =
UnionTypeMask.unionOf([subtypeA, exactC], classWorld);
UnionTypeMask.unionOf([subtypeA, exactC], closedWorld);
var unionSubclassAC =
UnionTypeMask.unionOf([subclassA, exactC], classWorld);
UnionTypeMask.unionOf([subclassA, exactC], closedWorld);
var unionBCD =
UnionTypeMask.unionOf([exactB, exactC, exactD], classWorld);
UnionTypeMask.unionOf([exactB, exactC, exactD], closedWorld);
var unionBCDn = UnionTypeMask
.unionOf([exactB, exactC, exactD.nullable()], classWorld);
.unionOf([exactB, exactC, exactD.nullable()], closedWorld);
Expect.isFalse(unionABC.isNullable);
Expect.isTrue(unionABnC.isNullable);
Expect.isFalse(unionBCD.isNullable);
Expect.isTrue(unionBCDn.isNullable);
rule(a, b, c) => Expect.equals(c, a.isInMask(b, classWorld));
rule(a, b, c) => Expect.equals(c, a.isInMask(b, closedWorld));
rule(exactA, exactA, true);
rule(exactA, exactB, false);