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 /// Create the mixin applications for [superMixin]. |
| 298 /// |
| 299 /// This algorithm is ported from |
| 300 /// `package:front_end/src/fasta/kernel/kernel_library_builder.dart` and |
| 301 /// added create allow for equivalence testing between the AST and kernel |
| 302 /// based compilations in face of shared mixins. It will be removed when we |
| 303 /// no longer need equivalence testing. |
| 304 ResolutionDartType createMixinsOptimized( |
| 305 BaseClassElementX element, MixinApplication superMixin, |
| 306 {bool isNamed: false}) { |
| 307 LibraryElementX library = element.library; |
| 308 Map<String, MixinApplicationElementX> mixinApplicationClasses = |
| 309 library.mixinApplicationCache; |
| 310 |
| 311 String name = element.isNamedMixinApplication ? element.name : null; |
| 312 ResolutionDartType supertype = |
| 313 resolveSupertype(element, superMixin.superclass); |
| 314 Link<Node> link = superMixin.mixins.nodes; |
| 315 List<ResolutionDartType> mixins = <ResolutionDartType>[]; |
| 316 List<Node> mixinNodes = <Node>[]; |
| 317 while (!link.isEmpty) { |
| 318 mixins.add(checkMixinType(link.head)); |
| 319 mixinNodes.add(link.head); |
| 320 link = link.tail; |
| 321 } |
| 322 |
| 323 List<List<String>> signatureParts = <List<String>>[]; |
| 324 Map<String, ResolutionDartType> freeTypes = <String, ResolutionDartType>{}; |
| 325 |
| 326 { |
| 327 Map<String, String> unresolved = <String, String>{}; |
| 328 int unresolvedCount = 0; |
| 329 |
| 330 /// Compute a signature of the type arguments used by the supertype and |
| 331 /// mixins. These types are free variables. At this point we can't |
| 332 /// trust that the number of type arguments match the type parameters, |
| 333 /// so we also need to be able to detect missing type arguments. To do |
| 334 /// so, we separate each list of type arguments by `^` and type |
| 335 /// arguments by `&`. For example, the mixin `C<S> with M<T, U>` would |
| 336 /// look like this: |
| 337 /// |
| 338 /// ^#U0^#U1&#U2 |
| 339 /// |
| 340 /// Where `#U0`, `#U1`, and `#U2` are the free variables arising from |
| 341 /// `S`, `T`, and `U` respectively. |
| 342 /// |
| 343 /// As we can resolve any type parameters used at this point, those are |
| 344 /// named `#T0` and so forth. This reduces the number of free variables |
| 345 /// which is crucial for memory usage and the Dart VM's bootstrap |
| 346 /// sequence. |
| 347 /// |
| 348 /// For example, consider this use of mixin applications: |
| 349 /// |
| 350 /// class _InternalLinkedHashMap<K, V> extends _HashVMBase |
| 351 /// with |
| 352 /// MapMixin<K, V>, |
| 353 /// _LinkedHashMapMixin<K, V>, |
| 354 /// _HashBase, |
| 355 /// _OperatorEqualsAndHashCode {} |
| 356 /// |
| 357 /// In this case, only two variables are free, and we produce this |
| 358 /// signature: `^^#T0&#T1^#T0&#T1^^`. Assume another class uses the |
| 359 /// sames mixins but with missing type arguments for `MapMixin`, its |
| 360 /// signature would be: `^^^#T0&#T1^^`. |
| 361 /// |
| 362 /// Note that we do not need to compute a signature for a named mixin |
| 363 /// application with only one mixin as we don't have to invent a name |
| 364 /// for any classes in this situation. |
| 365 void analyzeArguments(ResolutionDartType type, {bool isLast}) { |
| 366 if (isNamed && isLast) { |
| 367 // The last mixin of a named mixin application doesn't contribute |
| 368 // to free variables. |
| 369 return; |
| 370 } |
| 371 if (type is GenericType) { |
| 372 List<String> part = <String>[]; |
| 373 for (int i = 0; i < type.typeArguments.length; i++) { |
| 374 var argument = type.typeArguments[i]; |
| 375 String name; |
| 376 if (argument is ResolutionTypeVariableType) { |
| 377 int index = element.typeVariables.indexOf(argument) ?? -1; |
| 378 if (index != -1) { |
| 379 name = "#T${index}"; |
| 380 } |
| 381 } else if (argument is GenericType && argument.isRaw) { |
| 382 name = unresolved[argument.name] ??= "#U${unresolvedCount++}"; |
| 383 } |
| 384 name ??= "#U${unresolvedCount++}"; |
| 385 freeTypes[name] = argument; |
| 386 part.add(name); |
| 387 } |
| 388 signatureParts.add(part); |
| 389 } |
| 390 } |
| 391 |
| 392 analyzeArguments(supertype, isLast: false); |
| 393 for (int i = 0; i < mixins.length; i++) { |
| 394 analyzeArguments(mixins[i], isLast: i == mixins.length - 1); |
| 395 } |
| 396 } |
| 397 |
| 398 List<List<String>> currentSignatureParts = <List<String>>[]; |
| 399 String computeSignature(int index) { |
| 400 if (freeTypes.isEmpty) return ""; |
| 401 currentSignatureParts.add(signatureParts[index]); |
| 402 if (currentSignatureParts.any((l) => l.isNotEmpty)) { |
| 403 return "^${currentSignatureParts.map((l) => l.join('&')).join('^')}"; |
| 404 } else { |
| 405 return ""; |
| 406 } |
| 407 } |
| 408 |
| 409 Map<String, ResolutionTypeVariableType> computeTypeVariables( |
| 410 ClassElement cls, Node node) { |
| 411 Map<String, ResolutionTypeVariableType> variables = |
| 412 <String, ResolutionTypeVariableType>{}; |
| 413 int index = 0; |
| 414 for (List<String> strings in currentSignatureParts) { |
| 415 for (String name in strings) { |
| 416 variables[name] ??= new ResolutionTypeVariableType( |
| 417 new TypeVariableElementX(name, cls, index++, node)); |
| 418 } |
| 419 } |
| 420 return variables; |
| 421 } |
| 422 |
| 423 computeSignature(0); // This combines the supertype with the first mixin. |
| 424 |
| 425 for (int i = 0; i < mixins.length; i++) { |
| 426 int signatureIndex = i + 1; |
| 427 Set<String> supertypeArguments = new Set<String>(); |
| 428 for (List<String> part in currentSignatureParts) { |
| 429 supertypeArguments.addAll(part); |
| 430 } |
| 431 Node node = mixinNodes[i]; |
| 432 ResolutionDartType mixin = mixins[i]; |
| 433 |
| 434 bool lastAndNamed = i == mixins.length - 1 && isNamed; |
| 435 |
| 436 ResolutionInterfaceType createMixinApplication() { |
| 437 Map<String, ResolutionDartType> variables; |
| 438 MixinApplicationElementX mixinElement; |
| 439 ResolutionInterfaceType mixinType; |
| 440 if (lastAndNamed) { |
| 441 mixinElement = element; |
| 442 variables = freeTypes; |
| 443 } else { |
| 444 String signature = computeSignature(signatureIndex); |
| 445 name = supertype.name; |
| 446 int index = name.indexOf("^"); |
| 447 if (index != -1) { |
| 448 name = name.substring(0, index); |
| 449 } |
| 450 name = "$name&${mixin.name}$signature"; |
| 451 mixinElement = mixinApplicationClasses[name]; |
| 452 if (mixinElement != null) return mixinElement.thisType; |
| 453 |
| 454 mixinElement = new UnnamedMixinApplicationElementX( |
| 455 name, element, resolution.idGenerator.getNextFreeId(), node); |
| 456 variables = computeTypeVariables(mixinElement, node); |
| 457 mixinElement.setThisAndRawTypes(variables.values.toList()); |
| 458 mixinApplicationClasses[name] = mixinElement; |
| 459 } |
| 460 |
| 461 if (supertypeArguments.isNotEmpty) { |
| 462 List<ResolutionDartType> supertypeTypeArguments = |
| 463 <ResolutionDartType>[]; |
| 464 for (String part in supertypeArguments) { |
| 465 supertypeTypeArguments.add(variables[part]); |
| 466 } |
| 467 supertype = new ResolutionInterfaceType( |
| 468 supertype.element, supertypeTypeArguments); |
| 469 } |
| 470 |
| 471 if (lastAndNamed) { |
| 472 mixinType = mixin; |
| 473 } else { |
| 474 List<ResolutionDartType> mixinTypeArguments = <ResolutionDartType>[]; |
| 475 for (String part in signatureParts[signatureIndex]) { |
| 476 mixinTypeArguments.add(variables[part]); |
| 477 } |
| 478 mixinType = |
| 479 new ResolutionInterfaceType(mixin.element, mixinTypeArguments); |
| 480 } |
| 481 |
| 482 doApplyMixinTo(mixinElement, supertype, mixinType); |
| 483 mixinElement.resolutionState = STATE_DONE; |
| 484 mixinElement.supertypeLoadState = STATE_DONE; |
| 485 return mixinElement.thisType; |
| 486 } |
| 487 |
| 488 supertype = createMixinApplication(); |
| 489 } |
| 490 |
| 491 return new ResolutionInterfaceType( |
| 492 supertype.element, freeTypes.values.toList()); |
| 493 } |
| 494 |
| 495 ResolutionDartType createMixins(ClassElement element, MixinApplication node, |
| 496 {bool isNamed: false}) { |
288 ResolutionDartType supertype = resolveSupertype(element, node.superclass); | 497 ResolutionDartType supertype = resolveSupertype(element, node.superclass); |
289 Link<Node> link = node.mixins.nodes; | 498 Link<Node> link = node.mixins.nodes; |
290 while (!link.tail.isEmpty) { | 499 while (!link.isEmpty) { |
| 500 if (isNamed && link.tail.isEmpty) { |
| 501 doApplyMixinTo(element, supertype, checkMixinType(link.head)); |
| 502 return supertype; |
| 503 } |
291 supertype = applyMixin(supertype, checkMixinType(link.head), link.head); | 504 supertype = applyMixin(supertype, checkMixinType(link.head), link.head); |
292 link = link.tail; | 505 link = link.tail; |
293 } | 506 } |
294 doApplyMixinTo(element, supertype, checkMixinType(link.head)); | 507 return supertype; |
295 return element.computeType(resolution); | |
296 } | 508 } |
297 | 509 |
298 ResolutionDartType applyMixin( | 510 ResolutionDartType applyMixin( |
299 ResolutionDartType supertype, ResolutionDartType mixinType, Node node) { | 511 ResolutionDartType supertype, ResolutionDartType mixinType, Node node) { |
300 String superName = supertype.name; | 512 String superName = supertype.name; |
301 String mixinName = mixinType.name; | 513 String mixinName = mixinType.name; |
302 MixinApplicationElementX mixinApplication = | 514 MixinApplicationElementX mixinApplication = |
303 new UnnamedMixinApplicationElementX("${superName}+${mixinName}", | 515 new UnnamedMixinApplicationElementX("${superName}+${mixinName}", |
304 element, resolution.idGenerator.getNextFreeId(), node); | 516 element, resolution.idGenerator.getNextFreeId(), node); |
305 // Create synthetic type variables for the mixin application. | 517 // 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(); | 858 Identifier selector = node.selector.asIdentifier(); |
647 var e = prefixElement.lookupLocalMember(selector.source); | 859 var e = prefixElement.lookupLocalMember(selector.source); |
648 if (e == null || !e.impliesType) { | 860 if (e == null || !e.impliesType) { |
649 reporter.reportErrorMessage(node.selector, | 861 reporter.reportErrorMessage(node.selector, |
650 MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.selector}); | 862 MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.selector}); |
651 return; | 863 return; |
652 } | 864 } |
653 loadSupertype(e, node); | 865 loadSupertype(e, node); |
654 } | 866 } |
655 } | 867 } |
OLD | NEW |