Chromium Code Reviews| 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 |