mirror of
https://github.com/dart-lang/sdk
synced 2024-09-06 00:59:09 +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);
|
||||
ClosureClassElement globalizedElement = new ClosureClassElement(
|
||||
node, closureName, compiler, element);
|
||||
// Extend [globalizedElement] as an instantiated class in the closed world.
|
||||
compiler.world.registerClass(
|
||||
globalizedElement, isDirectlyInstantiated: true);
|
||||
FunctionElement callElement =
|
||||
new SynthesizedCallMethodElementX(Identifiers.call,
|
||||
element,
|
||||
|
|
|
@ -25,13 +25,6 @@ class TypeMaskSystem {
|
|||
final World classWorld;
|
||||
final JavaScriptBackend backend;
|
||||
|
||||
TypeMask _numStringBoolType;
|
||||
TypeMask _fixedLengthType;
|
||||
TypeMask _interceptorType;
|
||||
TypeMask _interceptedTypes; // Does not include null.
|
||||
|
||||
TypeMask __indexableTypeTest;
|
||||
|
||||
TypeMask get dynamicType => inferrer.dynamicType;
|
||||
TypeMask get typeType => inferrer.typeType;
|
||||
TypeMask get functionType => inferrer.functionType;
|
||||
|
@ -50,70 +43,12 @@ class TypeMaskSystem {
|
|||
TypeMask get uint32Type => inferrer.uint32Type;
|
||||
TypeMask get uintType => inferrer.positiveIntType;
|
||||
|
||||
TypeMask get numStringBoolType {
|
||||
if (_numStringBoolType == null) {
|
||||
// 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);
|
||||
}
|
||||
return _numStringBoolType;
|
||||
}
|
||||
TypeMask numStringBoolType;
|
||||
TypeMask fixedLengthType;
|
||||
TypeMask interceptorType;
|
||||
TypeMask interceptedTypes; // Does not include null.
|
||||
|
||||
TypeMask get fixedLengthType {
|
||||
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;
|
||||
}
|
||||
TypeMask _indexableTypeTest;
|
||||
|
||||
ClassElement get jsNullClass => helpers.jsNullClass;
|
||||
|
||||
|
@ -124,6 +59,41 @@ class TypeMaskSystem {
|
|||
: inferrer = compiler.typesTask,
|
||||
classWorld = compiler.world,
|
||||
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) {
|
||||
|
|
|
@ -178,19 +178,15 @@ abstract class Enqueuer {
|
|||
task.measure(() {
|
||||
ClassElement cls = type.element;
|
||||
cls.ensureResolved(resolution);
|
||||
bool isNative = compiler.backend.isNative(cls);
|
||||
universe.registerTypeInstantiation(
|
||||
type,
|
||||
isNative: isNative,
|
||||
isNative: compiler.backend.isNative(cls),
|
||||
byMirrors: mirrorUsage,
|
||||
onImplemented: (ClassElement cls) {
|
||||
compiler.backend.registerImplementedClass(
|
||||
cls, this, compiler.globalDependencies);
|
||||
});
|
||||
// TODO(johnniwinther): Share this reasoning with [Universe].
|
||||
if (!cls.isAbstract || isNative || mirrorUsage) {
|
||||
processInstantiatedClass(cls);
|
||||
}
|
||||
processInstantiatedClass(cls);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -339,10 +335,9 @@ abstract class Enqueuer {
|
|||
superclass, this, compiler.globalDependencies);
|
||||
}
|
||||
|
||||
ClassElement superclass = cls;
|
||||
while (superclass != null) {
|
||||
processClass(superclass);
|
||||
superclass = superclass.superclass;
|
||||
while (cls != null) {
|
||||
processClass(cls);
|
||||
cls = cls.superclass;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -647,19 +647,7 @@ class SimpleTypeInferrerVisitor<T>
|
|||
}
|
||||
});
|
||||
}
|
||||
if (analyzedElement.isGenerativeConstructor && cls.isAbstract) {
|
||||
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);
|
||||
}
|
||||
returnType = types.nonNullExact(cls);
|
||||
} else {
|
||||
signature.forEachParameter((LocalParameterElement element) {
|
||||
locals.update(element, inferrer.typeOfElement(element), node);
|
||||
|
|
|
@ -3247,7 +3247,7 @@ class SsaBuilder extends ast.Visitor
|
|||
});
|
||||
|
||||
TypeMask type =
|
||||
new TypeMask.nonNullExact(closureClassElement, compiler.world);
|
||||
new TypeMask.nonNullExact(coreClasses.functionClass, compiler.world);
|
||||
push(new HForeignNew(closureClassElement, type, capturedVariables)
|
||||
..sourceInformation = sourceInformationBuilder.buildCreate(node));
|
||||
|
||||
|
@ -5074,13 +5074,7 @@ class SsaBuilder extends ast.Visitor
|
|||
: inferred;
|
||||
} else if (element.isGenerativeConstructor) {
|
||||
ClassElement cls = element.enclosingClass;
|
||||
if (cls.isAbstract) {
|
||||
// An error will be thrown.
|
||||
return new TypeMask.nonNullEmpty();
|
||||
} else {
|
||||
return new TypeMask.nonNullExact(
|
||||
cls.thisType.element, compiler.world);
|
||||
}
|
||||
return new TypeMask.nonNullExact(cls.thisType.element, compiler.world);
|
||||
} else {
|
||||
return TypeMaskFactory.inferredReturnTypeForElement(
|
||||
originalElement, compiler);
|
||||
|
|
|
@ -546,8 +546,9 @@ class FlatTypeMask implements TypeMask {
|
|||
*/
|
||||
static bool hasConcreteMatch(ClassElement cls,
|
||||
Selector selector,
|
||||
ClassWorld world) {
|
||||
assert(invariant(cls, world.isInstantiated(cls),
|
||||
World world) {
|
||||
assert(invariant(cls,
|
||||
world.compiler.resolverWorld.isInstantiated(cls),
|
||||
message: '$cls has not been instantiated.'));
|
||||
Element element = findMatchIn(cls, selector);
|
||||
if (element == null) return false;
|
||||
|
|
|
@ -89,7 +89,7 @@ abstract class TypeMask implements ReceiverConstraint {
|
|||
factory TypeMask.exact(ClassElement base, ClassWorld classWorld) {
|
||||
assert(invariant(base, classWorld.isInstantiated(base),
|
||||
message: () => "Cannot create exact type mask for uninstantiated "
|
||||
"class $base.\n${classWorld.dump(base)}"));
|
||||
"class $base.\n${classWorld.dump()}"));
|
||||
return new FlatTypeMask.exact(base);
|
||||
}
|
||||
|
||||
|
@ -99,31 +99,21 @@ abstract class TypeMask implements ReceiverConstraint {
|
|||
}
|
||||
|
||||
factory TypeMask.subclass(ClassElement base, ClassWorld classWorld) {
|
||||
assert(invariant(base, classWorld.isInstantiated(base),
|
||||
message: () => "Cannot create subclass type mask for uninstantiated "
|
||||
"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);
|
||||
if (classWorld.hasAnyStrictSubclass(base)) {
|
||||
return new FlatTypeMask.subclass(base);
|
||||
} else {
|
||||
return new TypeMask.exact(topmost, classWorld);
|
||||
return new TypeMask.exactOrEmpty(base, classWorld);
|
||||
}
|
||||
}
|
||||
|
||||
factory TypeMask.subtype(ClassElement base, ClassWorld classWorld) {
|
||||
ClassElement topmost = classWorld.getLubOfInstantiatedSubtypes(base);
|
||||
if (topmost == null) {
|
||||
return new TypeMask.empty();
|
||||
if (classWorld.hasOnlySubclasses(base)) {
|
||||
return new TypeMask.subclass(base, classWorld);
|
||||
}
|
||||
if (classWorld.hasOnlySubclasses(topmost)) {
|
||||
return new TypeMask.subclass(topmost, classWorld);
|
||||
}
|
||||
if (classWorld.hasAnyStrictSubtype(topmost)) {
|
||||
return new FlatTypeMask.subtype(topmost);
|
||||
if (classWorld.hasAnyStrictSubtype(base)) {
|
||||
return new FlatTypeMask.subtype(base);
|
||||
} 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) {
|
||||
assert(invariant(base, classWorld.isInstantiated(base),
|
||||
message: () => "Cannot create exact type mask for uninstantiated "
|
||||
"class $base.\n${classWorld.dump(base)}"));
|
||||
message: () => "Cannot create exact type mask for "
|
||||
"uninstantiated class $base.\n${classWorld.dump(base)}"));
|
||||
return new FlatTypeMask.nonNullExact(base);
|
||||
}
|
||||
|
||||
|
@ -145,31 +135,21 @@ abstract class TypeMask implements ReceiverConstraint {
|
|||
}
|
||||
|
||||
factory TypeMask.nonNullSubclass(ClassElement base, ClassWorld classWorld) {
|
||||
assert(invariant(base, classWorld.isInstantiated(base),
|
||||
message: () => "Cannot create subclass type mask for uninstantiated "
|
||||
"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);
|
||||
if (classWorld.hasAnyStrictSubclass(base)) {
|
||||
return new FlatTypeMask.nonNullSubclass(base);
|
||||
} else {
|
||||
return new TypeMask.nonNullExact(topmost, classWorld);
|
||||
return new TypeMask.nonNullExactOrEmpty(base, classWorld);
|
||||
}
|
||||
}
|
||||
|
||||
factory TypeMask.nonNullSubtype(ClassElement base, ClassWorld classWorld) {
|
||||
ClassElement topmost = classWorld.getLubOfInstantiatedSubtypes(base);
|
||||
if (topmost == null) {
|
||||
return new TypeMask.nonNullEmpty();
|
||||
if (classWorld.hasOnlySubclasses(base)) {
|
||||
return new TypeMask.nonNullSubclass(base, classWorld);
|
||||
}
|
||||
if (classWorld.hasOnlySubclasses(topmost)) {
|
||||
return new TypeMask.nonNullSubclass(topmost, classWorld);
|
||||
}
|
||||
if (classWorld.hasAnyStrictSubtype(topmost)) {
|
||||
return new FlatTypeMask.nonNullSubtype(topmost);
|
||||
if (classWorld.hasAnyStrictSubtype(base)) {
|
||||
return new FlatTypeMask.nonNullSubtype(base);
|
||||
} 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 {
|
||||
final ClassElement cls;
|
||||
ClassElement _leastUpperInstantiatedSubclass;
|
||||
|
||||
/// `true` if [cls] has been directly instantiated.
|
||||
///
|
||||
|
@ -102,55 +101,15 @@ class ClassHierarchyNode {
|
|||
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,
|
||||
{bool instantiatedOnly: false,
|
||||
bool sorted: true,
|
||||
ClassElement withRespectTo}) {
|
||||
|
||||
bool isRelatedTo(ClassElement subclass) {
|
||||
return subclass == withRespectTo ||
|
||||
subclass.implementsInterface(withRespectTo);
|
||||
return subclass.implementsInterface(withRespectTo);
|
||||
}
|
||||
|
||||
sb.write(indentation);
|
||||
if (cls.isAbstract) {
|
||||
sb.write('abstract ');
|
||||
}
|
||||
sb.write('class ${cls.name}:');
|
||||
sb.write('$indentation$cls');
|
||||
if (isDirectlyInstantiated) {
|
||||
sb.write(' directly');
|
||||
}
|
||||
|
@ -161,14 +120,11 @@ class ClassHierarchyNode {
|
|||
if (_directSubclasses.isEmpty) {
|
||||
sb.write(']');
|
||||
} else {
|
||||
var subclasses = _directSubclasses;
|
||||
if (sorted) {
|
||||
subclasses = _directSubclasses.toList()..sort((a, b) {
|
||||
return a.cls.name.compareTo(b.cls.name);
|
||||
});
|
||||
}
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
|
@ -184,7 +140,6 @@ class ClassHierarchyNode {
|
|||
sb,
|
||||
'$indentation ',
|
||||
instantiatedOnly: instantiatedOnly,
|
||||
sorted: sorted,
|
||||
withRespectTo: withRespectTo);
|
||||
needsComma = true;
|
||||
}
|
||||
|
@ -256,7 +211,6 @@ class ClassHierarchyNode {
|
|||
///
|
||||
class ClassSet {
|
||||
final ClassHierarchyNode node;
|
||||
ClassElement _leastUpperInstantiatedSubtype;
|
||||
|
||||
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() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.write('[\n');
|
||||
|
|
|
@ -298,11 +298,8 @@ class FullFunctionSetQuery implements FunctionSetQuery {
|
|||
.map((cls) {
|
||||
if (classWorld.backend.isNullImplementation(cls)) {
|
||||
return const TypeMask.empty();
|
||||
} else if (classWorld.isInstantiated(cls.declaration)) {
|
||||
return new TypeMask.nonNullSubclass(cls.declaration, classWorld);
|
||||
} else {
|
||||
// TODO(johnniwinther): Avoid the need for this case.
|
||||
return const TypeMask.empty();
|
||||
return new TypeMask.nonNullSubclass(cls.declaration, classWorld);
|
||||
}
|
||||
}),
|
||||
classWorld);
|
||||
|
|
|
@ -124,6 +124,12 @@ class Universe {
|
|||
/// See [_directlyInstantiatedClasses].
|
||||
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.
|
||||
final Set<ClassElement> _implementedClasses = new Set<ClassElement>();
|
||||
|
||||
|
@ -200,6 +206,13 @@ class Universe {
|
|||
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
|
||||
/// instantiated classes.
|
||||
///
|
||||
|
@ -207,6 +220,13 @@ class Universe {
|
|||
// TODO(johnniwinther): Improve semantic precision.
|
||||
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
|
||||
/// instantiated class, either directly, through subclasses or through
|
||||
/// 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,
|
||||
|
@ -377,6 +403,7 @@ class Universe {
|
|||
fieldSetters.remove(element);
|
||||
fieldGetters.remove(element);
|
||||
_directlyInstantiatedClasses.remove(element);
|
||||
_allInstantiatedClasses.remove(element);
|
||||
if (element is ClassElement) {
|
||||
assert(invariant(
|
||||
element, element.thisType.isRaw,
|
||||
|
|
|
@ -62,16 +62,9 @@ abstract class ClassWorld {
|
|||
/// The [ClassElement] for the [String] class defined in 'dart:core'.
|
||||
ClassElement get stringClass;
|
||||
|
||||
/// Returns `true` if [cls] is either directly or indirectly instantiated.
|
||||
/// Returns `true` if [cls] is instantiated.
|
||||
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.
|
||||
bool isImplemented(ClassElement cls);
|
||||
|
||||
|
@ -113,16 +106,6 @@ abstract class ClassWorld {
|
|||
/// Returns `true` if all live classes that implement [cls] extend it.
|
||||
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].
|
||||
Iterable<ClassElement> commonSupertypesOf(Iterable<ClassElement> classes);
|
||||
|
||||
|
@ -207,22 +190,10 @@ class World implements ClassWorld {
|
|||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
/// Returns `true` if [cls] is instantiated either directly or through a
|
||||
/// subclass.
|
||||
bool isInstantiated(ClassElement cls) {
|
||||
ClassHierarchyNode node = _classHierarchyNodes[cls.declaration];
|
||||
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;
|
||||
return compiler.resolverWorld.isInstantiated(cls);
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
@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].
|
||||
Iterable<ClassElement> commonSupertypesOf(Iterable<ClassElement> classes) {
|
||||
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
|
||||
/// classes that extend or implement it.
|
||||
void registerClass(ClassElement cls, {bool isDirectlyInstantiated: false}) {
|
||||
void registerClass(ClassElement cls) {
|
||||
_ensureClassSet(cls);
|
||||
if (isDirectlyInstantiated) {
|
||||
_updateClassHierarchyNodeForClass(cls, directlyInstantiated: true);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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() {
|
||||
/// Updates the `isDirectlyInstantiated` and `isIndirectlyInstantiated`
|
||||
/// 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) {
|
||||
if (compiler.hasIncrementalSupport && !alreadyPopulated.add(cls)) {
|
||||
|
@ -578,7 +525,7 @@ class World implements ClassWorld {
|
|||
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
|
||||
// implemented by that type on the superclasses.
|
||||
|
|
|
@ -12,7 +12,7 @@ import "package:compiler/src/elements/elements.dart"
|
|||
show Element, ClassElement, MemberSignature, Name, PublicName,
|
||||
DeclaredMember, Member;
|
||||
import "package:compiler/src/resolution/class_members.dart"
|
||||
show MembersCreator, DeclaredMember, ErroneousMember, SyntheticMember;
|
||||
show DeclaredMember, ErroneousMember, SyntheticMember;
|
||||
|
||||
void main() {
|
||||
testClassMembers();
|
||||
|
@ -212,8 +212,6 @@ void testClassMembers() {
|
|||
functionType: env.functionType(String_, []));
|
||||
|
||||
InterfaceType A = env['A'];
|
||||
MembersCreator.computeAllClassMembers(env.compiler, A.element);
|
||||
|
||||
checkMemberCount(A, 5 /*inherited*/ + 9 /*non-static declared*/,
|
||||
interfaceMembers: true);
|
||||
checkMemberCount(A, 5 /*inherited*/ + 9 /*non-abstract declared*/ +
|
||||
|
@ -257,7 +255,6 @@ void testClassMembers() {
|
|||
isStatic: true, functionType: env.functionType(dynamic_, []));
|
||||
|
||||
ClassElement B = env.getElement('B');
|
||||
MembersCreator.computeAllClassMembers(env.compiler, B);
|
||||
InterfaceType B_this = B.thisType;
|
||||
TypeVariableType B_T = B_this.typeArguments.first;
|
||||
checkMemberCount(B_this, 4 /*inherited*/ + 4 /*non-static declared*/,
|
||||
|
@ -283,7 +280,6 @@ void testClassMembers() {
|
|||
optionalParameters: [B_T]));
|
||||
|
||||
ClassElement C = env.getElement('C');
|
||||
MembersCreator.computeAllClassMembers(env.compiler, C);
|
||||
InterfaceType C_this = C.thisType;
|
||||
TypeVariableType C_S = C_this.typeArguments.first;
|
||||
checkMemberCount(C_this, 8 /*inherited*/, interfaceMembers: true);
|
||||
|
@ -310,7 +306,6 @@ void testClassMembers() {
|
|||
optionalParameters: [C_S]));
|
||||
|
||||
InterfaceType D = env['D'];
|
||||
MembersCreator.computeAllClassMembers(env.compiler, D.element);
|
||||
checkMemberCount(D, 8 /*inherited*/, interfaceMembers: true);
|
||||
checkMemberCount(D, 8 /*inherited*/, interfaceMembers: false);
|
||||
InterfaceType B_int = instantiate(B, [int_]);
|
||||
|
@ -335,7 +330,6 @@ void testClassMembers() {
|
|||
optionalParameters: [int_]));
|
||||
|
||||
InterfaceType E = env['E'];
|
||||
MembersCreator.computeAllClassMembers(env.compiler, E.element);
|
||||
checkMemberCount(E, 8 /*inherited*/, interfaceMembers: true);
|
||||
checkMemberCount(E, 8 /*inherited*/, interfaceMembers: false);
|
||||
|
||||
|
@ -417,9 +411,6 @@ void testInterfaceMembers() {
|
|||
InterfaceType C = env['C'];
|
||||
InterfaceType D = env['D'];
|
||||
|
||||
// Ensure that members have been computed on all classes.
|
||||
MembersCreator.computeAllClassMembers(env.compiler, D.element);
|
||||
|
||||
// A: num method1()
|
||||
// B: int method1()
|
||||
// D: dynamic method1() -- synthesized from A and B.
|
||||
|
@ -585,9 +576,6 @@ void testClassVsInterfaceMembers() {
|
|||
InterfaceType B = env['B'];
|
||||
InterfaceType C = env['C'];
|
||||
|
||||
// Ensure that members have been computed on all classes.
|
||||
MembersCreator.computeAllClassMembers(env.compiler, C.element);
|
||||
|
||||
// A: method1()
|
||||
// B: method1()
|
||||
// C class: method1() -- inherited from A.
|
||||
|
@ -646,9 +634,6 @@ void testMixinMembers() {
|
|||
InterfaceType A_U = instantiate(A, [C_U]);
|
||||
InterfaceType B_V = instantiate(B, [C_V]);
|
||||
|
||||
// Ensure that members have been computed on all classes.
|
||||
MembersCreator.computeAllClassMembers(env.compiler, C);
|
||||
|
||||
// A: method1()
|
||||
// B: method1()
|
||||
// C class: method1() -- inherited from A.
|
||||
|
@ -717,9 +702,6 @@ void testMixinMembersWithoutImplements() {
|
|||
InterfaceType B = env['B'];
|
||||
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,
|
||||
inheritedFrom: A,
|
||||
functionType: env.functionType(dynamic_ , []));
|
||||
|
|
|
@ -63,7 +63,7 @@ const Map<String, String> DEFAULT_CORE_LIBRARY = const <String, String>{
|
|||
E get current => null;
|
||||
}''',
|
||||
'LinkedHashMap': r'''
|
||||
class LinkedHashMap<K, V> implements Map<K, V> {
|
||||
class LinkedHashMap {
|
||||
factory LinkedHashMap._empty() => null;
|
||||
factory LinkedHashMap._literal(elements) => null;
|
||||
static _makeEmpty() => null;
|
||||
|
|
|
@ -914,7 +914,6 @@ Future testPatchAndSelector() async {
|
|||
""",
|
||||
runCompiler: true, analyzeOnly: true);
|
||||
World world = compiler.world;
|
||||
world.populate();
|
||||
|
||||
ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
|
||||
expectIsPatched: true);
|
||||
|
|
|
@ -76,9 +76,8 @@ class RuleSet {
|
|||
|
||||
var r1 = operate(type1, type2);
|
||||
var r2 = operate(type2, type1);
|
||||
Expect.equals(result, r1,
|
||||
"Unexpected result of $name($type1,$type2)");
|
||||
Expect.equals(r1, r2, 'Symmetry violation of $name($type1,$type2)');
|
||||
Expect.equals(result, r1);
|
||||
Expect.equals(r1, r2, 'symmetry violation');
|
||||
}
|
||||
|
||||
void check(type1, type2, predicate) {
|
||||
|
@ -732,11 +731,7 @@ void testRegressions(MockCompiler compiler) {
|
|||
}
|
||||
|
||||
void main() {
|
||||
asyncTest(() async {
|
||||
MockCompiler compiler = new MockCompiler.internal();
|
||||
await compiler.init("""
|
||||
class PatternImpl implements Pattern {}
|
||||
""");
|
||||
asyncTest(() => MockCompiler.create((MockCompiler compiler) {
|
||||
JavaScriptBackend backend = compiler.backend;
|
||||
BackendHelpers helpers = backend.helpers;
|
||||
World world = compiler.world;
|
||||
|
@ -749,9 +744,6 @@ void main() {
|
|||
compiler.globalDependencies);
|
||||
}
|
||||
});
|
||||
ClassElement patternImplClass = compiler.mainApp.find('PatternImpl');
|
||||
patternImplClass.ensureResolved(compiler.resolution);
|
||||
|
||||
backend.registerInstantiatedType(
|
||||
compiler.coreTypes.mapType(),
|
||||
compiler.enqueuer.resolution,
|
||||
|
@ -760,10 +752,6 @@ void main() {
|
|||
compiler.coreTypes.functionType,
|
||||
compiler.enqueuer.resolution,
|
||||
compiler.globalDependencies);
|
||||
backend.registerInstantiatedType(
|
||||
patternImplClass.rawType,
|
||||
compiler.enqueuer.resolution,
|
||||
compiler.globalDependencies);
|
||||
compiler.world.populate();
|
||||
|
||||
// Grab hold of a supertype for String so we can produce potential
|
||||
|
@ -817,15 +805,8 @@ void main() {
|
|||
dynamicType = new TypeMask.subclass(
|
||||
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);
|
||||
testIntersection(compiler);
|
||||
testRegressions(compiler);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -4,15 +4,12 @@
|
|||
|
||||
library type_mask2_test;
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:expect/expect.dart';
|
||||
import 'package:async_helper/async_helper.dart';
|
||||
import 'type_test_helper.dart';
|
||||
import 'package:compiler/src/elements/elements.dart'
|
||||
show Element, ClassElement;
|
||||
import 'package:compiler/src/types/types.dart';
|
||||
import 'package:compiler/src/world.dart' show
|
||||
ClassWorld;
|
||||
|
||||
isCheckedMode() {
|
||||
try {
|
||||
|
@ -25,67 +22,11 @@ isCheckedMode() {
|
|||
}
|
||||
|
||||
void main() {
|
||||
asyncTest(() async {
|
||||
await testUnionTypeMaskFlatten();
|
||||
await testStringSubtypes();
|
||||
});
|
||||
testUnionTypeMaskFlatten();
|
||||
}
|
||||
|
||||
checkMasks(ClassWorld classWorld,
|
||||
List<ClassElement> allClasses,
|
||||
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"""
|
||||
void testUnionTypeMaskFlatten() {
|
||||
asyncTest(() => TypeEnvironment.create(r"""
|
||||
class A {}
|
||||
class B {}
|
||||
class C extends A {}
|
||||
|
@ -101,158 +42,153 @@ Future testUnionTypeMaskFlatten() async {
|
|||
new E();
|
||||
}
|
||||
""",
|
||||
useMockCompiler: false);
|
||||
|
||||
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);
|
||||
useMockCompiler: false).then((env) {
|
||||
var classWorld = env.compiler.world;
|
||||
var backend = env.compiler.backend;
|
||||
|
||||
ClassElement Object_ = env.getElement("Object");
|
||||
ClassElement String_ = env.getElement("String");
|
||||
ClassElement JSString = backend.helpers.jsStringClass;
|
||||
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_, String_];
|
||||
List<ClassElement> allClasses = <ClassElement>[Object_, A, B, C, D, E];
|
||||
|
||||
Expect.isFalse(classWorld.isDirectlyInstantiated(Object_));
|
||||
Expect.isTrue(classWorld.isIndirectlyInstantiated(Object_));
|
||||
Expect.isTrue(classWorld.isInstantiated(Object_));
|
||||
check(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
|
||||
// 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_));
|
||||
Expect.isFalse(classWorld.isInstantiated(String_));
|
||||
}
|
||||
return union;
|
||||
}
|
||||
|
||||
Expect.isTrue(classWorld.isDirectlyInstantiated(JSString));
|
||||
Expect.isFalse(classWorld.isIndirectlyInstantiated(JSString));
|
||||
Expect.isTrue(classWorld.isInstantiated(JSString));
|
||||
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);
|
||||
|
||||
TypeMask subtypeString = new TypeMask.nonNullSubtype(String_, classWorld);
|
||||
TypeMask exactJSString = new TypeMask.nonNullExact(JSString, classWorld);
|
||||
TypeMask subtypeJSString =
|
||||
new TypeMask.nonNullSubtype(JSString, classWorld);
|
||||
TypeMask subclassJSString =
|
||||
new TypeMask.nonNullSubclass(JSString, classWorld);
|
||||
check([],
|
||||
result: empty,
|
||||
disjointMasks: [],
|
||||
containedClasses: []);
|
||||
|
||||
Expect.equals(exactJSString, subtypeString);
|
||||
Expect.equals(exactJSString, subtypeJSString);
|
||||
Expect.equals(exactJSString, subclassJSString);
|
||||
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]);
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -5,29 +5,22 @@
|
|||
import "package:async_helper/async_helper.dart";
|
||||
import "package:expect/expect.dart";
|
||||
import "package:compiler/src/types/types.dart";
|
||||
import "package:compiler/src/world.dart";
|
||||
import 'type_test_helper.dart';
|
||||
|
||||
import "compiler_helper.dart";
|
||||
|
||||
main() {
|
||||
|
||||
asyncTest(() async {
|
||||
TypeEnvironment env = await TypeEnvironment.create(r"""
|
||||
class A {}
|
||||
class B {}
|
||||
""",
|
||||
mainSource: r"""
|
||||
MockCompiler compiler = new MockCompiler.internal(analyzeOnly: true);
|
||||
asyncTest(() => compiler.run(null, """
|
||||
main() {
|
||||
new A();
|
||||
new B();
|
||||
print(2); print("Hello");
|
||||
}
|
||||
""",
|
||||
useMockCompiler: false);
|
||||
World world = env.compiler.world;
|
||||
world.populate();
|
||||
FlatTypeMask mask1 = new FlatTypeMask.exact(env.getElement('A'));
|
||||
FlatTypeMask mask2 = new FlatTypeMask.exact(env.getElement('B'));
|
||||
UnionTypeMask union1 = mask1.nonNullable().union(mask2, world);
|
||||
UnionTypeMask union2 = mask2.nonNullable().union(mask1, world);
|
||||
""").then((_) {
|
||||
FlatTypeMask mask1 =
|
||||
new FlatTypeMask.exact(compiler.coreClasses.intClass);
|
||||
FlatTypeMask mask2 =
|
||||
new FlatTypeMask.exact(compiler.coreClasses.stringClass);
|
||||
UnionTypeMask union1 = mask1.nonNullable().union(mask2, compiler.world);
|
||||
UnionTypeMask union2 = mask2.nonNullable().union(mask1, compiler.world);
|
||||
Expect.equals(union1, union2);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue