| Index: pkg/compiler/lib/src/resolution/class_hierarchy.dart
|
| diff --git a/pkg/compiler/lib/src/resolution/class_hierarchy.dart b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
|
| index 3b867eabc10860eb90ec417a956bb0004213d16e..0d9b50cfa0dac064c6ac80c4bb704f652d22ce50 100644
|
| --- a/pkg/compiler/lib/src/resolution/class_hierarchy.dart
|
| +++ b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
|
| @@ -13,6 +13,7 @@ import '../elements/modelx.dart'
|
| show
|
| BaseClassElementX,
|
| ErroneousElementX,
|
| + LibraryElementX,
|
| MixinApplicationElementX,
|
| SynthesizedConstructorElementX,
|
| TypeVariableElementX,
|
| @@ -30,6 +31,10 @@ import 'registry.dart' show ResolutionRegistry;
|
| import 'resolution_common.dart' show CommonResolverVisitor, MappingVisitor;
|
| import 'scope.dart' show Scope, TypeDeclarationScope;
|
|
|
| +/// If `true` compatible mixin applications are shared within a library. This
|
| +/// matches the mixins generated by fasta.
|
| +bool useOptimizedMixins = false;
|
| +
|
| class TypeDefinitionVisitor extends MappingVisitor<ResolutionDartType> {
|
| Scope scope;
|
| final TypeDeclarationElement enclosingElement;
|
| @@ -145,15 +150,11 @@ class ClassResolverVisitor extends TypeDefinitionVisitor {
|
| if (element.supertype == null && node.superclass != null) {
|
| MixinApplication superMixin = node.superclass.asMixinApplication();
|
| if (superMixin != null) {
|
| - ResolutionDartType supertype =
|
| - resolveSupertype(element, superMixin.superclass);
|
| - Link<Node> link = superMixin.mixins.nodes;
|
| - while (!link.isEmpty) {
|
| - supertype =
|
| - applyMixin(supertype, checkMixinType(link.head), link.head);
|
| - link = link.tail;
|
| + if (useOptimizedMixins) {
|
| + element.supertype = createMixinsOptimized(element, superMixin);
|
| + } else {
|
| + element.supertype = createMixins(element, superMixin);
|
| }
|
| - element.supertype = supertype;
|
| } else {
|
| element.supertype = resolveSupertype(element, node.superclass);
|
| }
|
| @@ -285,14 +286,225 @@ class ClassResolverVisitor extends TypeDefinitionVisitor {
|
|
|
| // Generate anonymous mixin application elements for the
|
| // intermediate mixin applications (excluding the last).
|
| + if (useOptimizedMixins) {
|
| + createMixinsOptimized(element, node, isNamed: true);
|
| + } else {
|
| + createMixins(element, node, isNamed: true);
|
| + }
|
| + return element.computeType(resolution);
|
| + }
|
| +
|
| + /// Create the mixin applications for [superMixin].
|
| + ///
|
| + /// This algorithm is ported from
|
| + /// `package:front_end/src/fasta/kernel/kernel_library_builder.dart` and
|
| + /// added create allow for equivalence testing between the AST and kernel
|
| + /// based compilations in face of shared mixins. It will be removed when we
|
| + /// no longer need equivalence testing.
|
| + ResolutionDartType createMixinsOptimized(
|
| + BaseClassElementX element, MixinApplication superMixin,
|
| + {bool isNamed: false}) {
|
| + LibraryElementX library = element.library;
|
| + Map<String, MixinApplicationElementX> mixinApplicationClasses =
|
| + library.mixinApplicationCache;
|
| +
|
| + String name = element.isNamedMixinApplication ? element.name : null;
|
| + ResolutionDartType supertype =
|
| + resolveSupertype(element, superMixin.superclass);
|
| + Link<Node> link = superMixin.mixins.nodes;
|
| + List<ResolutionDartType> mixins = <ResolutionDartType>[];
|
| + List<Node> mixinNodes = <Node>[];
|
| + while (!link.isEmpty) {
|
| + mixins.add(checkMixinType(link.head));
|
| + mixinNodes.add(link.head);
|
| + link = link.tail;
|
| + }
|
| +
|
| + List<List<String>> signatureParts = <List<String>>[];
|
| + Map<String, ResolutionDartType> freeTypes = <String, ResolutionDartType>{};
|
| +
|
| + {
|
| + Map<String, String> unresolved = <String, String>{};
|
| + int unresolvedCount = 0;
|
| +
|
| + /// Compute a signature of the type arguments used by the supertype and
|
| + /// mixins. These types are free variables. At this point we can't
|
| + /// trust that the number of type arguments match the type parameters,
|
| + /// so we also need to be able to detect missing type arguments. To do
|
| + /// so, we separate each list of type arguments by `^` and type
|
| + /// arguments by `&`. For example, the mixin `C<S> with M<T, U>` would
|
| + /// look like this:
|
| + ///
|
| + /// ^#U0^#U1&#U2
|
| + ///
|
| + /// Where `#U0`, `#U1`, and `#U2` are the free variables arising from
|
| + /// `S`, `T`, and `U` respectively.
|
| + ///
|
| + /// As we can resolve any type parameters used at this point, those are
|
| + /// named `#T0` and so forth. This reduces the number of free variables
|
| + /// which is crucial for memory usage and the Dart VM's bootstrap
|
| + /// sequence.
|
| + ///
|
| + /// For example, consider this use of mixin applications:
|
| + ///
|
| + /// class _InternalLinkedHashMap<K, V> extends _HashVMBase
|
| + /// with
|
| + /// MapMixin<K, V>,
|
| + /// _LinkedHashMapMixin<K, V>,
|
| + /// _HashBase,
|
| + /// _OperatorEqualsAndHashCode {}
|
| + ///
|
| + /// In this case, only two variables are free, and we produce this
|
| + /// signature: `^^#T0&#T1^#T0&#T1^^`. Assume another class uses the
|
| + /// sames mixins but with missing type arguments for `MapMixin`, its
|
| + /// signature would be: `^^^#T0&#T1^^`.
|
| + ///
|
| + /// Note that we do not need to compute a signature for a named mixin
|
| + /// application with only one mixin as we don't have to invent a name
|
| + /// for any classes in this situation.
|
| + void analyzeArguments(ResolutionDartType type, {bool isLast}) {
|
| + if (isNamed && isLast) {
|
| + // The last mixin of a named mixin application doesn't contribute
|
| + // to free variables.
|
| + return;
|
| + }
|
| + if (type is GenericType) {
|
| + List<String> part = <String>[];
|
| + for (int i = 0; i < type.typeArguments.length; i++) {
|
| + var argument = type.typeArguments[i];
|
| + String name;
|
| + if (argument is ResolutionTypeVariableType) {
|
| + int index = element.typeVariables.indexOf(argument) ?? -1;
|
| + if (index != -1) {
|
| + name = "#T${index}";
|
| + }
|
| + } else if (argument is GenericType && argument.isRaw) {
|
| + name = unresolved[argument.name] ??= "#U${unresolvedCount++}";
|
| + }
|
| + name ??= "#U${unresolvedCount++}";
|
| + freeTypes[name] = argument;
|
| + part.add(name);
|
| + }
|
| + signatureParts.add(part);
|
| + }
|
| + }
|
| +
|
| + analyzeArguments(supertype, isLast: false);
|
| + for (int i = 0; i < mixins.length; i++) {
|
| + analyzeArguments(mixins[i], isLast: i == mixins.length - 1);
|
| + }
|
| + }
|
| +
|
| + List<List<String>> currentSignatureParts = <List<String>>[];
|
| + String computeSignature(int index) {
|
| + if (freeTypes.isEmpty) return "";
|
| + currentSignatureParts.add(signatureParts[index]);
|
| + if (currentSignatureParts.any((l) => l.isNotEmpty)) {
|
| + return "^${currentSignatureParts.map((l) => l.join('&')).join('^')}";
|
| + } else {
|
| + return "";
|
| + }
|
| + }
|
| +
|
| + Map<String, ResolutionTypeVariableType> computeTypeVariables(
|
| + ClassElement cls, Node node) {
|
| + Map<String, ResolutionTypeVariableType> variables =
|
| + <String, ResolutionTypeVariableType>{};
|
| + int index = 0;
|
| + for (List<String> strings in currentSignatureParts) {
|
| + for (String name in strings) {
|
| + variables[name] ??= new ResolutionTypeVariableType(
|
| + new TypeVariableElementX(name, cls, index++, node));
|
| + }
|
| + }
|
| + return variables;
|
| + }
|
| +
|
| + computeSignature(0); // This combines the supertype with the first mixin.
|
| +
|
| + for (int i = 0; i < mixins.length; i++) {
|
| + int signatureIndex = i + 1;
|
| + Set<String> supertypeArguments = new Set<String>();
|
| + for (List<String> part in currentSignatureParts) {
|
| + supertypeArguments.addAll(part);
|
| + }
|
| + Node node = mixinNodes[i];
|
| + ResolutionDartType mixin = mixins[i];
|
| +
|
| + bool lastAndNamed = i == mixins.length - 1 && isNamed;
|
| +
|
| + ResolutionInterfaceType createMixinApplication() {
|
| + Map<String, ResolutionDartType> variables;
|
| + MixinApplicationElementX mixinElement;
|
| + ResolutionInterfaceType mixinType;
|
| + if (lastAndNamed) {
|
| + mixinElement = element;
|
| + variables = freeTypes;
|
| + } else {
|
| + String signature = computeSignature(signatureIndex);
|
| + name = supertype.name;
|
| + int index = name.indexOf("^");
|
| + if (index != -1) {
|
| + name = name.substring(0, index);
|
| + }
|
| + name = "$name&${mixin.name}$signature";
|
| + mixinElement = mixinApplicationClasses[name];
|
| + if (mixinElement != null) return mixinElement.thisType;
|
| +
|
| + mixinElement = new UnnamedMixinApplicationElementX(
|
| + name, element, resolution.idGenerator.getNextFreeId(), node);
|
| + variables = computeTypeVariables(mixinElement, node);
|
| + mixinElement.setThisAndRawTypes(variables.values.toList());
|
| + mixinApplicationClasses[name] = mixinElement;
|
| + }
|
| +
|
| + if (supertypeArguments.isNotEmpty) {
|
| + List<ResolutionDartType> supertypeTypeArguments =
|
| + <ResolutionDartType>[];
|
| + for (String part in supertypeArguments) {
|
| + supertypeTypeArguments.add(variables[part]);
|
| + }
|
| + supertype = new ResolutionInterfaceType(
|
| + supertype.element, supertypeTypeArguments);
|
| + }
|
| +
|
| + if (lastAndNamed) {
|
| + mixinType = mixin;
|
| + } else {
|
| + List<ResolutionDartType> mixinTypeArguments = <ResolutionDartType>[];
|
| + for (String part in signatureParts[signatureIndex]) {
|
| + mixinTypeArguments.add(variables[part]);
|
| + }
|
| + mixinType =
|
| + new ResolutionInterfaceType(mixin.element, mixinTypeArguments);
|
| + }
|
| +
|
| + doApplyMixinTo(mixinElement, supertype, mixinType);
|
| + mixinElement.resolutionState = STATE_DONE;
|
| + mixinElement.supertypeLoadState = STATE_DONE;
|
| + return mixinElement.thisType;
|
| + }
|
| +
|
| + supertype = createMixinApplication();
|
| + }
|
| +
|
| + return new ResolutionInterfaceType(
|
| + supertype.element, freeTypes.values.toList());
|
| + }
|
| +
|
| + ResolutionDartType createMixins(ClassElement element, MixinApplication node,
|
| + {bool isNamed: false}) {
|
| ResolutionDartType supertype = resolveSupertype(element, node.superclass);
|
| Link<Node> link = node.mixins.nodes;
|
| - while (!link.tail.isEmpty) {
|
| + while (!link.isEmpty) {
|
| + if (isNamed && link.tail.isEmpty) {
|
| + doApplyMixinTo(element, supertype, checkMixinType(link.head));
|
| + return supertype;
|
| + }
|
| supertype = applyMixin(supertype, checkMixinType(link.head), link.head);
|
| link = link.tail;
|
| }
|
| - doApplyMixinTo(element, supertype, checkMixinType(link.head));
|
| - return element.computeType(resolution);
|
| + return supertype;
|
| }
|
|
|
| ResolutionDartType applyMixin(
|
|
|