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:
Johnni Winther 2015-11-05 11:14:47 +01:00
parent d3c68df853
commit c1b102a94d
17 changed files with 292 additions and 587 deletions

View file

@ -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,

View file

@ -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) {

View file

@ -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;
}
});
}

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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');

View file

@ -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);

View file

@ -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,

View file

@ -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.

View file

@ -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_ , []));

View file

@ -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;

View file

@ -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);

View file

@ -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);
});
}));
}

View file

@ -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]);
}));
}

View file

@ -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);
});
}));
}