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