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