Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 universe; | 5 library universe; |
| 6 | 6 |
| 7 import '../closure.dart'; | 7 import '../closure.dart'; |
| 8 import '../elements/elements.dart'; | 8 import '../elements/elements.dart'; |
| 9 import '../dart2jslib.dart'; | 9 import '../dart2jslib.dart'; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 93 class SelectorKind { | 93 class SelectorKind { |
| 94 final String name; | 94 final String name; |
| 95 const SelectorKind(this.name); | 95 const SelectorKind(this.name); |
| 96 | 96 |
| 97 static const SelectorKind GETTER = const SelectorKind('getter'); | 97 static const SelectorKind GETTER = const SelectorKind('getter'); |
| 98 static const SelectorKind SETTER = const SelectorKind('setter'); | 98 static const SelectorKind SETTER = const SelectorKind('setter'); |
| 99 static const SelectorKind CALL = const SelectorKind('call'); | 99 static const SelectorKind CALL = const SelectorKind('call'); |
| 100 static const SelectorKind OPERATOR = const SelectorKind('operator'); | 100 static const SelectorKind OPERATOR = const SelectorKind('operator'); |
| 101 static const SelectorKind INDEX = const SelectorKind('index'); | 101 static const SelectorKind INDEX = const SelectorKind('index'); |
| 102 | 102 |
| 103 toString() => name; | 103 String toString() => name; |
| 104 } | |
| 105 | |
| 106 class TypedSelectorKind { | |
| 107 final String name; | |
| 108 const TypedSelectorKind(this.name); | |
| 109 | |
| 110 /// Unknown type: used for untyped selector. | |
| 111 static const TypedSelectorKind UNKNOWN = const TypedSelectorKind('unknown'); | |
| 112 | |
| 113 // Exact type: the selector knows the exact type of the receiver. | |
| 114 // For example [:new Map():]. | |
| 115 static const TypedSelectorKind EXACT = const TypedSelectorKind('exact'); | |
| 116 | |
| 117 // Subclass type: the receiver type is in a subclass hierarchy. | |
| 118 // For example [:this:]. | |
| 119 static const TypedSelectorKind SUBCLASS = const TypedSelectorKind('subclass'); | |
| 120 | |
| 121 // Interface type: any type that implements the receiver type. | |
| 122 // For example [(foo as Foo).bar()], or any type annotation in | |
| 123 // checked mode. | |
| 124 static const TypedSelectorKind INTERFACE = | |
| 125 const TypedSelectorKind('interface'); | |
| 126 | |
| 127 String toString() => name; | |
| 104 } | 128 } |
| 105 | 129 |
| 106 class Selector { | 130 class Selector { |
| 107 final SelectorKind kind; | 131 final SelectorKind kind; |
| 108 final SourceString name; | 132 final SourceString name; |
| 109 final LibraryElement library; // Library is null for non-private selectors. | 133 final LibraryElement library; // Library is null for non-private selectors. |
| 110 | 134 |
| 111 // The numbers of arguments of the selector. Includes named arguments. | 135 // The numbers of arguments of the selector. Includes named arguments. |
| 112 final int argumentCount; | 136 final int argumentCount; |
| 113 final List<SourceString> namedArguments; | 137 final List<SourceString> namedArguments; |
| 114 final List<SourceString> orderedNamedArguments; | 138 final List<SourceString> orderedNamedArguments; |
| 139 TypedSelectorKind get typeKind => TypedSelectorKind.UNKNOWN; | |
| 115 | 140 |
| 116 Selector( | 141 Selector( |
| 117 this.kind, | 142 this.kind, |
| 118 SourceString name, | 143 SourceString name, |
| 119 LibraryElement library, | 144 LibraryElement library, |
| 120 this.argumentCount, | 145 this.argumentCount, |
| 121 [List<SourceString> namedArguments = const <SourceString>[]]) | 146 [List<SourceString> namedArguments = const <SourceString>[]]) |
| 122 : this.name = name, | 147 : this.name = name, |
| 123 this.library = name.isPrivate() ? library : null, | 148 this.library = name.isPrivate() ? library : null, |
| 124 this.namedArguments = namedArguments, | 149 this.namedArguments = namedArguments, |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 361 | 386 |
| 362 bool operator ==(other) { | 387 bool operator ==(other) { |
| 363 if (other is !Selector) return false; | 388 if (other is !Selector) return false; |
| 364 return identical(receiverType, other.receiverType) | 389 return identical(receiverType, other.receiverType) |
| 365 && equalsUntyped(other); | 390 && equalsUntyped(other); |
| 366 } | 391 } |
| 367 | 392 |
| 368 bool equalsUntyped(Selector other) { | 393 bool equalsUntyped(Selector other) { |
| 369 return name == other.name | 394 return name == other.name |
| 370 && kind == other.kind | 395 && kind == other.kind |
| 396 && typeKind == other.typeKind | |
| 371 && identical(library, other.library) | 397 && identical(library, other.library) |
| 372 && argumentCount == other.argumentCount | 398 && argumentCount == other.argumentCount |
| 373 && namedArguments.length == other.namedArguments.length | 399 && namedArguments.length == other.namedArguments.length |
| 374 && sameNames(namedArguments, other.namedArguments); | 400 && sameNames(namedArguments, other.namedArguments); |
| 375 } | 401 } |
| 376 | 402 |
| 377 List<SourceString> getOrderedNamedArguments() { | 403 List<SourceString> getOrderedNamedArguments() { |
| 378 if (namedArguments.isEmpty) return namedArguments; | 404 if (namedArguments.isEmpty) return namedArguments; |
| 379 if (!orderedNamedArguments.isEmpty) return orderedNamedArguments; | 405 if (!orderedNamedArguments.isEmpty) return orderedNamedArguments; |
| 380 | 406 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 394 } | 420 } |
| 395 return "[$result]"; | 421 return "[$result]"; |
| 396 } | 422 } |
| 397 return ''; | 423 return ''; |
| 398 } | 424 } |
| 399 | 425 |
| 400 String toString() { | 426 String toString() { |
| 401 String named = ''; | 427 String named = ''; |
| 402 String type = ''; | 428 String type = ''; |
| 403 if (namedArgumentCount > 0) named = ', named=${namedArgumentsToString()}'; | 429 if (namedArgumentCount > 0) named = ', named=${namedArgumentsToString()}'; |
| 404 if (receiverType != null) type = ', type=$receiverType'; | 430 if (receiverType != null) type = ', type=$receiverType'; |
|
sra1
2013/02/08 23:25:16
Include the typeKind in the string, e.g.
type = '
| |
| 405 return 'Selector($kind, ${name.slowToString()}, ' | 431 return 'Selector($kind, ${name.slowToString()}, ' |
| 406 'arity=$argumentCount$named$type)'; | 432 'arity=$argumentCount$named$type)'; |
| 407 } | 433 } |
| 408 } | 434 } |
| 409 | 435 |
| 410 class TypedSelector extends Selector { | 436 class TypedSelector extends Selector { |
| 411 /** | 437 /** |
| 412 * The type of the receiver. Any subtype of that type can be the | 438 * The type of the receiver. |
| 413 * target of the invocation. | |
| 414 */ | 439 */ |
| 415 final DartType receiverType; | 440 final DartType receiverType; |
| 441 final TypedSelectorKind typeKind; | |
| 416 | 442 |
| 417 final Selector asUntyped; | 443 final Selector asUntyped; |
| 418 | 444 |
| 419 TypedSelector(DartType this.receiverType, Selector selector) | 445 TypedSelector(DartType this.receiverType, this.typeKind, Selector selector) |
| 420 : asUntyped = selector.asUntyped, | 446 : asUntyped = selector.asUntyped, |
| 421 super(selector.kind, | 447 super(selector.kind, |
| 422 selector.name, | 448 selector.name, |
| 423 selector.library, | 449 selector.library, |
| 424 selector.argumentCount, | 450 selector.argumentCount, |
| 425 selector.namedArguments) { | 451 selector.namedArguments) { |
| 426 // Invariant: Typed selector can not be based on a malformed type. | 452 // Invariant: Typed selector can not be based on a malformed type. |
| 427 assert(!identical(receiverType.kind, TypeKind.MALFORMED_TYPE)); | 453 assert(!identical(receiverType.kind, TypeKind.MALFORMED_TYPE)); |
| 428 assert(asUntyped.receiverType == null); | 454 assert(asUntyped.receiverType == null); |
| 429 } | 455 } |
| 430 | 456 |
| 431 /** | 457 /** |
| 432 * Check if [element] will be the one used at runtime when being | 458 * Check if [element] will be the one used at runtime when being |
| 433 * invoked on an instance of [cls]. | 459 * invoked on an instance of [cls]. |
| 434 */ | 460 */ |
| 435 bool hasElementIn(ClassElement cls, Element element) { | 461 bool hasElementIn(ClassElement cls, Element element) { |
| 436 // Use the selector for the lookup instead of [:element.name:] | 462 // Use the selector for the lookup instead of [:element.name:] |
| 437 // because the selector has the right privacy information. | 463 // because the selector has the right privacy information. |
| 438 Element resolved = cls.lookupSelector(this); | 464 Element resolved = cls.lookupSelector(this); |
| 439 if (resolved == element) return true; | 465 if (resolved == element) return true; |
| 440 if (resolved == null) return false; | 466 if (resolved == null) return false; |
| 441 if (resolved.isAbstractField()) { | 467 if (resolved.isAbstractField()) { |
| 442 AbstractFieldElement field = resolved; | 468 AbstractFieldElement field = resolved; |
| 443 if (element == field.getter || element == field.setter) { | 469 if (element == field.getter || element == field.setter) { |
| 444 return true; | 470 return true; |
| 445 } else { | 471 } else { |
| 446 ClassElement otherCls = field.getEnclosingClass(); | |
| 447 // We have not found a match, but another class higher in the | 472 // We have not found a match, but another class higher in the |
| 448 // hierarchy may define the getter or the setter. | 473 // hierarchy may define the getter or the setter. |
| 449 return hasElementIn(otherCls.superclass, element); | 474 ClassElement otherCls = field.getEnclosingClass().superclass; |
| 475 if (otherCls == null) return false; | |
| 476 return hasElementIn(otherCls, element); | |
| 450 } | 477 } |
| 451 } | 478 } |
| 452 return false; | 479 return false; |
| 453 } | 480 } |
| 454 | 481 |
| 455 bool appliesUnnamed(Element element, Compiler compiler) { | 482 bool appliesUnnamed(Element element, Compiler compiler) { |
| 456 assert(sameNameHack(element, compiler)); | 483 assert(sameNameHack(element, compiler)); |
| 457 // [TypedSelector] are only used when compiling. | 484 // [TypedSelector] are only used when compiling. |
| 458 assert(compiler.phase == Compiler.PHASE_COMPILING); | 485 assert(compiler.phase == Compiler.PHASE_COMPILING); |
| 459 if (!element.isMember()) return false; | 486 if (!element.isMember()) return false; |
| 460 | 487 |
| 461 // A closure can be called through any typed selector: | 488 // A closure can be called through any typed selector: |
| 462 // class A { | 489 // class A { |
| 463 // get foo => () => 42; | 490 // get foo => () => 42; |
| 464 // bar() => foo(); // The call to 'foo' is a typed selector. | 491 // bar() => foo(); // The call to 'foo' is a typed selector. |
| 465 // } | 492 // } |
| 466 ClassElement other = element.getEnclosingClass(); | 493 ClassElement other = element.getEnclosingClass(); |
| 467 if (identical(other.superclass, compiler.closureClass)) { | 494 if (identical(other.superclass, compiler.closureClass)) { |
| 468 return appliesUntyped(element, compiler); | 495 return appliesUntyped(element, compiler); |
| 469 } | 496 } |
| 470 | 497 |
| 471 Element self = receiverType.element; | 498 Element self = receiverType.element; |
| 472 if (self.isTypedef()) { | 499 if (self.isTypedef()) { |
| 473 // A typedef is a function type that doesn't have any | 500 // A typedef is a function type that doesn't have any |
| 474 // user-defined members. | 501 // user-defined members. |
| 475 return false; | 502 return false; |
| 476 } | 503 } |
| 477 | 504 |
| 478 if (other.implementsInterface(self) | 505 if (typeKind == TypedSelectorKind.EXACT) { |
| 479 || other.isSubclassOf(self) | 506 return hasElementIn(self, element) && appliesUntyped(element, compiler); |
| 480 || compiler.world.hasAnySubclassThatImplements(other, receiverType)) { | 507 } else if (typeKind == TypedSelectorKind.SUBCLASS) { |
| 481 return appliesUntyped(element, compiler); | 508 return (hasElementIn(self, element) || other.isSubclassOf(self)) |
| 482 } | 509 && appliesUntyped(element, compiler); |
| 510 } else { | |
| 511 assert(typeKind == TypedSelectorKind.INTERFACE); | |
| 512 if (other.implementsInterface(self) | |
| 513 || other.isSubclassOf(self) | |
| 514 || compiler.world.hasAnySubclassThatImplements(other, receiverType)) { | |
| 515 return appliesUntyped(element, compiler); | |
| 516 } | |
| 483 | 517 |
| 484 // If [self] is a subclass of [other], it inherits the | 518 // If [self] is a subclass of [other], it inherits the |
| 485 // implementation of [element]. | 519 // implementation of [element]. |
| 486 ClassElement cls = self; | 520 ClassElement cls = self; |
| 487 if (cls.isSubclassOf(other)) { | 521 if (cls.isSubclassOf(other)) { |
| 488 // Resolve an invocation of [element.name] on [self]. If it | 522 // Resolve an invocation of [element.name] on [self]. If it |
| 489 // is found, this selector is a candidate. | 523 // is found, this selector is a candidate. |
| 490 return hasElementIn(self, element) && appliesUntyped(element, compiler); | 524 return hasElementIn(self, element) && appliesUntyped(element, compiler); |
| 525 } | |
| 491 } | 526 } |
| 492 | 527 |
| 493 return false; | 528 return false; |
| 494 } | 529 } |
| 495 } | 530 } |
| OLD | NEW |