mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 04:27:17 +00:00
Revert "Normalize type masks to use the least upper instantiated subclass/type."
This reverts commit d3c68df853
.
BUG=
Review URL: https://codereview.chromium.org/1431513010.
This commit is contained in:
parent
d3c68df853
commit
c1b102a94d
|
@ -998,9 +998,6 @@ class ClosureTranslator extends Visitor {
|
||||||
String closureName = computeClosureName(element);
|
String closureName = computeClosureName(element);
|
||||||
ClosureClassElement globalizedElement = new ClosureClassElement(
|
ClosureClassElement globalizedElement = new ClosureClassElement(
|
||||||
node, closureName, compiler, element);
|
node, closureName, compiler, element);
|
||||||
// Extend [globalizedElement] as an instantiated class in the closed world.
|
|
||||||
compiler.world.registerClass(
|
|
||||||
globalizedElement, isDirectlyInstantiated: true);
|
|
||||||
FunctionElement callElement =
|
FunctionElement callElement =
|
||||||
new SynthesizedCallMethodElementX(Identifiers.call,
|
new SynthesizedCallMethodElementX(Identifiers.call,
|
||||||
element,
|
element,
|
||||||
|
|
|
@ -25,13 +25,6 @@ class TypeMaskSystem {
|
||||||
final World classWorld;
|
final World classWorld;
|
||||||
final JavaScriptBackend backend;
|
final JavaScriptBackend backend;
|
||||||
|
|
||||||
TypeMask _numStringBoolType;
|
|
||||||
TypeMask _fixedLengthType;
|
|
||||||
TypeMask _interceptorType;
|
|
||||||
TypeMask _interceptedTypes; // Does not include null.
|
|
||||||
|
|
||||||
TypeMask __indexableTypeTest;
|
|
||||||
|
|
||||||
TypeMask get dynamicType => inferrer.dynamicType;
|
TypeMask get dynamicType => inferrer.dynamicType;
|
||||||
TypeMask get typeType => inferrer.typeType;
|
TypeMask get typeType => inferrer.typeType;
|
||||||
TypeMask get functionType => inferrer.functionType;
|
TypeMask get functionType => inferrer.functionType;
|
||||||
|
@ -50,70 +43,12 @@ class TypeMaskSystem {
|
||||||
TypeMask get uint32Type => inferrer.uint32Type;
|
TypeMask get uint32Type => inferrer.uint32Type;
|
||||||
TypeMask get uintType => inferrer.positiveIntType;
|
TypeMask get uintType => inferrer.positiveIntType;
|
||||||
|
|
||||||
TypeMask get numStringBoolType {
|
TypeMask numStringBoolType;
|
||||||
if (_numStringBoolType == null) {
|
TypeMask fixedLengthType;
|
||||||
// Build the number+string+bool type. To make containment tests more
|
TypeMask interceptorType;
|
||||||
// inclusive, we use the num, String, bool types for this, not
|
TypeMask interceptedTypes; // Does not include null.
|
||||||
// the JSNumber, JSString, JSBool subclasses.
|
|
||||||
TypeMask anyNum =
|
|
||||||
new TypeMask.nonNullSubtype(classWorld.numClass, classWorld);
|
|
||||||
TypeMask anyString =
|
|
||||||
new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld);
|
|
||||||
TypeMask anyBool =
|
|
||||||
new TypeMask.nonNullSubtype(classWorld.boolClass, classWorld);
|
|
||||||
_numStringBoolType =
|
|
||||||
new TypeMask.unionOf(<TypeMask>[anyNum, anyString, anyBool],
|
|
||||||
classWorld);
|
|
||||||
}
|
|
||||||
return _numStringBoolType;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeMask get fixedLengthType {
|
TypeMask _indexableTypeTest;
|
||||||
if (_fixedLengthType == null) {
|
|
||||||
List<TypeMask> fixedLengthTypes =
|
|
||||||
<TypeMask>[stringType, backend.fixedArrayType];
|
|
||||||
if (classWorld.isInstantiated(helpers.typedArrayClass)) {
|
|
||||||
fixedLengthTypes.add(nonNullSubclass(helpers.typedArrayClass));
|
|
||||||
}
|
|
||||||
_fixedLengthType = new TypeMask.unionOf(fixedLengthTypes, classWorld);
|
|
||||||
}
|
|
||||||
return _fixedLengthType;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeMask get interceptorType {
|
|
||||||
if (_interceptorType == null) {
|
|
||||||
_interceptorType =
|
|
||||||
new TypeMask.nonNullSubtype(helpers.jsInterceptorClass, classWorld);
|
|
||||||
}
|
|
||||||
return _interceptorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeMask get interceptedTypes { // Does not include null.
|
|
||||||
if (_interceptedTypes == null) {
|
|
||||||
// We redundantly include subtypes of num/string/bool as intercepted
|
|
||||||
// types, because the type system does not infer that their
|
|
||||||
// implementations are all subclasses of Interceptor.
|
|
||||||
_interceptedTypes = new TypeMask.unionOf(
|
|
||||||
<TypeMask>[interceptorType, numStringBoolType], classWorld);
|
|
||||||
}
|
|
||||||
return _interceptedTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeMask get _indexableTypeTest {
|
|
||||||
if (__indexableTypeTest == null) {
|
|
||||||
// Make a TypeMask containing Indexable and (redundantly) subtypes of
|
|
||||||
// string because the type inference does not infer that all strings are
|
|
||||||
// indexables.
|
|
||||||
TypeMask indexable =
|
|
||||||
new TypeMask.nonNullSubtype(helpers.jsIndexableClass, classWorld);
|
|
||||||
TypeMask anyString =
|
|
||||||
new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld);
|
|
||||||
__indexableTypeTest = new TypeMask.unionOf(
|
|
||||||
<TypeMask>[indexable, anyString],
|
|
||||||
classWorld);
|
|
||||||
}
|
|
||||||
return __indexableTypeTest;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassElement get jsNullClass => helpers.jsNullClass;
|
ClassElement get jsNullClass => helpers.jsNullClass;
|
||||||
|
|
||||||
|
@ -124,6 +59,41 @@ class TypeMaskSystem {
|
||||||
: inferrer = compiler.typesTask,
|
: inferrer = compiler.typesTask,
|
||||||
classWorld = compiler.world,
|
classWorld = compiler.world,
|
||||||
backend = compiler.backend {
|
backend = compiler.backend {
|
||||||
|
|
||||||
|
// Build the number+string+bool type. To make containment tests more
|
||||||
|
// inclusive, we use the num, String, bool types for this, not
|
||||||
|
// the JSNumber, JSString, JSBool subclasses.
|
||||||
|
TypeMask anyNum =
|
||||||
|
new TypeMask.nonNullSubtype(classWorld.numClass, classWorld);
|
||||||
|
TypeMask anyString =
|
||||||
|
new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld);
|
||||||
|
TypeMask anyBool =
|
||||||
|
new TypeMask.nonNullSubtype(classWorld.boolClass, classWorld);
|
||||||
|
numStringBoolType =
|
||||||
|
new TypeMask.unionOf(<TypeMask>[anyNum, anyString, anyBool],
|
||||||
|
classWorld);
|
||||||
|
interceptorType =
|
||||||
|
new TypeMask.nonNullSubtype(helpers.jsInterceptorClass, classWorld);
|
||||||
|
|
||||||
|
// We redundantly include subtypes of num/string/bool as intercepted types,
|
||||||
|
// because the type system does not infer that their implementations are
|
||||||
|
// all subclasses of Interceptor.
|
||||||
|
interceptedTypes = new TypeMask.unionOf(
|
||||||
|
<TypeMask>[interceptorType, numStringBoolType], classWorld);
|
||||||
|
|
||||||
|
TypeMask typedArray = nonNullSubclass(helpers.typedArrayClass);
|
||||||
|
fixedLengthType = new TypeMask.unionOf(
|
||||||
|
<TypeMask>[stringType, backend.fixedArrayType, typedArray],
|
||||||
|
classWorld);
|
||||||
|
|
||||||
|
// Make a TypeMask containing Indexable and (redundantly) subtypes of
|
||||||
|
// string because the type inference does not infer that all strings are
|
||||||
|
// indexables.
|
||||||
|
TypeMask indexable =
|
||||||
|
new TypeMask.nonNullSubtype(helpers.jsIndexableClass, classWorld);
|
||||||
|
_indexableTypeTest = new TypeMask.unionOf(
|
||||||
|
<TypeMask>[indexable, anyString],
|
||||||
|
classWorld);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool methodUsesReceiverArgument(FunctionElement function) {
|
bool methodUsesReceiverArgument(FunctionElement function) {
|
||||||
|
|
|
@ -178,19 +178,15 @@ abstract class Enqueuer {
|
||||||
task.measure(() {
|
task.measure(() {
|
||||||
ClassElement cls = type.element;
|
ClassElement cls = type.element;
|
||||||
cls.ensureResolved(resolution);
|
cls.ensureResolved(resolution);
|
||||||
bool isNative = compiler.backend.isNative(cls);
|
|
||||||
universe.registerTypeInstantiation(
|
universe.registerTypeInstantiation(
|
||||||
type,
|
type,
|
||||||
isNative: isNative,
|
isNative: compiler.backend.isNative(cls),
|
||||||
byMirrors: mirrorUsage,
|
byMirrors: mirrorUsage,
|
||||||
onImplemented: (ClassElement cls) {
|
onImplemented: (ClassElement cls) {
|
||||||
compiler.backend.registerImplementedClass(
|
compiler.backend.registerImplementedClass(
|
||||||
cls, this, compiler.globalDependencies);
|
cls, this, compiler.globalDependencies);
|
||||||
});
|
});
|
||||||
// TODO(johnniwinther): Share this reasoning with [Universe].
|
processInstantiatedClass(cls);
|
||||||
if (!cls.isAbstract || isNative || mirrorUsage) {
|
|
||||||
processInstantiatedClass(cls);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,10 +335,9 @@ abstract class Enqueuer {
|
||||||
superclass, this, compiler.globalDependencies);
|
superclass, this, compiler.globalDependencies);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassElement superclass = cls;
|
while (cls != null) {
|
||||||
while (superclass != null) {
|
processClass(cls);
|
||||||
processClass(superclass);
|
cls = cls.superclass;
|
||||||
superclass = superclass.superclass;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -647,19 +647,7 @@ class SimpleTypeInferrerVisitor<T>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (analyzedElement.isGenerativeConstructor && cls.isAbstract) {
|
returnType = types.nonNullExact(cls);
|
||||||
if (compiler.world.isDirectlyInstantiated(cls)) {
|
|
||||||
returnType = types.nonNullExact(cls);
|
|
||||||
} else if (compiler.world.isIndirectlyInstantiated(cls)) {
|
|
||||||
returnType = types.nonNullSubclass(cls);
|
|
||||||
} else {
|
|
||||||
// TODO(johnniwinther): Avoid analyzing [analyzedElement] in this
|
|
||||||
// case; it's never called.
|
|
||||||
returnType = types.nonNullEmpty();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
returnType = types.nonNullExact(cls);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
signature.forEachParameter((LocalParameterElement element) {
|
signature.forEachParameter((LocalParameterElement element) {
|
||||||
locals.update(element, inferrer.typeOfElement(element), node);
|
locals.update(element, inferrer.typeOfElement(element), node);
|
||||||
|
|
|
@ -3247,7 +3247,7 @@ class SsaBuilder extends ast.Visitor
|
||||||
});
|
});
|
||||||
|
|
||||||
TypeMask type =
|
TypeMask type =
|
||||||
new TypeMask.nonNullExact(closureClassElement, compiler.world);
|
new TypeMask.nonNullExact(coreClasses.functionClass, compiler.world);
|
||||||
push(new HForeignNew(closureClassElement, type, capturedVariables)
|
push(new HForeignNew(closureClassElement, type, capturedVariables)
|
||||||
..sourceInformation = sourceInformationBuilder.buildCreate(node));
|
..sourceInformation = sourceInformationBuilder.buildCreate(node));
|
||||||
|
|
||||||
|
@ -5074,13 +5074,7 @@ class SsaBuilder extends ast.Visitor
|
||||||
: inferred;
|
: inferred;
|
||||||
} else if (element.isGenerativeConstructor) {
|
} else if (element.isGenerativeConstructor) {
|
||||||
ClassElement cls = element.enclosingClass;
|
ClassElement cls = element.enclosingClass;
|
||||||
if (cls.isAbstract) {
|
return new TypeMask.nonNullExact(cls.thisType.element, compiler.world);
|
||||||
// An error will be thrown.
|
|
||||||
return new TypeMask.nonNullEmpty();
|
|
||||||
} else {
|
|
||||||
return new TypeMask.nonNullExact(
|
|
||||||
cls.thisType.element, compiler.world);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return TypeMaskFactory.inferredReturnTypeForElement(
|
return TypeMaskFactory.inferredReturnTypeForElement(
|
||||||
originalElement, compiler);
|
originalElement, compiler);
|
||||||
|
|
|
@ -546,8 +546,9 @@ class FlatTypeMask implements TypeMask {
|
||||||
*/
|
*/
|
||||||
static bool hasConcreteMatch(ClassElement cls,
|
static bool hasConcreteMatch(ClassElement cls,
|
||||||
Selector selector,
|
Selector selector,
|
||||||
ClassWorld world) {
|
World world) {
|
||||||
assert(invariant(cls, world.isInstantiated(cls),
|
assert(invariant(cls,
|
||||||
|
world.compiler.resolverWorld.isInstantiated(cls),
|
||||||
message: '$cls has not been instantiated.'));
|
message: '$cls has not been instantiated.'));
|
||||||
Element element = findMatchIn(cls, selector);
|
Element element = findMatchIn(cls, selector);
|
||||||
if (element == null) return false;
|
if (element == null) return false;
|
||||||
|
|
|
@ -89,7 +89,7 @@ abstract class TypeMask implements ReceiverConstraint {
|
||||||
factory TypeMask.exact(ClassElement base, ClassWorld classWorld) {
|
factory TypeMask.exact(ClassElement base, ClassWorld classWorld) {
|
||||||
assert(invariant(base, classWorld.isInstantiated(base),
|
assert(invariant(base, classWorld.isInstantiated(base),
|
||||||
message: () => "Cannot create exact type mask for uninstantiated "
|
message: () => "Cannot create exact type mask for uninstantiated "
|
||||||
"class $base.\n${classWorld.dump(base)}"));
|
"class $base.\n${classWorld.dump()}"));
|
||||||
return new FlatTypeMask.exact(base);
|
return new FlatTypeMask.exact(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,31 +99,21 @@ abstract class TypeMask implements ReceiverConstraint {
|
||||||
}
|
}
|
||||||
|
|
||||||
factory TypeMask.subclass(ClassElement base, ClassWorld classWorld) {
|
factory TypeMask.subclass(ClassElement base, ClassWorld classWorld) {
|
||||||
assert(invariant(base, classWorld.isInstantiated(base),
|
if (classWorld.hasAnyStrictSubclass(base)) {
|
||||||
message: () => "Cannot create subclass type mask for uninstantiated "
|
return new FlatTypeMask.subclass(base);
|
||||||
"class $base.\n${classWorld.dump(base)}"));
|
|
||||||
ClassElement topmost = classWorld.getLubOfInstantiatedSubclasses(base);
|
|
||||||
if (topmost == null) {
|
|
||||||
return new TypeMask.empty();
|
|
||||||
} else if (classWorld.hasAnyStrictSubclass(topmost)) {
|
|
||||||
return new FlatTypeMask.subclass(topmost);
|
|
||||||
} else {
|
} else {
|
||||||
return new TypeMask.exact(topmost, classWorld);
|
return new TypeMask.exactOrEmpty(base, classWorld);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
factory TypeMask.subtype(ClassElement base, ClassWorld classWorld) {
|
factory TypeMask.subtype(ClassElement base, ClassWorld classWorld) {
|
||||||
ClassElement topmost = classWorld.getLubOfInstantiatedSubtypes(base);
|
if (classWorld.hasOnlySubclasses(base)) {
|
||||||
if (topmost == null) {
|
return new TypeMask.subclass(base, classWorld);
|
||||||
return new TypeMask.empty();
|
|
||||||
}
|
}
|
||||||
if (classWorld.hasOnlySubclasses(topmost)) {
|
if (classWorld.hasAnyStrictSubtype(base)) {
|
||||||
return new TypeMask.subclass(topmost, classWorld);
|
return new FlatTypeMask.subtype(base);
|
||||||
}
|
|
||||||
if (classWorld.hasAnyStrictSubtype(topmost)) {
|
|
||||||
return new FlatTypeMask.subtype(topmost);
|
|
||||||
} else {
|
} else {
|
||||||
return new TypeMask.exact(topmost, classWorld);
|
return new TypeMask.exactOrEmpty(base, classWorld);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,8 +121,8 @@ abstract class TypeMask implements ReceiverConstraint {
|
||||||
|
|
||||||
factory TypeMask.nonNullExact(ClassElement base, ClassWorld classWorld) {
|
factory TypeMask.nonNullExact(ClassElement base, ClassWorld classWorld) {
|
||||||
assert(invariant(base, classWorld.isInstantiated(base),
|
assert(invariant(base, classWorld.isInstantiated(base),
|
||||||
message: () => "Cannot create exact type mask for uninstantiated "
|
message: () => "Cannot create exact type mask for "
|
||||||
"class $base.\n${classWorld.dump(base)}"));
|
"uninstantiated class $base.\n${classWorld.dump(base)}"));
|
||||||
return new FlatTypeMask.nonNullExact(base);
|
return new FlatTypeMask.nonNullExact(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,31 +135,21 @@ abstract class TypeMask implements ReceiverConstraint {
|
||||||
}
|
}
|
||||||
|
|
||||||
factory TypeMask.nonNullSubclass(ClassElement base, ClassWorld classWorld) {
|
factory TypeMask.nonNullSubclass(ClassElement base, ClassWorld classWorld) {
|
||||||
assert(invariant(base, classWorld.isInstantiated(base),
|
if (classWorld.hasAnyStrictSubclass(base)) {
|
||||||
message: () => "Cannot create subclass type mask for uninstantiated "
|
return new FlatTypeMask.nonNullSubclass(base);
|
||||||
"class $base.\n${classWorld.dump(base)}"));
|
|
||||||
ClassElement topmost = classWorld.getLubOfInstantiatedSubclasses(base);
|
|
||||||
if (topmost == null) {
|
|
||||||
return new TypeMask.nonNullEmpty();
|
|
||||||
} else if (classWorld.hasAnyStrictSubclass(topmost)) {
|
|
||||||
return new FlatTypeMask.nonNullSubclass(topmost);
|
|
||||||
} else {
|
} else {
|
||||||
return new TypeMask.nonNullExact(topmost, classWorld);
|
return new TypeMask.nonNullExactOrEmpty(base, classWorld);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
factory TypeMask.nonNullSubtype(ClassElement base, ClassWorld classWorld) {
|
factory TypeMask.nonNullSubtype(ClassElement base, ClassWorld classWorld) {
|
||||||
ClassElement topmost = classWorld.getLubOfInstantiatedSubtypes(base);
|
if (classWorld.hasOnlySubclasses(base)) {
|
||||||
if (topmost == null) {
|
return new TypeMask.nonNullSubclass(base, classWorld);
|
||||||
return new TypeMask.nonNullEmpty();
|
|
||||||
}
|
}
|
||||||
if (classWorld.hasOnlySubclasses(topmost)) {
|
if (classWorld.hasAnyStrictSubtype(base)) {
|
||||||
return new TypeMask.nonNullSubclass(topmost, classWorld);
|
return new FlatTypeMask.nonNullSubtype(base);
|
||||||
}
|
|
||||||
if (classWorld.hasAnyStrictSubtype(topmost)) {
|
|
||||||
return new FlatTypeMask.nonNullSubtype(topmost);
|
|
||||||
} else {
|
} else {
|
||||||
return new TypeMask.nonNullExact(topmost, classWorld);
|
return new TypeMask.nonNullExactOrEmpty(base, classWorld);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,6 @@ import '../util/util.dart' show Link;
|
||||||
///
|
///
|
||||||
class ClassHierarchyNode {
|
class ClassHierarchyNode {
|
||||||
final ClassElement cls;
|
final ClassElement cls;
|
||||||
ClassElement _leastUpperInstantiatedSubclass;
|
|
||||||
|
|
||||||
/// `true` if [cls] has been directly instantiated.
|
/// `true` if [cls] has been directly instantiated.
|
||||||
///
|
///
|
||||||
|
@ -102,55 +101,15 @@ class ClassHierarchyNode {
|
||||||
includeUninstantiated: includeUninstantiated);
|
includeUninstantiated: includeUninstantiated);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the most specific subclass of [cls] (including [cls]) that is
|
|
||||||
/// directly instantiated or a superclass of all directly instantiated
|
|
||||||
/// subclasses. If [cls] is not instantiated, `null` is returned.
|
|
||||||
ClassElement getLubOfInstantiatedSubclasses() {
|
|
||||||
if (!isInstantiated) return null;
|
|
||||||
if (_leastUpperInstantiatedSubclass == null) {
|
|
||||||
_leastUpperInstantiatedSubclass =
|
|
||||||
_computeLeastUpperInstantiatedSubclass();
|
|
||||||
}
|
|
||||||
return _leastUpperInstantiatedSubclass;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassElement _computeLeastUpperInstantiatedSubclass() {
|
|
||||||
if (isDirectlyInstantiated) {
|
|
||||||
return cls;
|
|
||||||
}
|
|
||||||
ClassHierarchyNode subclass;
|
|
||||||
for (Link<ClassHierarchyNode> link = _directSubclasses;
|
|
||||||
!link.isEmpty;
|
|
||||||
link = link.tail) {
|
|
||||||
if (link.head.isInstantiated) {
|
|
||||||
if (subclass == null) {
|
|
||||||
subclass = link.head;
|
|
||||||
} else {
|
|
||||||
return cls;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (subclass != null) {
|
|
||||||
return subclass.getLubOfInstantiatedSubclasses();
|
|
||||||
}
|
|
||||||
return cls;
|
|
||||||
}
|
|
||||||
|
|
||||||
void printOn(StringBuffer sb, String indentation,
|
void printOn(StringBuffer sb, String indentation,
|
||||||
{bool instantiatedOnly: false,
|
{bool instantiatedOnly: false,
|
||||||
bool sorted: true,
|
|
||||||
ClassElement withRespectTo}) {
|
ClassElement withRespectTo}) {
|
||||||
|
|
||||||
bool isRelatedTo(ClassElement subclass) {
|
bool isRelatedTo(ClassElement subclass) {
|
||||||
return subclass == withRespectTo ||
|
return subclass.implementsInterface(withRespectTo);
|
||||||
subclass.implementsInterface(withRespectTo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.write(indentation);
|
sb.write('$indentation$cls');
|
||||||
if (cls.isAbstract) {
|
|
||||||
sb.write('abstract ');
|
|
||||||
}
|
|
||||||
sb.write('class ${cls.name}:');
|
|
||||||
if (isDirectlyInstantiated) {
|
if (isDirectlyInstantiated) {
|
||||||
sb.write(' directly');
|
sb.write(' directly');
|
||||||
}
|
}
|
||||||
|
@ -161,14 +120,11 @@ class ClassHierarchyNode {
|
||||||
if (_directSubclasses.isEmpty) {
|
if (_directSubclasses.isEmpty) {
|
||||||
sb.write(']');
|
sb.write(']');
|
||||||
} else {
|
} else {
|
||||||
var subclasses = _directSubclasses;
|
|
||||||
if (sorted) {
|
|
||||||
subclasses = _directSubclasses.toList()..sort((a, b) {
|
|
||||||
return a.cls.name.compareTo(b.cls.name);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
bool needsComma = false;
|
bool needsComma = false;
|
||||||
for (ClassHierarchyNode child in subclasses) {
|
for (Link<ClassHierarchyNode> link = _directSubclasses;
|
||||||
|
!link.isEmpty;
|
||||||
|
link = link.tail) {
|
||||||
|
ClassHierarchyNode child = link.head;
|
||||||
if (instantiatedOnly && !child.isInstantiated) {
|
if (instantiatedOnly && !child.isInstantiated) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -184,7 +140,6 @@ class ClassHierarchyNode {
|
||||||
sb,
|
sb,
|
||||||
'$indentation ',
|
'$indentation ',
|
||||||
instantiatedOnly: instantiatedOnly,
|
instantiatedOnly: instantiatedOnly,
|
||||||
sorted: sorted,
|
|
||||||
withRespectTo: withRespectTo);
|
withRespectTo: withRespectTo);
|
||||||
needsComma = true;
|
needsComma = true;
|
||||||
}
|
}
|
||||||
|
@ -256,7 +211,6 @@ class ClassHierarchyNode {
|
||||||
///
|
///
|
||||||
class ClassSet {
|
class ClassSet {
|
||||||
final ClassHierarchyNode node;
|
final ClassHierarchyNode node;
|
||||||
ClassElement _leastUpperInstantiatedSubtype;
|
|
||||||
|
|
||||||
List<ClassHierarchyNode> _directSubtypes;
|
List<ClassHierarchyNode> _directSubtypes;
|
||||||
|
|
||||||
|
@ -357,42 +311,6 @@ class ClassSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the most specific subtype of [cls] (including [cls]) that is
|
|
||||||
/// directly instantiated or a superclass of all directly instantiated
|
|
||||||
/// subtypes. If no subtypes of [cls] are instantiated, `null` is returned.
|
|
||||||
ClassElement getLubOfInstantiatedSubtypes() {
|
|
||||||
if (_leastUpperInstantiatedSubtype == null) {
|
|
||||||
_leastUpperInstantiatedSubtype = _computeLeastUpperInstantiatedSubtype();
|
|
||||||
}
|
|
||||||
return _leastUpperInstantiatedSubtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassElement _computeLeastUpperInstantiatedSubtype() {
|
|
||||||
if (node.isDirectlyInstantiated) {
|
|
||||||
return cls;
|
|
||||||
}
|
|
||||||
if (_directSubtypes == null) {
|
|
||||||
return node.getLubOfInstantiatedSubclasses();
|
|
||||||
}
|
|
||||||
ClassHierarchyNode subtype;
|
|
||||||
if (node.isInstantiated) {
|
|
||||||
subtype = node;
|
|
||||||
}
|
|
||||||
for (ClassHierarchyNode subnode in _directSubtypes) {
|
|
||||||
if (subnode.isInstantiated) {
|
|
||||||
if (subtype == null) {
|
|
||||||
subtype = subnode;
|
|
||||||
} else {
|
|
||||||
return cls;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (subtype != null) {
|
|
||||||
return subtype.getLubOfInstantiatedSubclasses();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String toString() {
|
String toString() {
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
sb.write('[\n');
|
sb.write('[\n');
|
||||||
|
|
|
@ -298,11 +298,8 @@ class FullFunctionSetQuery implements FunctionSetQuery {
|
||||||
.map((cls) {
|
.map((cls) {
|
||||||
if (classWorld.backend.isNullImplementation(cls)) {
|
if (classWorld.backend.isNullImplementation(cls)) {
|
||||||
return const TypeMask.empty();
|
return const TypeMask.empty();
|
||||||
} else if (classWorld.isInstantiated(cls.declaration)) {
|
|
||||||
return new TypeMask.nonNullSubclass(cls.declaration, classWorld);
|
|
||||||
} else {
|
} else {
|
||||||
// TODO(johnniwinther): Avoid the need for this case.
|
return new TypeMask.nonNullSubclass(cls.declaration, classWorld);
|
||||||
return const TypeMask.empty();
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
classWorld);
|
classWorld);
|
||||||
|
|
|
@ -124,6 +124,12 @@ class Universe {
|
||||||
/// See [_directlyInstantiatedClasses].
|
/// See [_directlyInstantiatedClasses].
|
||||||
final Set<DartType> _instantiatedTypes = new Set<DartType>();
|
final Set<DartType> _instantiatedTypes = new Set<DartType>();
|
||||||
|
|
||||||
|
/// The set of all instantiated classes, either directly, as superclasses or
|
||||||
|
/// as supertypes.
|
||||||
|
///
|
||||||
|
/// Invariant: Elements are declaration elements.
|
||||||
|
final Set<ClassElement> _allInstantiatedClasses = new Set<ClassElement>();
|
||||||
|
|
||||||
/// Classes implemented by directly instantiated classes.
|
/// Classes implemented by directly instantiated classes.
|
||||||
final Set<ClassElement> _implementedClasses = new Set<ClassElement>();
|
final Set<ClassElement> _implementedClasses = new Set<ClassElement>();
|
||||||
|
|
||||||
|
@ -200,6 +206,13 @@ class Universe {
|
||||||
return _directlyInstantiatedClasses;
|
return _directlyInstantiatedClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// All instantiated classes, either directly, as superclasses or as
|
||||||
|
/// supertypes.
|
||||||
|
// TODO(johnniwinther): Improve semantic precision.
|
||||||
|
Iterable<ClassElement> get allInstantiatedClasses {
|
||||||
|
return _allInstantiatedClasses;
|
||||||
|
}
|
||||||
|
|
||||||
/// All directly instantiated types, that is, the types of the directly
|
/// All directly instantiated types, that is, the types of the directly
|
||||||
/// instantiated classes.
|
/// instantiated classes.
|
||||||
///
|
///
|
||||||
|
@ -207,6 +220,13 @@ class Universe {
|
||||||
// TODO(johnniwinther): Improve semantic precision.
|
// TODO(johnniwinther): Improve semantic precision.
|
||||||
Iterable<DartType> get instantiatedTypes => _instantiatedTypes;
|
Iterable<DartType> get instantiatedTypes => _instantiatedTypes;
|
||||||
|
|
||||||
|
/// Returns `true` if [cls] is considered to be instantiated, either directly,
|
||||||
|
/// through subclasses.
|
||||||
|
// TODO(johnniwinther): Improve semantic precision.
|
||||||
|
bool isInstantiated(ClassElement cls) {
|
||||||
|
return _allInstantiatedClasses.contains(cls.declaration);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if [cls] is considered to be implemented by an
|
/// Returns `true` if [cls] is considered to be implemented by an
|
||||||
/// instantiated class, either directly, through subclasses or through
|
/// instantiated class, either directly, through subclasses or through
|
||||||
/// subtypes. The latter case only contains spurious information from
|
/// subtypes. The latter case only contains spurious information from
|
||||||
|
@ -251,6 +271,12 @@ class Universe {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
while (cls != null) {
|
||||||
|
if (!_allInstantiatedClasses.add(cls)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cls = cls.superclass;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors,
|
bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors,
|
||||||
|
@ -377,6 +403,7 @@ class Universe {
|
||||||
fieldSetters.remove(element);
|
fieldSetters.remove(element);
|
||||||
fieldGetters.remove(element);
|
fieldGetters.remove(element);
|
||||||
_directlyInstantiatedClasses.remove(element);
|
_directlyInstantiatedClasses.remove(element);
|
||||||
|
_allInstantiatedClasses.remove(element);
|
||||||
if (element is ClassElement) {
|
if (element is ClassElement) {
|
||||||
assert(invariant(
|
assert(invariant(
|
||||||
element, element.thisType.isRaw,
|
element, element.thisType.isRaw,
|
||||||
|
|
|
@ -62,16 +62,9 @@ abstract class ClassWorld {
|
||||||
/// The [ClassElement] for the [String] class defined in 'dart:core'.
|
/// The [ClassElement] for the [String] class defined in 'dart:core'.
|
||||||
ClassElement get stringClass;
|
ClassElement get stringClass;
|
||||||
|
|
||||||
/// Returns `true` if [cls] is either directly or indirectly instantiated.
|
/// Returns `true` if [cls] is instantiated.
|
||||||
bool isInstantiated(ClassElement cls);
|
bool isInstantiated(ClassElement cls);
|
||||||
|
|
||||||
/// Returns `true` if [cls] is directly instantiated.
|
|
||||||
bool isDirectlyInstantiated(ClassElement cls);
|
|
||||||
|
|
||||||
/// Returns `true` if [cls] is indirectly instantiated, that is through a
|
|
||||||
/// subclass.
|
|
||||||
bool isIndirectlyInstantiated(ClassElement cls);
|
|
||||||
|
|
||||||
/// Returns `true` if [cls] is implemented by an instantiated class.
|
/// Returns `true` if [cls] is implemented by an instantiated class.
|
||||||
bool isImplemented(ClassElement cls);
|
bool isImplemented(ClassElement cls);
|
||||||
|
|
||||||
|
@ -113,16 +106,6 @@ abstract class ClassWorld {
|
||||||
/// Returns `true` if all live classes that implement [cls] extend it.
|
/// Returns `true` if all live classes that implement [cls] extend it.
|
||||||
bool hasOnlySubclasses(ClassElement cls);
|
bool hasOnlySubclasses(ClassElement cls);
|
||||||
|
|
||||||
/// Returns the most specific subclass of [cls] (including [cls]) that is
|
|
||||||
/// directly instantiated or a superclass of all directly instantiated
|
|
||||||
/// subclasses. If [cls] is not instantiated, `null` is returned.
|
|
||||||
ClassElement getLubOfInstantiatedSubclasses(ClassElement cls);
|
|
||||||
|
|
||||||
/// Returns the most specific subtype of [cls] (including [cls]) that is
|
|
||||||
/// directly instantiated or a superclass of all directly instantiated
|
|
||||||
/// subtypes. If no subtypes of [cls] are instantiated, `null` is returned.
|
|
||||||
ClassElement getLubOfInstantiatedSubtypes(ClassElement cls);
|
|
||||||
|
|
||||||
/// Returns an iterable over the common supertypes of the [classes].
|
/// Returns an iterable over the common supertypes of the [classes].
|
||||||
Iterable<ClassElement> commonSupertypesOf(Iterable<ClassElement> classes);
|
Iterable<ClassElement> commonSupertypesOf(Iterable<ClassElement> classes);
|
||||||
|
|
||||||
|
@ -207,22 +190,10 @@ class World implements ClassWorld {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
/// Returns `true` if [cls] is instantiated either directly or through a
|
||||||
|
/// subclass.
|
||||||
bool isInstantiated(ClassElement cls) {
|
bool isInstantiated(ClassElement cls) {
|
||||||
ClassHierarchyNode node = _classHierarchyNodes[cls.declaration];
|
return compiler.resolverWorld.isInstantiated(cls);
|
||||||
return node != null && node.isInstantiated;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool isDirectlyInstantiated(ClassElement cls) {
|
|
||||||
ClassHierarchyNode node = _classHierarchyNodes[cls.declaration];
|
|
||||||
return node != null && node.isDirectlyInstantiated;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool isIndirectlyInstantiated(ClassElement cls) {
|
|
||||||
ClassHierarchyNode node = _classHierarchyNodes[cls.declaration];
|
|
||||||
return node != null && node.isIndirectlyInstantiated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if [cls] is implemented by an instantiated class.
|
/// Returns `true` if [cls] is implemented by an instantiated class.
|
||||||
|
@ -316,20 +287,6 @@ class World implements ClassWorld {
|
||||||
return subclasses != null && (subclasses.length == subtypes.length);
|
return subclasses != null && (subclasses.length == subtypes.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
ClassElement getLubOfInstantiatedSubclasses(ClassElement cls) {
|
|
||||||
ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration];
|
|
||||||
return hierarchy != null
|
|
||||||
? hierarchy.getLubOfInstantiatedSubclasses() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
ClassElement getLubOfInstantiatedSubtypes(ClassElement cls) {
|
|
||||||
ClassSet classSet = _classSets[cls.declaration];
|
|
||||||
return classSet != null
|
|
||||||
? classSet.getLubOfInstantiatedSubtypes() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterable over the common supertypes of the [classes].
|
/// Returns an iterable over the common supertypes of the [classes].
|
||||||
Iterable<ClassElement> commonSupertypesOf(Iterable<ClassElement> classes) {
|
Iterable<ClassElement> commonSupertypesOf(Iterable<ClassElement> classes) {
|
||||||
Iterator<ClassElement> iterator = classes.iterator;
|
Iterator<ClassElement> iterator = classes.iterator;
|
||||||
|
@ -486,11 +443,8 @@ class World implements ClassWorld {
|
||||||
///
|
///
|
||||||
/// This ensures that class hierarchy queries can be performed on [cls] and
|
/// This ensures that class hierarchy queries can be performed on [cls] and
|
||||||
/// classes that extend or implement it.
|
/// classes that extend or implement it.
|
||||||
void registerClass(ClassElement cls, {bool isDirectlyInstantiated: false}) {
|
void registerClass(ClassElement cls) {
|
||||||
_ensureClassSet(cls);
|
_ensureClassSet(cls);
|
||||||
if (isDirectlyInstantiated) {
|
|
||||||
_updateClassHierarchyNodeForClass(cls, directlyInstantiated: true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies
|
/// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies
|
||||||
|
@ -538,36 +492,29 @@ class World implements ClassWorld {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateClassHierarchyNodeForClass(
|
|
||||||
ClassElement cls,
|
|
||||||
{bool directlyInstantiated: false,
|
|
||||||
bool indirectlyInstantiated: false}) {
|
|
||||||
ClassHierarchyNode node = getClassHierarchyNode(cls);
|
|
||||||
bool changed = false;
|
|
||||||
if (directlyInstantiated && !node.isDirectlyInstantiated) {
|
|
||||||
node.isDirectlyInstantiated = true;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
if (indirectlyInstantiated && !node.isIndirectlyInstantiated) {
|
|
||||||
node.isIndirectlyInstantiated = true;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
if (changed && cls.superclass != null) {
|
|
||||||
_updateClassHierarchyNodeForClass(
|
|
||||||
cls.superclass, indirectlyInstantiated: true);
|
|
||||||
}
|
|
||||||
// Ensure that classes implicitly implementing `Function` are in its
|
|
||||||
// subtype set.
|
|
||||||
if (cls != coreClasses.functionClass &&
|
|
||||||
cls.implementsFunction(compiler)) {
|
|
||||||
ClassSet subtypeSet = _ensureClassSet(coreClasses.functionClass);
|
|
||||||
subtypeSet.addSubtype(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void populate() {
|
void populate() {
|
||||||
/// Updates the `isDirectlyInstantiated` and `isIndirectlyInstantiated`
|
/// Updates the `isDirectlyInstantiated` and `isIndirectlyInstantiated`
|
||||||
/// properties of the [ClassHierarchyNode] for [cls].
|
/// properties of the [ClassHierarchyNode] for [cls].
|
||||||
|
void updateClassHierarchyNodeForClass(
|
||||||
|
ClassElement cls,
|
||||||
|
{bool directlyInstantiated: false,
|
||||||
|
bool indirectlyInstantiated: false}) {
|
||||||
|
assert(!directlyInstantiated || isInstantiated(cls));
|
||||||
|
ClassHierarchyNode node = getClassHierarchyNode(cls);
|
||||||
|
bool changed = false;
|
||||||
|
if (directlyInstantiated && !node.isDirectlyInstantiated) {
|
||||||
|
node.isDirectlyInstantiated = true;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (indirectlyInstantiated && !node.isIndirectlyInstantiated) {
|
||||||
|
node.isIndirectlyInstantiated = true;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (changed && cls.superclass != null) {
|
||||||
|
updateClassHierarchyNodeForClass(
|
||||||
|
cls.superclass, indirectlyInstantiated: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void addSubtypes(ClassElement cls) {
|
void addSubtypes(ClassElement cls) {
|
||||||
if (compiler.hasIncrementalSupport && !alreadyPopulated.add(cls)) {
|
if (compiler.hasIncrementalSupport && !alreadyPopulated.add(cls)) {
|
||||||
|
@ -578,7 +525,7 @@ class World implements ClassWorld {
|
||||||
reporter.internalError(cls, 'Class "${cls.name}" is not resolved.');
|
reporter.internalError(cls, 'Class "${cls.name}" is not resolved.');
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateClassHierarchyNodeForClass(cls, directlyInstantiated: true);
|
updateClassHierarchyNodeForClass(cls, directlyInstantiated: true);
|
||||||
|
|
||||||
// Walk through the superclasses, and record the types
|
// Walk through the superclasses, and record the types
|
||||||
// implemented by that type on the superclasses.
|
// implemented by that type on the superclasses.
|
||||||
|
|
|
@ -12,7 +12,7 @@ import "package:compiler/src/elements/elements.dart"
|
||||||
show Element, ClassElement, MemberSignature, Name, PublicName,
|
show Element, ClassElement, MemberSignature, Name, PublicName,
|
||||||
DeclaredMember, Member;
|
DeclaredMember, Member;
|
||||||
import "package:compiler/src/resolution/class_members.dart"
|
import "package:compiler/src/resolution/class_members.dart"
|
||||||
show MembersCreator, DeclaredMember, ErroneousMember, SyntheticMember;
|
show DeclaredMember, ErroneousMember, SyntheticMember;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testClassMembers();
|
testClassMembers();
|
||||||
|
@ -212,8 +212,6 @@ void testClassMembers() {
|
||||||
functionType: env.functionType(String_, []));
|
functionType: env.functionType(String_, []));
|
||||||
|
|
||||||
InterfaceType A = env['A'];
|
InterfaceType A = env['A'];
|
||||||
MembersCreator.computeAllClassMembers(env.compiler, A.element);
|
|
||||||
|
|
||||||
checkMemberCount(A, 5 /*inherited*/ + 9 /*non-static declared*/,
|
checkMemberCount(A, 5 /*inherited*/ + 9 /*non-static declared*/,
|
||||||
interfaceMembers: true);
|
interfaceMembers: true);
|
||||||
checkMemberCount(A, 5 /*inherited*/ + 9 /*non-abstract declared*/ +
|
checkMemberCount(A, 5 /*inherited*/ + 9 /*non-abstract declared*/ +
|
||||||
|
@ -257,7 +255,6 @@ void testClassMembers() {
|
||||||
isStatic: true, functionType: env.functionType(dynamic_, []));
|
isStatic: true, functionType: env.functionType(dynamic_, []));
|
||||||
|
|
||||||
ClassElement B = env.getElement('B');
|
ClassElement B = env.getElement('B');
|
||||||
MembersCreator.computeAllClassMembers(env.compiler, B);
|
|
||||||
InterfaceType B_this = B.thisType;
|
InterfaceType B_this = B.thisType;
|
||||||
TypeVariableType B_T = B_this.typeArguments.first;
|
TypeVariableType B_T = B_this.typeArguments.first;
|
||||||
checkMemberCount(B_this, 4 /*inherited*/ + 4 /*non-static declared*/,
|
checkMemberCount(B_this, 4 /*inherited*/ + 4 /*non-static declared*/,
|
||||||
|
@ -283,7 +280,6 @@ void testClassMembers() {
|
||||||
optionalParameters: [B_T]));
|
optionalParameters: [B_T]));
|
||||||
|
|
||||||
ClassElement C = env.getElement('C');
|
ClassElement C = env.getElement('C');
|
||||||
MembersCreator.computeAllClassMembers(env.compiler, C);
|
|
||||||
InterfaceType C_this = C.thisType;
|
InterfaceType C_this = C.thisType;
|
||||||
TypeVariableType C_S = C_this.typeArguments.first;
|
TypeVariableType C_S = C_this.typeArguments.first;
|
||||||
checkMemberCount(C_this, 8 /*inherited*/, interfaceMembers: true);
|
checkMemberCount(C_this, 8 /*inherited*/, interfaceMembers: true);
|
||||||
|
@ -310,7 +306,6 @@ void testClassMembers() {
|
||||||
optionalParameters: [C_S]));
|
optionalParameters: [C_S]));
|
||||||
|
|
||||||
InterfaceType D = env['D'];
|
InterfaceType D = env['D'];
|
||||||
MembersCreator.computeAllClassMembers(env.compiler, D.element);
|
|
||||||
checkMemberCount(D, 8 /*inherited*/, interfaceMembers: true);
|
checkMemberCount(D, 8 /*inherited*/, interfaceMembers: true);
|
||||||
checkMemberCount(D, 8 /*inherited*/, interfaceMembers: false);
|
checkMemberCount(D, 8 /*inherited*/, interfaceMembers: false);
|
||||||
InterfaceType B_int = instantiate(B, [int_]);
|
InterfaceType B_int = instantiate(B, [int_]);
|
||||||
|
@ -335,7 +330,6 @@ void testClassMembers() {
|
||||||
optionalParameters: [int_]));
|
optionalParameters: [int_]));
|
||||||
|
|
||||||
InterfaceType E = env['E'];
|
InterfaceType E = env['E'];
|
||||||
MembersCreator.computeAllClassMembers(env.compiler, E.element);
|
|
||||||
checkMemberCount(E, 8 /*inherited*/, interfaceMembers: true);
|
checkMemberCount(E, 8 /*inherited*/, interfaceMembers: true);
|
||||||
checkMemberCount(E, 8 /*inherited*/, interfaceMembers: false);
|
checkMemberCount(E, 8 /*inherited*/, interfaceMembers: false);
|
||||||
|
|
||||||
|
@ -417,9 +411,6 @@ void testInterfaceMembers() {
|
||||||
InterfaceType C = env['C'];
|
InterfaceType C = env['C'];
|
||||||
InterfaceType D = env['D'];
|
InterfaceType D = env['D'];
|
||||||
|
|
||||||
// Ensure that members have been computed on all classes.
|
|
||||||
MembersCreator.computeAllClassMembers(env.compiler, D.element);
|
|
||||||
|
|
||||||
// A: num method1()
|
// A: num method1()
|
||||||
// B: int method1()
|
// B: int method1()
|
||||||
// D: dynamic method1() -- synthesized from A and B.
|
// D: dynamic method1() -- synthesized from A and B.
|
||||||
|
@ -585,9 +576,6 @@ void testClassVsInterfaceMembers() {
|
||||||
InterfaceType B = env['B'];
|
InterfaceType B = env['B'];
|
||||||
InterfaceType C = env['C'];
|
InterfaceType C = env['C'];
|
||||||
|
|
||||||
// Ensure that members have been computed on all classes.
|
|
||||||
MembersCreator.computeAllClassMembers(env.compiler, C.element);
|
|
||||||
|
|
||||||
// A: method1()
|
// A: method1()
|
||||||
// B: method1()
|
// B: method1()
|
||||||
// C class: method1() -- inherited from A.
|
// C class: method1() -- inherited from A.
|
||||||
|
@ -646,9 +634,6 @@ void testMixinMembers() {
|
||||||
InterfaceType A_U = instantiate(A, [C_U]);
|
InterfaceType A_U = instantiate(A, [C_U]);
|
||||||
InterfaceType B_V = instantiate(B, [C_V]);
|
InterfaceType B_V = instantiate(B, [C_V]);
|
||||||
|
|
||||||
// Ensure that members have been computed on all classes.
|
|
||||||
MembersCreator.computeAllClassMembers(env.compiler, C);
|
|
||||||
|
|
||||||
// A: method1()
|
// A: method1()
|
||||||
// B: method1()
|
// B: method1()
|
||||||
// C class: method1() -- inherited from A.
|
// C class: method1() -- inherited from A.
|
||||||
|
@ -717,9 +702,6 @@ void testMixinMembersWithoutImplements() {
|
||||||
InterfaceType B = env['B'];
|
InterfaceType B = env['B'];
|
||||||
InterfaceType C = env['C'];
|
InterfaceType C = env['C'];
|
||||||
|
|
||||||
// Ensure that members have been computed on all classes.
|
|
||||||
MembersCreator.computeAllClassMembers(env.compiler, C.element);
|
|
||||||
|
|
||||||
checkMember(C, 'm', checkType: NO_CLASS_MEMBER,
|
checkMember(C, 'm', checkType: NO_CLASS_MEMBER,
|
||||||
inheritedFrom: A,
|
inheritedFrom: A,
|
||||||
functionType: env.functionType(dynamic_ , []));
|
functionType: env.functionType(dynamic_ , []));
|
||||||
|
|
|
@ -63,7 +63,7 @@ const Map<String, String> DEFAULT_CORE_LIBRARY = const <String, String>{
|
||||||
E get current => null;
|
E get current => null;
|
||||||
}''',
|
}''',
|
||||||
'LinkedHashMap': r'''
|
'LinkedHashMap': r'''
|
||||||
class LinkedHashMap<K, V> implements Map<K, V> {
|
class LinkedHashMap {
|
||||||
factory LinkedHashMap._empty() => null;
|
factory LinkedHashMap._empty() => null;
|
||||||
factory LinkedHashMap._literal(elements) => null;
|
factory LinkedHashMap._literal(elements) => null;
|
||||||
static _makeEmpty() => null;
|
static _makeEmpty() => null;
|
||||||
|
|
|
@ -914,7 +914,6 @@ Future testPatchAndSelector() async {
|
||||||
""",
|
""",
|
||||||
runCompiler: true, analyzeOnly: true);
|
runCompiler: true, analyzeOnly: true);
|
||||||
World world = compiler.world;
|
World world = compiler.world;
|
||||||
world.populate();
|
|
||||||
|
|
||||||
ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
|
ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
|
||||||
expectIsPatched: true);
|
expectIsPatched: true);
|
||||||
|
|
|
@ -76,9 +76,8 @@ class RuleSet {
|
||||||
|
|
||||||
var r1 = operate(type1, type2);
|
var r1 = operate(type1, type2);
|
||||||
var r2 = operate(type2, type1);
|
var r2 = operate(type2, type1);
|
||||||
Expect.equals(result, r1,
|
Expect.equals(result, r1);
|
||||||
"Unexpected result of $name($type1,$type2)");
|
Expect.equals(r1, r2, 'symmetry violation');
|
||||||
Expect.equals(r1, r2, 'Symmetry violation of $name($type1,$type2)');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(type1, type2, predicate) {
|
void check(type1, type2, predicate) {
|
||||||
|
@ -732,11 +731,7 @@ void testRegressions(MockCompiler compiler) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
asyncTest(() async {
|
asyncTest(() => MockCompiler.create((MockCompiler compiler) {
|
||||||
MockCompiler compiler = new MockCompiler.internal();
|
|
||||||
await compiler.init("""
|
|
||||||
class PatternImpl implements Pattern {}
|
|
||||||
""");
|
|
||||||
JavaScriptBackend backend = compiler.backend;
|
JavaScriptBackend backend = compiler.backend;
|
||||||
BackendHelpers helpers = backend.helpers;
|
BackendHelpers helpers = backend.helpers;
|
||||||
World world = compiler.world;
|
World world = compiler.world;
|
||||||
|
@ -749,9 +744,6 @@ void main() {
|
||||||
compiler.globalDependencies);
|
compiler.globalDependencies);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ClassElement patternImplClass = compiler.mainApp.find('PatternImpl');
|
|
||||||
patternImplClass.ensureResolved(compiler.resolution);
|
|
||||||
|
|
||||||
backend.registerInstantiatedType(
|
backend.registerInstantiatedType(
|
||||||
compiler.coreTypes.mapType(),
|
compiler.coreTypes.mapType(),
|
||||||
compiler.enqueuer.resolution,
|
compiler.enqueuer.resolution,
|
||||||
|
@ -760,10 +752,6 @@ void main() {
|
||||||
compiler.coreTypes.functionType,
|
compiler.coreTypes.functionType,
|
||||||
compiler.enqueuer.resolution,
|
compiler.enqueuer.resolution,
|
||||||
compiler.globalDependencies);
|
compiler.globalDependencies);
|
||||||
backend.registerInstantiatedType(
|
|
||||||
patternImplClass.rawType,
|
|
||||||
compiler.enqueuer.resolution,
|
|
||||||
compiler.globalDependencies);
|
|
||||||
compiler.world.populate();
|
compiler.world.populate();
|
||||||
|
|
||||||
// Grab hold of a supertype for String so we can produce potential
|
// Grab hold of a supertype for String so we can produce potential
|
||||||
|
@ -817,15 +805,8 @@ void main() {
|
||||||
dynamicType = new TypeMask.subclass(
|
dynamicType = new TypeMask.subclass(
|
||||||
compiler.coreClasses.objectClass, world);
|
compiler.coreClasses.objectClass, world);
|
||||||
|
|
||||||
Expect.notEquals(emptyType, nonPrimitive1,
|
|
||||||
"nonPrimitive1 expected to be non-empty.");
|
|
||||||
Expect.notEquals(jsStringOrNull, potentialString,
|
|
||||||
"potentialString expected not to be exact JSString");
|
|
||||||
Expect.notEquals(jsArrayOrNull, potentialArray,
|
|
||||||
"potentialArray expected not to be JSArray subclass");
|
|
||||||
|
|
||||||
testUnion(compiler);
|
testUnion(compiler);
|
||||||
testIntersection(compiler);
|
testIntersection(compiler);
|
||||||
testRegressions(compiler);
|
testRegressions(compiler);
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,12 @@
|
||||||
|
|
||||||
library type_mask2_test;
|
library type_mask2_test;
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'package:expect/expect.dart';
|
import 'package:expect/expect.dart';
|
||||||
import 'package:async_helper/async_helper.dart';
|
import 'package:async_helper/async_helper.dart';
|
||||||
import 'type_test_helper.dart';
|
import 'type_test_helper.dart';
|
||||||
import 'package:compiler/src/elements/elements.dart'
|
import 'package:compiler/src/elements/elements.dart'
|
||||||
show Element, ClassElement;
|
show Element, ClassElement;
|
||||||
import 'package:compiler/src/types/types.dart';
|
import 'package:compiler/src/types/types.dart';
|
||||||
import 'package:compiler/src/world.dart' show
|
|
||||||
ClassWorld;
|
|
||||||
|
|
||||||
isCheckedMode() {
|
isCheckedMode() {
|
||||||
try {
|
try {
|
||||||
|
@ -25,67 +22,11 @@ isCheckedMode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
asyncTest(() async {
|
testUnionTypeMaskFlatten();
|
||||||
await testUnionTypeMaskFlatten();
|
|
||||||
await testStringSubtypes();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkMasks(ClassWorld classWorld,
|
void testUnionTypeMaskFlatten() {
|
||||||
List<ClassElement> allClasses,
|
asyncTest(() => TypeEnvironment.create(r"""
|
||||||
List<FlatTypeMask> masks,
|
|
||||||
{FlatTypeMask result,
|
|
||||||
List<FlatTypeMask> disjointMasks,
|
|
||||||
FlatTypeMask flattened,
|
|
||||||
List<ClassElement> containedClasses}) {
|
|
||||||
List<FlatTypeMask> disjoint = <FlatTypeMask>[];
|
|
||||||
UnionTypeMask.unionOfHelper(masks, disjoint, classWorld);
|
|
||||||
Expect.listEquals(disjointMasks, disjoint,
|
|
||||||
'Unexpected disjoint masks: $disjoint, expected $disjointMasks.');
|
|
||||||
if (flattened == null) {
|
|
||||||
// We only do the invalid call to flatten in checked mode, as flatten's
|
|
||||||
// behaviour in unchecked mode is not defined and thus cannot be
|
|
||||||
// reliably tested.
|
|
||||||
if (isCheckedMode()) {
|
|
||||||
Expect.throws(() => UnionTypeMask.flatten(disjoint, classWorld),
|
|
||||||
(e) => e is AssertionError,
|
|
||||||
'Expect assertion failure on flattening of $disjoint.');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
TypeMask flattenResult =
|
|
||||||
UnionTypeMask.flatten(disjoint, classWorld);
|
|
||||||
Expect.equals(flattened, flattenResult,
|
|
||||||
'Unexpected flattening of $disjoint: '
|
|
||||||
'$flattenResult, expected $flattened.');
|
|
||||||
}
|
|
||||||
var union = UnionTypeMask.unionOf(masks, classWorld);
|
|
||||||
if (result == null) {
|
|
||||||
Expect.isTrue(union is UnionTypeMask,
|
|
||||||
'Expected union of $masks to be a union-type: $union.');
|
|
||||||
Expect.listEquals(disjointMasks, union.disjointMasks,
|
|
||||||
'Unexpected union masks: '
|
|
||||||
'${union.disjointMasks}, expected $disjointMasks.');
|
|
||||||
} else {
|
|
||||||
Expect.equals(result, union,
|
|
||||||
'Unexpected union of $masks: $union, expected $result.');
|
|
||||||
}
|
|
||||||
if (containedClasses != null) {
|
|
||||||
for (ClassElement cls in allClasses) {
|
|
||||||
if (containedClasses.contains(cls)) {
|
|
||||||
Expect.isTrue(union.contains(cls, classWorld),
|
|
||||||
'Expected $union to contain $cls.');
|
|
||||||
} else {
|
|
||||||
Expect.isFalse(union.contains(cls, classWorld),
|
|
||||||
'$union not expected to contain $cls.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return union;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future testUnionTypeMaskFlatten() async {
|
|
||||||
TypeEnvironment env = await TypeEnvironment.create(r"""
|
|
||||||
class A {}
|
class A {}
|
||||||
class B {}
|
class B {}
|
||||||
class C extends A {}
|
class C extends A {}
|
||||||
|
@ -101,158 +42,153 @@ Future testUnionTypeMaskFlatten() async {
|
||||||
new E();
|
new E();
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
useMockCompiler: false);
|
useMockCompiler: false).then((env) {
|
||||||
|
|
||||||
ClassWorld classWorld = env.compiler.world;
|
|
||||||
|
|
||||||
ClassElement Object_ = env.getElement("Object");
|
|
||||||
ClassElement A = env.getElement("A");
|
|
||||||
ClassElement B = env.getElement("B");
|
|
||||||
ClassElement C = env.getElement("C");
|
|
||||||
ClassElement D = env.getElement("D");
|
|
||||||
ClassElement E = env.getElement("E");
|
|
||||||
|
|
||||||
List<ClassElement> allClasses = <ClassElement>[Object_, A, B, C, D, E];
|
|
||||||
|
|
||||||
check(List<FlatTypeMask> masks,
|
|
||||||
{FlatTypeMask result,
|
|
||||||
List<FlatTypeMask> disjointMasks,
|
|
||||||
FlatTypeMask flattened,
|
|
||||||
List<ClassElement> containedClasses}) {
|
|
||||||
return checkMasks(
|
|
||||||
classWorld,
|
|
||||||
allClasses,
|
|
||||||
masks,
|
|
||||||
result: result,
|
|
||||||
disjointMasks: disjointMasks,
|
|
||||||
flattened: flattened,
|
|
||||||
containedClasses: containedClasses);
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeMask empty = const TypeMask.nonNullEmpty();
|
|
||||||
TypeMask subclassObject = new TypeMask.nonNullSubclass(Object_, classWorld);
|
|
||||||
TypeMask exactA = new TypeMask.nonNullExact(A, classWorld);
|
|
||||||
TypeMask subclassA = new TypeMask.nonNullSubclass(A, classWorld);
|
|
||||||
TypeMask subtypeA = new TypeMask.nonNullSubtype(A, classWorld);
|
|
||||||
TypeMask exactB = new TypeMask.nonNullExact(B, classWorld);
|
|
||||||
TypeMask subclassB = new TypeMask.nonNullSubclass(B, classWorld);
|
|
||||||
TypeMask exactC = new TypeMask.nonNullExact(C, classWorld);
|
|
||||||
TypeMask exactD = new TypeMask.nonNullExact(D, classWorld);
|
|
||||||
TypeMask exactE = new TypeMask.nonNullExact(E, classWorld);
|
|
||||||
|
|
||||||
check([],
|
|
||||||
result: empty,
|
|
||||||
disjointMasks: [],
|
|
||||||
containedClasses: []);
|
|
||||||
|
|
||||||
check([exactA],
|
|
||||||
result: exactA,
|
|
||||||
disjointMasks: [exactA],
|
|
||||||
containedClasses: [A]);
|
|
||||||
|
|
||||||
check([exactA, exactA],
|
|
||||||
result: exactA,
|
|
||||||
disjointMasks: [exactA],
|
|
||||||
containedClasses: [A]);
|
|
||||||
|
|
||||||
check([exactA, exactB],
|
|
||||||
disjointMasks: [exactA, exactB],
|
|
||||||
flattened: subclassObject,
|
|
||||||
containedClasses: [A, B]);
|
|
||||||
|
|
||||||
check([subclassObject],
|
|
||||||
result: subclassObject,
|
|
||||||
disjointMasks: [subclassObject],
|
|
||||||
containedClasses: [Object_, A, B, C, D, E]);
|
|
||||||
|
|
||||||
check([subclassObject, exactA],
|
|
||||||
disjointMasks: [subclassObject],
|
|
||||||
result: subclassObject,
|
|
||||||
containedClasses: [Object_, A, B, C, D, E]);
|
|
||||||
|
|
||||||
check([exactA, exactC],
|
|
||||||
disjointMasks: [subclassA],
|
|
||||||
result: subclassA,
|
|
||||||
containedClasses: [A, C]);
|
|
||||||
|
|
||||||
check([exactA, exactB, exactC],
|
|
||||||
disjointMasks: [subclassA, exactB],
|
|
||||||
flattened: subclassObject,
|
|
||||||
containedClasses: [A, B, C]);
|
|
||||||
|
|
||||||
check([exactA, exactD],
|
|
||||||
disjointMasks: [subtypeA],
|
|
||||||
result: subtypeA,
|
|
||||||
containedClasses: [A, C, D, E]);
|
|
||||||
|
|
||||||
check([exactA, exactB, exactD],
|
|
||||||
disjointMasks: [subtypeA, exactB],
|
|
||||||
flattened: subclassObject,
|
|
||||||
containedClasses: [A, B, C, D, E]);
|
|
||||||
|
|
||||||
check([exactA, exactE],
|
|
||||||
disjointMasks: [subtypeA],
|
|
||||||
result: subtypeA,
|
|
||||||
containedClasses: [A, C, D, E]);
|
|
||||||
|
|
||||||
check([exactA, exactB, exactE],
|
|
||||||
disjointMasks: [subtypeA, exactB],
|
|
||||||
flattened: subclassObject,
|
|
||||||
containedClasses: [A, B, C, D, E]);
|
|
||||||
|
|
||||||
check([exactB, exactE, exactA],
|
|
||||||
disjointMasks: [subclassB, exactA],
|
|
||||||
flattened: subclassObject,
|
|
||||||
containedClasses: [A, B, E]);
|
|
||||||
|
|
||||||
check([exactE, exactA, exactB],
|
|
||||||
disjointMasks: [subtypeA, exactB],
|
|
||||||
flattened: subclassObject,
|
|
||||||
containedClasses: [A, B, C, D, E]);
|
|
||||||
|
|
||||||
check([exactE, exactB, exactA],
|
|
||||||
disjointMasks: [subclassB, exactA],
|
|
||||||
flattened: subclassObject,
|
|
||||||
containedClasses: [A, B, E]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future testStringSubtypes() async {
|
|
||||||
TypeEnvironment env = await TypeEnvironment.create('',
|
|
||||||
mainSource: r"""
|
|
||||||
main() {
|
|
||||||
'' is String;
|
|
||||||
}
|
|
||||||
""",
|
|
||||||
useMockCompiler: false);
|
|
||||||
var classWorld = env.compiler.world;
|
var classWorld = env.compiler.world;
|
||||||
var backend = env.compiler.backend;
|
|
||||||
|
|
||||||
ClassElement Object_ = env.getElement("Object");
|
ClassElement Object_ = env.getElement("Object");
|
||||||
ClassElement String_ = env.getElement("String");
|
ClassElement A = env.getElement("A");
|
||||||
ClassElement JSString = backend.helpers.jsStringClass;
|
ClassElement B = env.getElement("B");
|
||||||
|
ClassElement C = env.getElement("C");
|
||||||
|
ClassElement D = env.getElement("D");
|
||||||
|
ClassElement E = env.getElement("E");
|
||||||
|
|
||||||
List<ClassElement> allClasses = <ClassElement>[Object_, String_];
|
List<ClassElement> allClasses = <ClassElement>[Object_, A, B, C, D, E];
|
||||||
|
|
||||||
Expect.isFalse(classWorld.isDirectlyInstantiated(Object_));
|
check(List<FlatTypeMask> masks,
|
||||||
Expect.isTrue(classWorld.isIndirectlyInstantiated(Object_));
|
{FlatTypeMask result,
|
||||||
Expect.isTrue(classWorld.isInstantiated(Object_));
|
List<FlatTypeMask> disjointMasks,
|
||||||
|
FlatTypeMask flattened,
|
||||||
|
List<ClassElement> containedClasses}) {
|
||||||
|
List<FlatTypeMask> disjoint = <FlatTypeMask>[];
|
||||||
|
UnionTypeMask.unionOfHelper(masks, disjoint, classWorld);
|
||||||
|
Expect.listEquals(disjointMasks, disjoint,
|
||||||
|
'Unexpected disjoint masks: $disjoint, expected $disjointMasks.');
|
||||||
|
if (flattened == null) {
|
||||||
|
// We only do the invalid call to flatten in checked mode, as flatten's
|
||||||
|
// brehaviour in unchecked more is not defined and thus cannot be
|
||||||
|
// reliably tested.
|
||||||
|
if (isCheckedMode()) {
|
||||||
|
Expect.throws(() => UnionTypeMask.flatten(disjoint, classWorld),
|
||||||
|
(e) => e is AssertionError,
|
||||||
|
'Expect assertion failure on flattening of $disjoint.');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TypeMask flattenResult =
|
||||||
|
UnionTypeMask.flatten(disjoint, classWorld);
|
||||||
|
Expect.equals(flattened, flattenResult,
|
||||||
|
'Unexpected flattening of $disjoint: '
|
||||||
|
'$flattenResult, expected $flattened.');
|
||||||
|
}
|
||||||
|
var union = UnionTypeMask.unionOf(masks, classWorld);
|
||||||
|
if (result == null) {
|
||||||
|
Expect.isTrue(union is UnionTypeMask,
|
||||||
|
'Expected union of $masks to be a union-type: $union.');
|
||||||
|
Expect.listEquals(disjointMasks, union.disjointMasks,
|
||||||
|
'Unexpected union masks: '
|
||||||
|
'${union.disjointMasks}, expected $disjointMasks.');
|
||||||
|
} else {
|
||||||
|
Expect.equals(result, union,
|
||||||
|
'Unexpected union of $masks: $union, expected $result.');
|
||||||
|
}
|
||||||
|
if (containedClasses != null) {
|
||||||
|
for (ClassElement cls in allClasses) {
|
||||||
|
if (containedClasses.contains(cls)) {
|
||||||
|
Expect.isTrue(union.contains(cls, classWorld),
|
||||||
|
'Expected $union to contain $cls.');
|
||||||
|
} else {
|
||||||
|
Expect.isFalse(union.contains(cls, classWorld),
|
||||||
|
'$union not expected to contain $cls.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Expect.isFalse(classWorld.isDirectlyInstantiated(String_));
|
}
|
||||||
Expect.isFalse(classWorld.isIndirectlyInstantiated(String_));
|
return union;
|
||||||
Expect.isFalse(classWorld.isInstantiated(String_));
|
}
|
||||||
|
|
||||||
Expect.isTrue(classWorld.isDirectlyInstantiated(JSString));
|
TypeMask empty = const TypeMask.nonNullEmpty();
|
||||||
Expect.isFalse(classWorld.isIndirectlyInstantiated(JSString));
|
TypeMask subclassObject = new TypeMask.nonNullSubclass(Object_, classWorld);
|
||||||
Expect.isTrue(classWorld.isInstantiated(JSString));
|
TypeMask exactA = new TypeMask.nonNullExact(A, classWorld);
|
||||||
|
TypeMask subclassA = new TypeMask.nonNullSubclass(A, classWorld);
|
||||||
|
TypeMask subtypeA = new TypeMask.nonNullSubtype(A, classWorld);
|
||||||
|
TypeMask exactB = new TypeMask.nonNullExact(B, classWorld);
|
||||||
|
TypeMask subclassB = new TypeMask.nonNullSubclass(B, classWorld);
|
||||||
|
TypeMask exactC = new TypeMask.nonNullExact(C, classWorld);
|
||||||
|
TypeMask exactD = new TypeMask.nonNullExact(D, classWorld);
|
||||||
|
TypeMask exactE = new TypeMask.nonNullExact(E, classWorld);
|
||||||
|
|
||||||
TypeMask subtypeString = new TypeMask.nonNullSubtype(String_, classWorld);
|
check([],
|
||||||
TypeMask exactJSString = new TypeMask.nonNullExact(JSString, classWorld);
|
result: empty,
|
||||||
TypeMask subtypeJSString =
|
disjointMasks: [],
|
||||||
new TypeMask.nonNullSubtype(JSString, classWorld);
|
containedClasses: []);
|
||||||
TypeMask subclassJSString =
|
|
||||||
new TypeMask.nonNullSubclass(JSString, classWorld);
|
|
||||||
|
|
||||||
Expect.equals(exactJSString, subtypeString);
|
check([exactA],
|
||||||
Expect.equals(exactJSString, subtypeJSString);
|
result: exactA,
|
||||||
Expect.equals(exactJSString, subclassJSString);
|
disjointMasks: [exactA],
|
||||||
|
containedClasses: [A]);
|
||||||
|
|
||||||
|
check([exactA, exactA],
|
||||||
|
result: exactA,
|
||||||
|
disjointMasks: [exactA],
|
||||||
|
containedClasses: [A]);
|
||||||
|
|
||||||
|
check([exactA, exactB],
|
||||||
|
disjointMasks: [exactA, exactB],
|
||||||
|
flattened: subclassObject,
|
||||||
|
containedClasses: [A, B]);
|
||||||
|
|
||||||
|
check([subclassObject],
|
||||||
|
result: subclassObject,
|
||||||
|
disjointMasks: [subclassObject],
|
||||||
|
containedClasses: [Object_, A, B, C, D, E]);
|
||||||
|
|
||||||
|
check([subclassObject, exactA],
|
||||||
|
disjointMasks: [subclassObject],
|
||||||
|
result: subclassObject,
|
||||||
|
containedClasses: [Object_, A, B, C, D, E]);
|
||||||
|
|
||||||
|
check([exactA, exactC],
|
||||||
|
disjointMasks: [subclassA],
|
||||||
|
result: subclassA,
|
||||||
|
containedClasses: [A, C]);
|
||||||
|
|
||||||
|
check([exactA, exactB, exactC],
|
||||||
|
disjointMasks: [subclassA, exactB],
|
||||||
|
flattened: subclassObject,
|
||||||
|
containedClasses: [A, B, C]);
|
||||||
|
|
||||||
|
check([exactA, exactD],
|
||||||
|
disjointMasks: [subtypeA],
|
||||||
|
result: subtypeA,
|
||||||
|
containedClasses: [A, C, D, E]);
|
||||||
|
|
||||||
|
check([exactA, exactB, exactD],
|
||||||
|
disjointMasks: [subtypeA, exactB],
|
||||||
|
flattened: subclassObject,
|
||||||
|
containedClasses: [A, B, C, D, E]);
|
||||||
|
|
||||||
|
check([exactA, exactE],
|
||||||
|
disjointMasks: [subtypeA],
|
||||||
|
result: subtypeA,
|
||||||
|
containedClasses: [A, C, D, E]);
|
||||||
|
|
||||||
|
check([exactA, exactB, exactE],
|
||||||
|
disjointMasks: [subtypeA, exactB],
|
||||||
|
flattened: subclassObject,
|
||||||
|
containedClasses: [A, B, C, D, E]);
|
||||||
|
|
||||||
|
check([exactB, exactE, exactA],
|
||||||
|
disjointMasks: [subclassB, exactA],
|
||||||
|
flattened: subclassObject,
|
||||||
|
containedClasses: [A, B, E]);
|
||||||
|
|
||||||
|
check([exactE, exactA, exactB],
|
||||||
|
disjointMasks: [subtypeA, exactB],
|
||||||
|
flattened: subclassObject,
|
||||||
|
containedClasses: [A, B, C, D, E]);
|
||||||
|
|
||||||
|
check([exactE, exactB, exactA],
|
||||||
|
disjointMasks: [subclassB, exactA],
|
||||||
|
flattened: subclassObject,
|
||||||
|
containedClasses: [A, B, E]);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,29 +5,22 @@
|
||||||
import "package:async_helper/async_helper.dart";
|
import "package:async_helper/async_helper.dart";
|
||||||
import "package:expect/expect.dart";
|
import "package:expect/expect.dart";
|
||||||
import "package:compiler/src/types/types.dart";
|
import "package:compiler/src/types/types.dart";
|
||||||
import "package:compiler/src/world.dart";
|
|
||||||
import 'type_test_helper.dart';
|
import "compiler_helper.dart";
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
|
MockCompiler compiler = new MockCompiler.internal(analyzeOnly: true);
|
||||||
asyncTest(() async {
|
asyncTest(() => compiler.run(null, """
|
||||||
TypeEnvironment env = await TypeEnvironment.create(r"""
|
|
||||||
class A {}
|
|
||||||
class B {}
|
|
||||||
""",
|
|
||||||
mainSource: r"""
|
|
||||||
main() {
|
main() {
|
||||||
new A();
|
print(2); print("Hello");
|
||||||
new B();
|
|
||||||
}
|
}
|
||||||
""",
|
""").then((_) {
|
||||||
useMockCompiler: false);
|
FlatTypeMask mask1 =
|
||||||
World world = env.compiler.world;
|
new FlatTypeMask.exact(compiler.coreClasses.intClass);
|
||||||
world.populate();
|
FlatTypeMask mask2 =
|
||||||
FlatTypeMask mask1 = new FlatTypeMask.exact(env.getElement('A'));
|
new FlatTypeMask.exact(compiler.coreClasses.stringClass);
|
||||||
FlatTypeMask mask2 = new FlatTypeMask.exact(env.getElement('B'));
|
UnionTypeMask union1 = mask1.nonNullable().union(mask2, compiler.world);
|
||||||
UnionTypeMask union1 = mask1.nonNullable().union(mask2, world);
|
UnionTypeMask union2 = mask2.nonNullable().union(mask1, compiler.world);
|
||||||
UnionTypeMask union2 = mask2.nonNullable().union(mask1, world);
|
|
||||||
Expect.equals(union1, union2);
|
Expect.equals(union1, union2);
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue