OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dart2js.resolution.class_hierarchy; | 5 library dart2js.resolution.class_hierarchy; |
6 | 6 |
7 import '../common.dart'; | 7 import '../common.dart'; |
8 import '../common/resolution.dart' show Resolution; | 8 import '../common/resolution.dart' show Resolution; |
9 import '../common_elements.dart' show CommonElements; | 9 import '../common_elements.dart' show CommonElements; |
10 import '../elements/resolution_types.dart'; | 10 import '../elements/resolution_types.dart'; |
11 import '../elements/elements.dart'; | 11 import '../elements/elements.dart'; |
12 import '../elements/modelx.dart' | 12 import '../elements/modelx.dart' |
13 show | 13 show |
14 BaseClassElementX, | 14 BaseClassElementX, |
15 ErroneousElementX, | 15 ErroneousElementX, |
16 LibraryElementX, | |
16 MixinApplicationElementX, | 17 MixinApplicationElementX, |
17 SynthesizedConstructorElementX, | 18 SynthesizedConstructorElementX, |
18 TypeVariableElementX, | 19 TypeVariableElementX, |
19 UnnamedMixinApplicationElementX; | 20 UnnamedMixinApplicationElementX; |
20 import '../elements/names.dart'; | 21 import '../elements/names.dart'; |
21 import '../ordered_typeset.dart' | 22 import '../ordered_typeset.dart' |
22 show OrderedTypeSet, ResolutionOrderedTypeSetBuilder; | 23 show OrderedTypeSet, ResolutionOrderedTypeSetBuilder; |
23 import '../tree/tree.dart'; | 24 import '../tree/tree.dart'; |
24 import '../universe/call_structure.dart' show CallStructure; | 25 import '../universe/call_structure.dart' show CallStructure; |
25 import '../universe/feature.dart' show Feature; | 26 import '../universe/feature.dart' show Feature; |
26 import '../util/util.dart' show Link, Setlet; | 27 import '../util/util.dart' show Link, Setlet; |
27 import 'enum_creator.dart'; | 28 import 'enum_creator.dart'; |
28 import 'members.dart' show lookupInScope; | 29 import 'members.dart' show lookupInScope; |
29 import 'registry.dart' show ResolutionRegistry; | 30 import 'registry.dart' show ResolutionRegistry; |
30 import 'resolution_common.dart' show CommonResolverVisitor, MappingVisitor; | 31 import 'resolution_common.dart' show CommonResolverVisitor, MappingVisitor; |
31 import 'scope.dart' show Scope, TypeDeclarationScope; | 32 import 'scope.dart' show Scope, TypeDeclarationScope; |
32 | 33 |
34 /// If `true` compatible mixin applications are shared within a library. This | |
35 /// matches the mixins generated by fasta. | |
36 bool useOptimizedMixins = false; | |
37 | |
33 class TypeDefinitionVisitor extends MappingVisitor<ResolutionDartType> { | 38 class TypeDefinitionVisitor extends MappingVisitor<ResolutionDartType> { |
34 Scope scope; | 39 Scope scope; |
35 final TypeDeclarationElement enclosingElement; | 40 final TypeDeclarationElement enclosingElement; |
36 TypeDeclarationElement get element => enclosingElement; | 41 TypeDeclarationElement get element => enclosingElement; |
37 | 42 |
38 TypeDefinitionVisitor(Resolution resolution, TypeDeclarationElement element, | 43 TypeDefinitionVisitor(Resolution resolution, TypeDeclarationElement element, |
39 ResolutionRegistry registry) | 44 ResolutionRegistry registry) |
40 : this.enclosingElement = element, | 45 : this.enclosingElement = element, |
41 scope = Scope.buildEnclosingScope(element), | 46 scope = Scope.buildEnclosingScope(element), |
42 super(resolution, registry); | 47 super(resolution, registry); |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
138 // TODO(ahe): It is not safe to call resolveTypeVariableBounds yet. | 143 // TODO(ahe): It is not safe to call resolveTypeVariableBounds yet. |
139 // As a side-effect, this may get us back here trying to | 144 // As a side-effect, this may get us back here trying to |
140 // resolve this class again. | 145 // resolve this class again. |
141 resolveTypeVariableBounds(node.typeParameters); | 146 resolveTypeVariableBounds(node.typeParameters); |
142 | 147 |
143 // Setup the supertype for the element (if there is a cycle in the | 148 // Setup the supertype for the element (if there is a cycle in the |
144 // class hierarchy, it has already been set to Object). | 149 // class hierarchy, it has already been set to Object). |
145 if (element.supertype == null && node.superclass != null) { | 150 if (element.supertype == null && node.superclass != null) { |
146 MixinApplication superMixin = node.superclass.asMixinApplication(); | 151 MixinApplication superMixin = node.superclass.asMixinApplication(); |
147 if (superMixin != null) { | 152 if (superMixin != null) { |
148 ResolutionDartType supertype = | 153 if (useOptimizedMixins) { |
149 resolveSupertype(element, superMixin.superclass); | 154 element.supertype = createMixinsOptimized(element, superMixin); |
150 Link<Node> link = superMixin.mixins.nodes; | 155 } else { |
151 while (!link.isEmpty) { | 156 element.supertype = createMixins(element, superMixin); |
152 supertype = | |
153 applyMixin(supertype, checkMixinType(link.head), link.head); | |
154 link = link.tail; | |
155 } | 157 } |
156 element.supertype = supertype; | |
157 } else { | 158 } else { |
158 element.supertype = resolveSupertype(element, node.superclass); | 159 element.supertype = resolveSupertype(element, node.superclass); |
159 } | 160 } |
160 } | 161 } |
161 // If the super type isn't specified, we provide a default. The language | 162 // If the super type isn't specified, we provide a default. The language |
162 // specifies [Object] but the backend can pick a specific 'implementation' | 163 // specifies [Object] but the backend can pick a specific 'implementation' |
163 // of Object - the JavaScript backend chooses between Object and | 164 // of Object - the JavaScript backend chooses between Object and |
164 // Interceptor. | 165 // Interceptor. |
165 if (element.supertype == null) { | 166 if (element.supertype == null) { |
166 ClassElement superElement = registry.defaultSuperclass(element); | 167 ClassElement superElement = registry.defaultSuperclass(element); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
278 throw reporter.internalError( | 279 throw reporter.internalError( |
279 element, 'cyclic resolution of class $element'); | 280 element, 'cyclic resolution of class $element'); |
280 } | 281 } |
281 | 282 |
282 element.computeType(resolution); | 283 element.computeType(resolution); |
283 scope = new TypeDeclarationScope(scope, element); | 284 scope = new TypeDeclarationScope(scope, element); |
284 resolveTypeVariableBounds(node.typeParameters); | 285 resolveTypeVariableBounds(node.typeParameters); |
285 | 286 |
286 // Generate anonymous mixin application elements for the | 287 // Generate anonymous mixin application elements for the |
287 // intermediate mixin applications (excluding the last). | 288 // intermediate mixin applications (excluding the last). |
289 if (useOptimizedMixins) { | |
290 createMixinsOptimized(element, node, isNamed: true); | |
291 } else { | |
292 createMixins(element, node, isNamed: true); | |
293 } | |
294 return element.computeType(resolution); | |
295 } | |
296 | |
297 ResolutionDartType createMixinsOptimized( | |
298 BaseClassElementX element, MixinApplication superMixin, | |
299 {bool isNamed: false}) { | |
300 LibraryElementX library = element.library; | |
301 Map<String, MixinApplicationElementX> mixinApplicationClasses = | |
302 library.mixinApplicationCache; | |
303 | |
304 String name = element.isNamedMixinApplication ? element.name : null; | |
305 ResolutionDartType supertype = | |
306 resolveSupertype(element, superMixin.superclass); | |
307 Link<Node> link = superMixin.mixins.nodes; | |
308 List<ResolutionDartType> mixins = <ResolutionDartType>[]; | |
309 List<Node> mixinNodes = <Node>[]; | |
310 while (!link.isEmpty) { | |
311 mixins.add(checkMixinType(link.head)); | |
312 mixinNodes.add(link.head); | |
313 link = link.tail; | |
314 } | |
315 | |
316 List<List<String>> signatureParts = <List<String>>[]; | |
317 Map<String, ResolutionDartType> freeTypes = <String, ResolutionDartType>{}; | |
318 | |
319 { | |
320 Map<String, String> unresolved = <String, String>{}; | |
321 int unresolvedCount = 0; | |
322 | |
323 /// Compute a signature of the type arguments used by the supertype and | |
324 /// mixins. These types are free variables. At this point we can't | |
325 /// trust that the number of type arguments match the type parameters, | |
326 /// so we also need to be able to detect missing type arguments. To do | |
327 /// so, we separate each list of type arguments by `^` and type | |
328 /// arguments by `&`. For example, the mixin `C<S> with M<T, U>` would | |
329 /// look like this: | |
330 /// | |
331 /// ^#U0^#U1&#U2 | |
332 /// | |
333 /// Where `#U0`, `#U1`, and `#U2` are the free variables arising from | |
334 /// `S`, `T`, and `U` respectively. | |
335 /// | |
336 /// As we can resolve any type parameters used at this point, those are | |
337 /// named `#T0` and so forth. This reduces the number of free variables | |
338 /// which is crucial for memory usage and the Dart VM's bootstrap | |
Siggi Cherem (dart-lang)
2017/07/19 04:38:34
VM bootstrap? I just realized this code was ported
Johnni Winther
2017/07/19 11:33:58
Done.
| |
339 /// sequence. | |
340 /// | |
341 /// For example, consider this use of mixin applications: | |
342 /// | |
343 /// class _InternalLinkedHashMap<K, V> extends _HashVMBase | |
344 /// with | |
345 /// MapMixin<K, V>, | |
346 /// _LinkedHashMapMixin<K, V>, | |
347 /// _HashBase, | |
348 /// _OperatorEqualsAndHashCode {} | |
349 /// | |
350 /// In this case, only two variables are free, and we produce this | |
351 /// signature: `^^#T0&#T1^#T0&#T1^^`. Assume another class uses the | |
352 /// sames mixins but with missing type arguments for `MapMixin`, its | |
353 /// signature would be: `^^^#T0&#T1^^`. | |
354 /// | |
355 /// Note that we do not need to compute a signature for a named mixin | |
356 /// application with only one mixin as we don't have to invent a name | |
357 /// for any classes in this situation. | |
358 void analyzeArguments(ResolutionDartType type, {bool isLast}) { | |
359 if (isNamed && isLast) { | |
360 // The last mixin of a named mixin application doesn't contribute | |
361 // to free variables. | |
362 return; | |
363 } | |
364 if (type is GenericType) { | |
365 List<String> part = <String>[]; | |
366 for (int i = 0; i < type.typeArguments.length; i++) { | |
367 var argument = type.typeArguments[i]; | |
368 String name; | |
369 if (argument is ResolutionTypeVariableType) { | |
370 int index = element.typeVariables.indexOf(argument) ?? -1; | |
371 if (index != -1) { | |
372 name = "#T${index}"; | |
373 } | |
374 } else if (argument is GenericType && argument.isRaw) { | |
375 name = unresolved[argument.name] ??= "#U${unresolvedCount++}"; | |
376 } | |
377 name ??= "#U${unresolvedCount++}"; | |
378 freeTypes[name] = argument; | |
379 part.add(name); | |
380 } | |
381 signatureParts.add(part); | |
382 } | |
383 } | |
384 | |
385 analyzeArguments(supertype, isLast: false); | |
386 for (int i = 0; i < mixins.length; i++) { | |
387 analyzeArguments(mixins[i], isLast: i == mixins.length - 1); | |
388 } | |
389 } | |
390 | |
391 List<List<String>> currentSignatureParts = <List<String>>[]; | |
392 String computeSignature(int index) { | |
393 if (freeTypes.isEmpty) return ""; | |
394 currentSignatureParts.add(signatureParts[index]); | |
395 if (currentSignatureParts.any((l) => l.isNotEmpty)) { | |
396 return "^${currentSignatureParts.map((l) => l.join('&')).join('^')}"; | |
397 } else { | |
398 return ""; | |
399 } | |
400 } | |
401 | |
402 Map<String, ResolutionTypeVariableType> computeTypeVariables( | |
403 ClassElement cls, Node node) { | |
404 Map<String, ResolutionTypeVariableType> variables = | |
405 <String, ResolutionTypeVariableType>{}; | |
406 int index = 0; | |
407 for (List<String> strings in currentSignatureParts) { | |
408 for (String name in strings) { | |
409 variables[name] ??= new ResolutionTypeVariableType( | |
410 new TypeVariableElementX(name, cls, index++, node)); | |
411 } | |
412 } | |
413 return variables; | |
414 } | |
415 | |
416 computeSignature(0); // This combines the supertype with the first mixin. | |
417 | |
418 for (int i = 0; i < mixins.length; i++) { | |
419 int signatureIndex = i + 1; | |
420 Set<String> supertypeArguments = new Set<String>(); | |
421 for (List<String> part in currentSignatureParts) { | |
422 supertypeArguments.addAll(part); | |
423 } | |
424 Node node = mixinNodes[i]; | |
425 ResolutionDartType mixin = mixins[i]; | |
426 | |
427 bool lastAndNamed = i == mixins.length - 1 && isNamed; | |
428 | |
429 ResolutionInterfaceType createMixinApplication() { | |
430 Map<String, ResolutionDartType> variables; | |
431 MixinApplicationElementX mixinElement; | |
432 ResolutionInterfaceType mixinType; | |
433 if (lastAndNamed) { | |
434 mixinElement = element; | |
435 variables = freeTypes; | |
436 } else { | |
437 String signature = computeSignature(signatureIndex); | |
438 name = supertype.name; | |
439 int index = name.indexOf("^"); | |
440 if (index != -1) { | |
441 name = name.substring(0, index); | |
442 } | |
443 name = "$name&${mixin.name}$signature"; | |
444 mixinElement = mixinApplicationClasses[name]; | |
445 if (mixinElement != null) return mixinElement.thisType; | |
446 | |
447 mixinElement = new UnnamedMixinApplicationElementX( | |
448 name, element, resolution.idGenerator.getNextFreeId(), node); | |
449 variables = computeTypeVariables(mixinElement, node); | |
450 mixinElement.setThisAndRawTypes(variables.values.toList()); | |
451 mixinApplicationClasses[name] = mixinElement; | |
452 } | |
453 | |
454 if (supertypeArguments.isNotEmpty) { | |
455 List<ResolutionDartType> supertypeTypeArguments = | |
456 <ResolutionDartType>[]; | |
457 for (String part in supertypeArguments) { | |
458 supertypeTypeArguments.add(variables[part]); | |
459 } | |
460 supertype = new ResolutionInterfaceType( | |
461 supertype.element, supertypeTypeArguments); | |
462 } | |
463 | |
464 if (lastAndNamed) { | |
465 mixinType = mixin; | |
466 } else { | |
467 List<ResolutionDartType> mixinTypeArguments = <ResolutionDartType>[]; | |
468 for (String part in signatureParts[signatureIndex]) { | |
469 mixinTypeArguments.add(variables[part]); | |
470 } | |
471 mixinType = | |
472 new ResolutionInterfaceType(mixin.element, mixinTypeArguments); | |
473 } | |
474 | |
475 doApplyMixinTo(mixinElement, supertype, mixinType); | |
476 mixinElement.resolutionState = STATE_DONE; | |
477 mixinElement.supertypeLoadState = STATE_DONE; | |
478 return mixinElement.thisType; | |
479 } | |
480 | |
481 supertype = createMixinApplication(); | |
482 } | |
483 | |
484 return new ResolutionInterfaceType( | |
485 supertype.element, freeTypes.values.toList()); | |
486 } | |
487 | |
488 ResolutionDartType createMixins(ClassElement element, MixinApplication node, | |
489 {bool isNamed: false}) { | |
288 ResolutionDartType supertype = resolveSupertype(element, node.superclass); | 490 ResolutionDartType supertype = resolveSupertype(element, node.superclass); |
289 Link<Node> link = node.mixins.nodes; | 491 Link<Node> link = node.mixins.nodes; |
290 while (!link.tail.isEmpty) { | 492 while (!link.isEmpty) { |
493 if (isNamed && link.tail.isEmpty) { | |
494 doApplyMixinTo(element, supertype, checkMixinType(link.head)); | |
495 return supertype; | |
496 } | |
291 supertype = applyMixin(supertype, checkMixinType(link.head), link.head); | 497 supertype = applyMixin(supertype, checkMixinType(link.head), link.head); |
292 link = link.tail; | 498 link = link.tail; |
293 } | 499 } |
294 doApplyMixinTo(element, supertype, checkMixinType(link.head)); | 500 return supertype; |
295 return element.computeType(resolution); | |
296 } | 501 } |
297 | 502 |
298 ResolutionDartType applyMixin( | 503 ResolutionDartType applyMixin( |
299 ResolutionDartType supertype, ResolutionDartType mixinType, Node node) { | 504 ResolutionDartType supertype, ResolutionDartType mixinType, Node node) { |
300 String superName = supertype.name; | 505 String superName = supertype.name; |
301 String mixinName = mixinType.name; | 506 String mixinName = mixinType.name; |
302 MixinApplicationElementX mixinApplication = | 507 MixinApplicationElementX mixinApplication = |
303 new UnnamedMixinApplicationElementX("${superName}+${mixinName}", | 508 new UnnamedMixinApplicationElementX("${superName}+${mixinName}", |
304 element, resolution.idGenerator.getNextFreeId(), node); | 509 element, resolution.idGenerator.getNextFreeId(), node); |
305 // Create synthetic type variables for the mixin application. | 510 // Create synthetic type variables for the mixin application. |
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
646 Identifier selector = node.selector.asIdentifier(); | 851 Identifier selector = node.selector.asIdentifier(); |
647 var e = prefixElement.lookupLocalMember(selector.source); | 852 var e = prefixElement.lookupLocalMember(selector.source); |
648 if (e == null || !e.impliesType) { | 853 if (e == null || !e.impliesType) { |
649 reporter.reportErrorMessage(node.selector, | 854 reporter.reportErrorMessage(node.selector, |
650 MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.selector}); | 855 MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.selector}); |
651 return; | 856 return; |
652 } | 857 } |
653 loadSupertype(e, node); | 858 loadSupertype(e, node); |
654 } | 859 } |
655 } | 860 } |
OLD | NEW |