Index: pkg/compiler/lib/src/universe/world_builder.dart |
diff --git a/pkg/compiler/lib/src/universe/world_builder.dart b/pkg/compiler/lib/src/universe/world_builder.dart |
index fa4108aa282ab8ce8ca2fcb149cb9862be2891a1..caa50e60b4ad1869a91fb71d176f8dc31e24f2bb 100644 |
--- a/pkg/compiler/lib/src/universe/world_builder.dart |
+++ b/pkg/compiler/lib/src/universe/world_builder.dart |
@@ -14,9 +14,7 @@ import '../compiler.dart' show Compiler; |
import '../core_types.dart' show CoreClasses; |
import '../dart_types.dart'; |
import '../elements/elements.dart'; |
-import '../types/masks.dart' show CommonMasks; |
import '../universe/class_set.dart' show Instantiation; |
-import '../util/enumset.dart'; |
import '../util/util.dart'; |
import '../world.dart' show World, ClosedWorld, OpenWorld, WorldImpl; |
import 'selector.dart' show Selector; |
@@ -164,9 +162,10 @@ abstract class ResolutionWorldBuilder implements WorldBuilder { |
/// Set of all fields that are statically known to be written to. |
Iterable<Element> get fieldSetters; |
- /// Call [f] for all directly or abstractly instantiated classes. |
- void forEachInstantiatedClass( |
- f(ClassElement cls, EnumSet<Instantiation> instantiations)); |
+ /// Call [f] for all classes with instantiated types. This includes the |
+ /// directly and abstractly instantiated classes but also classes whose type |
+ /// arguments are used in live factory constructors. |
+ void forEachInstantiatedClass(f(ClassElement cls, InstantiationInfo info)); |
/// `true` of `Object.runtimeType` is supported. |
bool get hasRuntimeTypeSupport; |
@@ -182,22 +181,172 @@ abstract class ResolutionWorldBuilder implements WorldBuilder { |
OpenWorld get openWorld; |
} |
-class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder { |
- /// The set of all directly instantiated classes, that is, classes with a |
- /// generative constructor that has been called directly and not only through |
- /// a super-call. |
+/// The type and kind of an instantiation registered through |
+/// `ResolutionWorldBuilder.registerTypeInstantiation`. |
+class Instance { |
+ final InterfaceType type; |
+ final Instantiation kind; |
+ final bool isRedirection; |
+ |
+ Instance(this.type, this.kind, {this.isRedirection: false}); |
+ |
+ int get hashCode { |
+ return Hashing.objectHash( |
+ type, Hashing.objectHash(kind, Hashing.objectHash(isRedirection))); |
+ } |
+ |
+ bool operator ==(other) { |
+ if (identical(this, other)) return true; |
+ if (other is! Instance) return false; |
+ return type == other.type && |
+ kind == other.kind && |
+ isRedirection == other.isRedirection; |
+ } |
+ |
+ String toString() { |
+ StringBuffer sb = new StringBuffer(); |
+ sb.write(type); |
+ if (kind == Instantiation.DIRECTLY_INSTANTIATED) { |
+ sb.write(' directly'); |
+ } else if (kind == Instantiation.ABSTRACTLY_INSTANTIATED) { |
+ sb.write(' abstractly'); |
+ } else if (kind == Instantiation.UNINSTANTIATED) { |
+ sb.write(' none'); |
+ } |
+ if (isRedirection) { |
+ sb.write(' redirect'); |
+ } |
+ return sb.toString(); |
+ } |
+} |
+ |
+/// Information about instantiations of a class. |
+class InstantiationInfo { |
+ /// A map from constructor of the class to their instantiated types. |
/// |
- /// Invariant: Elements are declaration elements. |
- // TODO(johnniwinther): [_directlyInstantiatedClasses] and |
- // [_instantiatedTypes] sets should be merged. |
- final Map<ClassElement, EnumSet<Instantiation>> _directlyInstantiatedClasses = |
- <ClassElement, EnumSet<Instantiation>>{}; |
+ /// For instance |
+ /// |
+ /// import 'dart:html'; |
+ /// |
+ /// abstract class AbstractClass<S> { |
+ /// factory AbstractClass.a() = Class<S>.a; |
+ /// factory AbstractClass.b() => new Class<S>.b(); |
+ /// } |
+ /// class Class<T> implements AbstractClass<T> { |
+ /// Class.a(); |
+ /// Class.b(); |
+ /// factory Class.c() = Class.b<T>; |
+ /// } |
+ /// |
+ /// |
+ /// main() { |
+ /// new Class.a(); |
+ /// new Class<int>.a(); |
+ /// new Class<String>.b(); |
+ /// new Class<num>.c(); |
+ /// new AbstractClass<double>.a(); |
+ /// new AbstractClass<bool>.b(); |
+ /// new DivElement(); // native instantiation |
+ /// } |
+ /// |
+ /// will generate the mappings |
+ /// |
+ /// AbstractClass: { |
+ /// AbstractClass.a: { |
+ /// AbstractClass<double> none, // from `new AbstractClass<double>.a()` |
+ /// }, |
+ /// AbstractClass.b: { |
+ /// AbstractClass<bool> none, // from `new AbstractClass<bool>.b()` |
+ /// }, |
+ /// }, |
+ /// Class: { |
+ /// Class.a: { |
+ /// Class directly, // from `new Class.a()` |
+ /// Class<int> directly, // from `new Class<int>.a()` |
+ /// Class<S> directly redirect, // from `factory AbstractClass.a` |
+ /// }, |
+ /// Class.b: { |
+ /// Class<String> directly, // from `new Class<String>.b()` |
+ /// Class<T> directly redirect, // from `factory Class.c` |
+ /// Class<S> directly, // from `factory AbstractClass.b` |
+ /// }, |
+ /// Class.c: { |
+ /// Class<num> directly, // from `new Class<num>.c()` |
+ /// }, |
+ /// }, |
+ /// DivElement: { |
+ /// DivElement: { |
+ /// DivElement abstractly, // from `new DivElement()` |
+ /// }, |
+ /// } |
+ /// |
+ /// If the constructor is unknown, for instance for native or mirror usage, |
+ /// `null` is used as key. |
+ Map<ConstructorElement, Set<Instance>> instantiationMap; |
+ |
+ /// Register [type] as the instantiation [kind] using [constructor]. |
+ void addInstantiation( |
+ ConstructorElement constructor, InterfaceType type, Instantiation kind, |
+ {bool isRedirection: false}) { |
+ instantiationMap ??= <ConstructorElement, Set<Instance>>{}; |
+ instantiationMap |
+ .putIfAbsent(constructor, () => new Set<Instance>()) |
+ .add(new Instance(type, kind, isRedirection: isRedirection)); |
+ switch (kind) { |
+ case Instantiation.DIRECTLY_INSTANTIATED: |
+ isDirectlyInstantiated = true; |
+ break; |
+ case Instantiation.ABSTRACTLY_INSTANTIATED: |
+ isAbstractlyInstantiated = true; |
+ break; |
+ case Instantiation.UNINSTANTIATED: |
+ break; |
+ default: |
+ throw new StateError("Instantiation $kind is not allowed."); |
+ } |
+ } |
- /// The set of all directly instantiated types, that is, the types of the |
- /// directly instantiated classes. |
+ /// `true` if the class is either directly or abstractly instantiated. |
+ bool get hasInstantiation => |
+ isDirectlyInstantiated || isAbstractlyInstantiated; |
+ |
+ /// `true` if the class is directly instantiated. |
+ bool isDirectlyInstantiated = false; |
+ |
+ /// `true` if the class is abstractly instantiated. |
+ bool isAbstractlyInstantiated = false; |
+ |
+ String toString() { |
+ StringBuffer sb = new StringBuffer(); |
+ sb.write('InstantiationInfo['); |
+ if (instantiationMap != null) { |
+ bool needsComma = false; |
+ instantiationMap |
+ .forEach((ConstructorElement constructor, Set<Instance> set) { |
+ if (needsComma) { |
+ sb.write(', '); |
+ } |
+ if (constructor != null) { |
+ sb.write(constructor); |
+ } else { |
+ sb.write('<unknown>'); |
+ } |
+ sb.write(': '); |
+ sb.write(set); |
+ needsComma = true; |
+ }); |
+ } |
+ sb.write(']'); |
+ return sb.toString(); |
+ } |
+} |
+ |
+class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder { |
+ /// Instantiation information for all classes with instantiated types. |
/// |
- /// See [_directlyInstantiatedClasses]. |
- final Set<DartType> _instantiatedTypes = new Set<DartType>(); |
+ /// Invariant: Elements are declaration elements. |
+ final Map<ClassElement, InstantiationInfo> _instantiationInfo = |
+ <ClassElement, InstantiationInfo>{}; |
/// Classes implemented by directly instantiated classes. |
final Set<ClassElement> _implementedClasses = new Set<ClassElement>(); |
@@ -272,7 +421,13 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder { |
/// super-call. |
// TODO(johnniwinther): Improve semantic precision. |
Iterable<ClassElement> get directlyInstantiatedClasses { |
- return _directlyInstantiatedClasses.keys; |
+ Set<ClassElement> classes = new Set<ClassElement>(); |
+ _instantiationInfo.forEach((ClassElement cls, InstantiationInfo info) { |
+ if (info.hasInstantiation) { |
+ classes.add(cls); |
+ } |
+ }); |
+ return classes; |
} |
/// All directly instantiated types, that is, the types of the directly |
@@ -280,7 +435,19 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder { |
/// |
/// See [directlyInstantiatedClasses]. |
// TODO(johnniwinther): Improve semantic precision. |
- Iterable<DartType> get instantiatedTypes => _instantiatedTypes; |
+ Iterable<DartType> get instantiatedTypes { |
+ Set<InterfaceType> types = new Set<InterfaceType>(); |
+ _instantiationInfo.forEach((_, InstantiationInfo info) { |
+ if (info.instantiationMap != null) { |
+ for (Set<Instance> instances in info.instantiationMap.values) { |
+ for (Instance instance in instances) { |
+ types.add(instance.type); |
+ } |
+ } |
+ } |
+ }); |
+ return types; |
+ } |
/// Returns `true` if [cls] is considered to be implemented by an |
/// instantiated class, either directly, through subclasses or through |
@@ -298,11 +465,15 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder { |
// subclass and through subtype instantiated types/classes. |
// TODO(johnniwinther): Support unknown type arguments for generic types. |
void registerTypeInstantiation(InterfaceType type, |
- {bool byMirrors: false, |
+ {ConstructorElement constructor, |
+ bool byMirrors: false, |
bool isNative: false, |
+ bool isRedirection: false, |
void onImplemented(ClassElement cls)}) { |
- _instantiatedTypes.add(type); |
ClassElement cls = type.element; |
+ InstantiationInfo info = |
+ _instantiationInfo.putIfAbsent(cls, () => new InstantiationInfo()); |
+ Instantiation kind = Instantiation.UNINSTANTIATED; |
if (!cls.isAbstract |
// We can't use the closed-world assumption with native abstract |
// classes; a native abstract class may have non-abstract subclasses |
@@ -315,17 +486,17 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder { |
// TODO(herhut): Track classes required by mirrors seperately. |
|| |
byMirrors) { |
- EnumSet<Instantiation> instantiations = _directlyInstantiatedClasses |
- .putIfAbsent(cls, () => new EnumSet<Instantiation>()); |
if (isNative || byMirrors) { |
- instantiations.add(Instantiation.ABSTRACTLY_INSTANTIATED); |
+ kind = Instantiation.ABSTRACTLY_INSTANTIATED; |
} else { |
- instantiations.add(Instantiation.DIRECTLY_INSTANTIATED); |
+ kind = Instantiation.DIRECTLY_INSTANTIATED; |
} |
} |
+ info.addInstantiation(constructor, type, kind, |
+ isRedirection: isRedirection); |
- // TODO(johnniwinther): Replace this by separate more specific mappings that |
- // include the type arguments. |
+ // TODO(johnniwinther): Use [_instantiationInfo] to compute this information |
+ // instead. |
if (_implementedClasses.add(cls)) { |
onImplemented(cls); |
cls.allSupertypes.forEach((InterfaceType supertype) { |
@@ -337,9 +508,8 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder { |
} |
@override |
- void forEachInstantiatedClass( |
- f(ClassElement cls, EnumSet<Instantiation> instantiations)) { |
- _directlyInstantiatedClasses.forEach(f); |
+ void forEachInstantiatedClass(f(ClassElement cls, InstantiationInfo info)) { |
+ _instantiationInfo.forEach(f); |
} |
bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors, |
@@ -422,6 +592,7 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder { |
case StaticUseKind.FIELD_GET: |
case StaticUseKind.CONSTRUCTOR_INVOKE: |
case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: |
+ case StaticUseKind.REDIRECTION: |
break; |
case StaticUseKind.CLOSURE: |
allClosures.add(element); |
@@ -438,12 +609,7 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder { |
slowDirectlyNestedClosures(element).forEach(compiler.forgetElement); |
closurizedMembers.remove(element); |
fieldSetters.remove(element); |
- _directlyInstantiatedClasses.remove(element); |
- if (element is ClassElement) { |
- assert(invariant(element, element.thisType.isRaw, |
- message: 'Generic classes not supported (${element.thisType}).')); |
- _instantiatedTypes..remove(element.rawType)..remove(element.thisType); |
- } |
+ _instantiationInfo.remove(element); |
} |
// TODO(ahe): Replace this method with something that is O(1), for example, |
@@ -701,6 +867,7 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder { |
case StaticUseKind.FIELD_GET: |
case StaticUseKind.CONSTRUCTOR_INVOKE: |
case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: |
+ case StaticUseKind.REDIRECTION: |
case StaticUseKind.DIRECT_INVOKE: |
break; |
} |