| OLD | NEW |
| 1 // Copyright (c) 2012, 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 universe; | 5 part of universe; |
| 6 | |
| 7 import 'dart:collection'; | |
| 8 | |
| 9 import '../common/names.dart' show | |
| 10 Identifiers, | |
| 11 Names, | |
| 12 Selectors; | |
| 13 import '../compiler.dart' show | |
| 14 Compiler; | |
| 15 import '../diagnostics/invariant.dart' show | |
| 16 invariant; | |
| 17 import '../diagnostics/spannable.dart' show | |
| 18 SpannableAssertionFailure; | |
| 19 import '../elements/elements.dart'; | |
| 20 import '../dart_types.dart'; | |
| 21 import '../tree/tree.dart'; | |
| 22 import '../types/types.dart'; | |
| 23 import '../util/util.dart'; | |
| 24 import '../world.dart' show | |
| 25 ClassWorld, | |
| 26 World; | |
| 27 | |
| 28 part 'function_set.dart'; | |
| 29 part 'side_effects.dart'; | |
| 30 | |
| 31 class UniverseSelector { | |
| 32 final Selector selector; | |
| 33 final ReceiverMask mask; | |
| 34 | |
| 35 UniverseSelector(this.selector, this.mask); | |
| 36 | |
| 37 bool appliesUnnamed(Element element, ClassWorld world) { | |
| 38 return selector.appliesUnnamed(element, world) && | |
| 39 (mask == null || mask.canHit(element, selector, world)); | |
| 40 } | |
| 41 | |
| 42 String toString() => '$selector,$mask'; | |
| 43 } | |
| 44 | |
| 45 /// A potential receiver for a dynamic call site. | |
| 46 abstract class ReceiverMask { | |
| 47 /// Returns whether [element] is a potential target when being | |
| 48 /// invoked on this receiver mask. [selector] is used to ensure library | |
| 49 /// privacy is taken into account. | |
| 50 bool canHit(Element element, Selector selector, ClassWorld classWorld); | |
| 51 } | |
| 52 | |
| 53 /// A set of potential receivers for the dynamic call sites of the same | |
| 54 /// selector. | |
| 55 /// | |
| 56 /// For instance for these calls | |
| 57 /// | |
| 58 /// new A().foo(a, b); | |
| 59 /// new B().foo(0, 42); | |
| 60 /// | |
| 61 /// the receiver mask set for dynamic calls to 'foo' with to positional | |
| 62 /// arguments will contain receiver masks abstracting `new A()` and `new B()`. | |
| 63 abstract class ReceiverMaskSet { | |
| 64 /// Returns `true` if [selector] applies to any of the potential receivers | |
| 65 /// in this set given the closed [world]. | |
| 66 bool applies(Element element, Selector selector, ClassWorld world); | |
| 67 | |
| 68 /// Returns `true` if any potential receivers in this set given the closed | |
| 69 /// [world] have no implementation matching [selector]. | |
| 70 /// | |
| 71 /// For instance for this code snippet | |
| 72 /// | |
| 73 /// class A {} | |
| 74 /// class B { foo() {} } | |
| 75 /// m(b) => (b ? new A() : new B()).foo(); | |
| 76 /// | |
| 77 /// the potential receiver `new A()` have no implementation of `foo` and thus | |
| 78 /// needs to handle the call though its `noSuchMethod` handler. | |
| 79 bool needsNoSuchMethodHandling(Selector selector, ClassWorld world); | |
| 80 } | |
| 81 | |
| 82 /// A mutable [ReceiverMaskSet] used in [Universe]. | |
| 83 abstract class UniverseReceiverMaskSet extends ReceiverMaskSet { | |
| 84 /// Adds [mask] to this set of potential receivers. Return `true` if the | |
| 85 /// set expanded due to the new mask. | |
| 86 bool addReceiverMask(ReceiverMask mask); | |
| 87 } | |
| 88 | |
| 89 /// Strategy for computing potential receivers of dynamic call sites. | |
| 90 abstract class ReceiverMaskStrategy { | |
| 91 /// Create a [UniverseReceiverMaskSet] to represent the potential receiver for | |
| 92 /// a dynamic call site with [selector]. | |
| 93 UniverseReceiverMaskSet createReceiverMaskSet(Selector selector); | |
| 94 } | |
| 95 | |
| 96 class Universe { | |
| 97 /// The set of all directly instantiated classes, that is, classes with a | |
| 98 /// generative constructor that has been called directly and not only through | |
| 99 /// a super-call. | |
| 100 /// | |
| 101 /// Invariant: Elements are declaration elements. | |
| 102 // TODO(johnniwinther): [_directlyInstantiatedClasses] and | |
| 103 // [_instantiatedTypes] sets should be merged. | |
| 104 final Set<ClassElement> _directlyInstantiatedClasses = | |
| 105 new Set<ClassElement>(); | |
| 106 | |
| 107 /// The set of all directly instantiated types, that is, the types of the | |
| 108 /// directly instantiated classes. | |
| 109 /// | |
| 110 /// See [_directlyInstantiatedClasses]. | |
| 111 final Set<DartType> _instantiatedTypes = new Set<DartType>(); | |
| 112 | |
| 113 /// The set of all instantiated classes, either directly, as superclasses or | |
| 114 /// as supertypes. | |
| 115 /// | |
| 116 /// Invariant: Elements are declaration elements. | |
| 117 final Set<ClassElement> _allInstantiatedClasses = new Set<ClassElement>(); | |
| 118 | |
| 119 /// The set of all referenced static fields. | |
| 120 /// | |
| 121 /// Invariant: Elements are declaration elements. | |
| 122 final Set<FieldElement> allReferencedStaticFields = new Set<FieldElement>(); | |
| 123 | |
| 124 /** | |
| 125 * Documentation wanted -- johnniwinther | |
| 126 * | |
| 127 * Invariant: Elements are declaration elements. | |
| 128 */ | |
| 129 final Set<FunctionElement> staticFunctionsNeedingGetter = | |
| 130 new Set<FunctionElement>(); | |
| 131 final Set<FunctionElement> methodsNeedingSuperGetter = | |
| 132 new Set<FunctionElement>(); | |
| 133 final Map<String, Map<Selector, ReceiverMaskSet>> _invokedNames = | |
| 134 <String, Map<Selector, ReceiverMaskSet>>{}; | |
| 135 final Map<String, Map<Selector, ReceiverMaskSet>> _invokedGetters = | |
| 136 <String, Map<Selector, ReceiverMaskSet>>{}; | |
| 137 final Map<String, Map<Selector, ReceiverMaskSet>> _invokedSetters = | |
| 138 <String, Map<Selector, ReceiverMaskSet>>{}; | |
| 139 | |
| 140 /** | |
| 141 * Fields accessed. Currently only the codegen knows this | |
| 142 * information. The resolver is too conservative when seeing a | |
| 143 * getter and only registers an invoked getter. | |
| 144 */ | |
| 145 final Set<Element> fieldGetters = new Set<Element>(); | |
| 146 | |
| 147 /** | |
| 148 * Fields set. See comment in [fieldGetters]. | |
| 149 */ | |
| 150 final Set<Element> fieldSetters = new Set<Element>(); | |
| 151 final Set<DartType> isChecks = new Set<DartType>(); | |
| 152 | |
| 153 /** | |
| 154 * Set of (live) [:call:] methods whose signatures reference type variables. | |
| 155 * | |
| 156 * A live [:call:] method is one whose enclosing class has been instantiated. | |
| 157 */ | |
| 158 final Set<Element> callMethodsWithFreeTypeVariables = new Set<Element>(); | |
| 159 | |
| 160 /** | |
| 161 * Set of (live) local functions (closures) whose signatures reference type | |
| 162 * variables. | |
| 163 * | |
| 164 * A live function is one whose enclosing member function has been enqueued. | |
| 165 */ | |
| 166 final Set<Element> closuresWithFreeTypeVariables = new Set<Element>(); | |
| 167 | |
| 168 /** | |
| 169 * Set of all closures in the program. Used by the mirror tracking system | |
| 170 * to find all live closure instances. | |
| 171 */ | |
| 172 final Set<LocalFunctionElement> allClosures = new Set<LocalFunctionElement>(); | |
| 173 | |
| 174 /** | |
| 175 * Set of methods in instantiated classes that are potentially | |
| 176 * closurized. | |
| 177 */ | |
| 178 final Set<Element> closurizedMembers = new Set<Element>(); | |
| 179 | |
| 180 final ReceiverMaskStrategy receiverMaskStrategy; | |
| 181 | |
| 182 Universe(this.receiverMaskStrategy); | |
| 183 | |
| 184 /// All directly instantiated classes, that is, classes with a generative | |
| 185 /// constructor that has been called directly and not only through a | |
| 186 /// super-call. | |
| 187 // TODO(johnniwinther): Improve semantic precision. | |
| 188 Iterable<ClassElement> get directlyInstantiatedClasses { | |
| 189 return _directlyInstantiatedClasses; | |
| 190 } | |
| 191 | |
| 192 /// All instantiated classes, either directly, as superclasses or as | |
| 193 /// supertypes. | |
| 194 // TODO(johnniwinther): Improve semantic precision. | |
| 195 Iterable<ClassElement> get allInstantiatedClasses { | |
| 196 return _allInstantiatedClasses; | |
| 197 } | |
| 198 | |
| 199 /// All directly instantiated types, that is, the types of the directly | |
| 200 /// instantiated classes. | |
| 201 /// | |
| 202 /// See [directlyInstantiatedClasses]. | |
| 203 // TODO(johnniwinther): Improve semantic precision. | |
| 204 Iterable<DartType> get instantiatedTypes => _instantiatedTypes; | |
| 205 | |
| 206 /// Returns `true` if [cls] is considered to be instantiated, either directly, | |
| 207 /// through subclasses or through subtypes. The latter case only contains | |
| 208 /// spurious information from instatiations through factory constructors and | |
| 209 /// mixins. | |
| 210 // TODO(johnniwinther): Improve semantic precision. | |
| 211 bool isInstantiated(ClassElement cls) { | |
| 212 return _allInstantiatedClasses.contains(cls); | |
| 213 } | |
| 214 | |
| 215 /// Register [type] as (directly) instantiated. | |
| 216 /// | |
| 217 /// If [byMirrors] is `true`, the instantiation is through mirrors. | |
| 218 // TODO(johnniwinther): Fully enforce the separation between exact, through | |
| 219 // subclass and through subtype instantiated types/classes. | |
| 220 // TODO(johnniwinther): Support unknown type arguments for generic types. | |
| 221 void registerTypeInstantiation(InterfaceType type, | |
| 222 {bool byMirrors: false}) { | |
| 223 _instantiatedTypes.add(type); | |
| 224 ClassElement cls = type.element; | |
| 225 if (!cls.isAbstract | |
| 226 // We can't use the closed-world assumption with native abstract | |
| 227 // classes; a native abstract class may have non-abstract subclasses | |
| 228 // not declared to the program. Instances of these classes are | |
| 229 // indistinguishable from the abstract class. | |
| 230 || cls.isNative | |
| 231 // Likewise, if this registration comes from the mirror system, | |
| 232 // all bets are off. | |
| 233 // TODO(herhut): Track classes required by mirrors seperately. | |
| 234 || byMirrors) { | |
| 235 _directlyInstantiatedClasses.add(cls); | |
| 236 } | |
| 237 | |
| 238 // TODO(johnniwinther): Replace this by separate more specific mappings. | |
| 239 if (!_allInstantiatedClasses.add(cls)) return; | |
| 240 cls.allSupertypes.forEach((InterfaceType supertype) { | |
| 241 _allInstantiatedClasses.add(supertype.element); | |
| 242 }); | |
| 243 } | |
| 244 | |
| 245 bool _hasMatchingSelector(Map<Selector, ReceiverMaskSet> selectors, | |
| 246 Element member, | |
| 247 World world) { | |
| 248 if (selectors == null) return false; | |
| 249 for (Selector selector in selectors.keys) { | |
| 250 if (selector.appliesUnnamed(member, world)) { | |
| 251 ReceiverMaskSet masks = selectors[selector]; | |
| 252 if (masks.applies(member, selector, world)) { | |
| 253 return true; | |
| 254 } | |
| 255 } | |
| 256 } | |
| 257 return false; | |
| 258 } | |
| 259 | |
| 260 bool hasInvocation(Element member, World world) { | |
| 261 return _hasMatchingSelector(_invokedNames[member.name], member, world); | |
| 262 } | |
| 263 | |
| 264 bool hasInvokedGetter(Element member, World world) { | |
| 265 return _hasMatchingSelector(_invokedGetters[member.name], member, world); | |
| 266 } | |
| 267 | |
| 268 bool hasInvokedSetter(Element member, World world) { | |
| 269 return _hasMatchingSelector(_invokedSetters[member.name], member, world); | |
| 270 } | |
| 271 | |
| 272 bool registerInvocation(UniverseSelector selector) { | |
| 273 return _registerNewSelector(selector, _invokedNames); | |
| 274 } | |
| 275 | |
| 276 bool registerInvokedGetter(UniverseSelector selector) { | |
| 277 return _registerNewSelector(selector, _invokedGetters); | |
| 278 } | |
| 279 | |
| 280 bool registerInvokedSetter(UniverseSelector selector) { | |
| 281 return _registerNewSelector(selector, _invokedSetters); | |
| 282 } | |
| 283 | |
| 284 bool _registerNewSelector( | |
| 285 UniverseSelector universeSelector, | |
| 286 Map<String, Map<Selector, ReceiverMaskSet>> selectorMap) { | |
| 287 Selector selector = universeSelector.selector; | |
| 288 String name = selector.name; | |
| 289 ReceiverMask mask = universeSelector.mask; | |
| 290 Map<Selector, ReceiverMaskSet> selectors = selectorMap.putIfAbsent( | |
| 291 name, () => new Maplet<Selector, ReceiverMaskSet>()); | |
| 292 UniverseReceiverMaskSet masks = selectors.putIfAbsent( | |
| 293 selector, () => receiverMaskStrategy.createReceiverMaskSet(selector)); | |
| 294 return masks.addReceiverMask(mask); | |
| 295 } | |
| 296 | |
| 297 Map<Selector, ReceiverMaskSet> _asUnmodifiable( | |
| 298 Map<Selector, ReceiverMaskSet> map) { | |
| 299 if (map == null) return null; | |
| 300 return new UnmodifiableMapView(map); | |
| 301 } | |
| 302 | |
| 303 Map<Selector, ReceiverMaskSet> invocationsByName(String name) { | |
| 304 return _asUnmodifiable(_invokedNames[name]); | |
| 305 } | |
| 306 | |
| 307 Map<Selector, ReceiverMaskSet> getterInvocationsByName(String name) { | |
| 308 return _asUnmodifiable(_invokedGetters[name]); | |
| 309 } | |
| 310 | |
| 311 Map<Selector, ReceiverMaskSet> setterInvocationsByName(String name) { | |
| 312 return _asUnmodifiable(_invokedSetters[name]); | |
| 313 } | |
| 314 | |
| 315 void forEachInvokedName( | |
| 316 f(String name, Map<Selector, ReceiverMaskSet> selectors)) { | |
| 317 _invokedNames.forEach(f); | |
| 318 } | |
| 319 | |
| 320 void forEachInvokedGetter( | |
| 321 f(String name, Map<Selector, ReceiverMaskSet> selectors)) { | |
| 322 _invokedGetters.forEach(f); | |
| 323 } | |
| 324 | |
| 325 void forEachInvokedSetter( | |
| 326 f(String name, Map<Selector, ReceiverMaskSet> selectors)) { | |
| 327 _invokedSetters.forEach(f); | |
| 328 } | |
| 329 | |
| 330 DartType registerIsCheck(DartType type, Compiler compiler) { | |
| 331 type = type.unalias(compiler); | |
| 332 // Even in checked mode, type annotations for return type and argument | |
| 333 // types do not imply type checks, so there should never be a check | |
| 334 // against the type variable of a typedef. | |
| 335 isChecks.add(type); | |
| 336 return type; | |
| 337 } | |
| 338 | |
| 339 void registerStaticFieldUse(FieldElement staticField) { | |
| 340 assert(Elements.isStaticOrTopLevel(staticField) && staticField.isField); | |
| 341 assert(staticField.isDeclaration); | |
| 342 | |
| 343 allReferencedStaticFields.add(staticField); | |
| 344 } | |
| 345 | |
| 346 void forgetElement(Element element, Compiler compiler) { | |
| 347 allClosures.remove(element); | |
| 348 slowDirectlyNestedClosures(element).forEach(compiler.forgetElement); | |
| 349 closurizedMembers.remove(element); | |
| 350 fieldSetters.remove(element); | |
| 351 fieldGetters.remove(element); | |
| 352 _directlyInstantiatedClasses.remove(element); | |
| 353 _allInstantiatedClasses.remove(element); | |
| 354 if (element is ClassElement) { | |
| 355 assert(invariant( | |
| 356 element, element.thisType.isRaw, | |
| 357 message: 'Generic classes not supported (${element.thisType}).')); | |
| 358 _instantiatedTypes | |
| 359 ..remove(element.rawType) | |
| 360 ..remove(element.thisType); | |
| 361 } | |
| 362 } | |
| 363 | |
| 364 // TODO(ahe): Replace this method with something that is O(1), for example, | |
| 365 // by using a map. | |
| 366 List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) { | |
| 367 // Return new list to guard against concurrent modifications. | |
| 368 return new List<LocalFunctionElement>.from( | |
| 369 allClosures.where((LocalFunctionElement closure) { | |
| 370 return closure.executableContext == element; | |
| 371 })); | |
| 372 } | |
| 373 } | |
| 374 | |
| 375 class SelectorKind { | |
| 376 final String name; | |
| 377 final int hashCode; | |
| 378 const SelectorKind(this.name, this.hashCode); | |
| 379 | |
| 380 static const SelectorKind GETTER = const SelectorKind('getter', 0); | |
| 381 static const SelectorKind SETTER = const SelectorKind('setter', 1); | |
| 382 static const SelectorKind CALL = const SelectorKind('call', 2); | |
| 383 static const SelectorKind OPERATOR = const SelectorKind('operator', 3); | |
| 384 static const SelectorKind INDEX = const SelectorKind('index', 4); | |
| 385 | |
| 386 String toString() => name; | |
| 387 } | |
| 388 | 6 |
| 389 /// The structure of the arguments at a call-site. | 7 /// The structure of the arguments at a call-site. |
| 390 // TODO(johnniwinther): Should these be cached? | 8 // TODO(johnniwinther): Should these be cached? |
| 391 // TODO(johnniwinther): Should isGetter/isSetter be part of the call structure | 9 // TODO(johnniwinther): Should isGetter/isSetter be part of the call structure |
| 392 // instead of the selector? | 10 // instead of the selector? |
| 393 class CallStructure { | 11 class CallStructure { |
| 394 static const CallStructure NO_ARGS = const CallStructure.unnamed(0); | 12 static const CallStructure NO_ARGS = const CallStructure.unnamed(0); |
| 395 static const CallStructure ONE_ARG = const CallStructure.unnamed(1); | 13 static const CallStructure ONE_ARG = const CallStructure.unnamed(1); |
| 396 static const CallStructure TWO_ARGS = const CallStructure.unnamed(2); | 14 static const CallStructure TWO_ARGS = const CallStructure.unnamed(2); |
| 397 | 15 |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 655 return first.compareTo(second); | 273 return first.compareTo(second); |
| 656 }); | 274 }); |
| 657 return _orderedNamedArguments; | 275 return _orderedNamedArguments; |
| 658 } | 276 } |
| 659 | 277 |
| 660 @override | 278 @override |
| 661 String structureToString() { | 279 String structureToString() { |
| 662 return 'arity=$argumentCount, named=[${namedArguments.join(', ')}]'; | 280 return 'arity=$argumentCount, named=[${namedArguments.join(', ')}]'; |
| 663 } | 281 } |
| 664 } | 282 } |
| 665 | |
| 666 class Selector { | |
| 667 final SelectorKind kind; | |
| 668 final Name memberName; | |
| 669 final CallStructure callStructure; | |
| 670 | |
| 671 final int hashCode; | |
| 672 | |
| 673 int get argumentCount => callStructure.argumentCount; | |
| 674 int get namedArgumentCount => callStructure.namedArgumentCount; | |
| 675 int get positionalArgumentCount => callStructure.positionalArgumentCount; | |
| 676 List<String> get namedArguments => callStructure.namedArguments; | |
| 677 | |
| 678 String get name => memberName.text; | |
| 679 | |
| 680 LibraryElement get library => memberName.library; | |
| 681 | |
| 682 static const Name INDEX_NAME = const PublicName("[]"); | |
| 683 static const Name INDEX_SET_NAME = const PublicName("[]="); | |
| 684 static const Name CALL_NAME = Names.call; | |
| 685 | |
| 686 Selector.internal(this.kind, | |
| 687 this.memberName, | |
| 688 this.callStructure, | |
| 689 this.hashCode) { | |
| 690 assert(kind == SelectorKind.INDEX || | |
| 691 (memberName != INDEX_NAME && memberName != INDEX_SET_NAME)); | |
| 692 assert(kind == SelectorKind.OPERATOR || | |
| 693 kind == SelectorKind.INDEX || | |
| 694 !Elements.isOperatorName(memberName.text) || | |
| 695 identical(memberName.text, '??')); | |
| 696 assert(kind == SelectorKind.CALL || | |
| 697 kind == SelectorKind.GETTER || | |
| 698 kind == SelectorKind.SETTER || | |
| 699 Elements.isOperatorName(memberName.text) || | |
| 700 identical(memberName.text, '??')); | |
| 701 } | |
| 702 | |
| 703 // TODO(johnniwinther): Extract caching. | |
| 704 static Map<int, List<Selector>> canonicalizedValues = | |
| 705 new Map<int, List<Selector>>(); | |
| 706 | |
| 707 factory Selector(SelectorKind kind, | |
| 708 Name name, | |
| 709 CallStructure callStructure) { | |
| 710 // TODO(johnniwinther): Maybe use equality instead of implicit hashing. | |
| 711 int hashCode = computeHashCode(kind, name, callStructure); | |
| 712 List<Selector> list = canonicalizedValues.putIfAbsent(hashCode, | |
| 713 () => <Selector>[]); | |
| 714 for (int i = 0; i < list.length; i++) { | |
| 715 Selector existing = list[i]; | |
| 716 if (existing.match(kind, name, callStructure)) { | |
| 717 assert(existing.hashCode == hashCode); | |
| 718 return existing; | |
| 719 } | |
| 720 } | |
| 721 Selector result = new Selector.internal( | |
| 722 kind, name, callStructure, hashCode); | |
| 723 list.add(result); | |
| 724 return result; | |
| 725 } | |
| 726 | |
| 727 factory Selector.fromElement(Element element) { | |
| 728 Name name = new Name(element.name, element.library); | |
| 729 if (element.isFunction) { | |
| 730 if (name == INDEX_NAME) { | |
| 731 return new Selector.index(); | |
| 732 } else if (name == INDEX_SET_NAME) { | |
| 733 return new Selector.indexSet(); | |
| 734 } | |
| 735 FunctionSignature signature = | |
| 736 element.asFunctionElement().functionSignature; | |
| 737 int arity = signature.parameterCount; | |
| 738 List<String> namedArguments = null; | |
| 739 if (signature.optionalParametersAreNamed) { | |
| 740 namedArguments = | |
| 741 signature.orderedOptionalParameters.map((e) => e.name).toList(); | |
| 742 } | |
| 743 if (element.isOperator) { | |
| 744 // Operators cannot have named arguments, however, that doesn't prevent | |
| 745 // a user from declaring such an operator. | |
| 746 return new Selector( | |
| 747 SelectorKind.OPERATOR, | |
| 748 name, | |
| 749 new CallStructure(arity, namedArguments)); | |
| 750 } else { | |
| 751 return new Selector.call( | |
| 752 name, new CallStructure(arity, namedArguments)); | |
| 753 } | |
| 754 } else if (element.isSetter) { | |
| 755 return new Selector.setter(name); | |
| 756 } else if (element.isGetter) { | |
| 757 return new Selector.getter(name); | |
| 758 } else if (element.isField) { | |
| 759 return new Selector.getter(name); | |
| 760 } else if (element.isConstructor) { | |
| 761 return new Selector.callConstructor(name); | |
| 762 } else { | |
| 763 throw new SpannableAssertionFailure( | |
| 764 element, "Can't get selector from $element"); | |
| 765 } | |
| 766 } | |
| 767 | |
| 768 factory Selector.getter(Name name) | |
| 769 => new Selector(SelectorKind.GETTER, | |
| 770 name.getter, | |
| 771 CallStructure.NO_ARGS); | |
| 772 | |
| 773 factory Selector.setter(Name name) | |
| 774 => new Selector(SelectorKind.SETTER, | |
| 775 name.setter, | |
| 776 CallStructure.ONE_ARG); | |
| 777 | |
| 778 factory Selector.unaryOperator(String name) => new Selector( | |
| 779 SelectorKind.OPERATOR, | |
| 780 new PublicName(Elements.constructOperatorName(name, true)), | |
| 781 CallStructure.NO_ARGS); | |
| 782 | |
| 783 factory Selector.binaryOperator(String name) => new Selector( | |
| 784 SelectorKind.OPERATOR, | |
| 785 new PublicName(Elements.constructOperatorName(name, false)), | |
| 786 CallStructure.ONE_ARG); | |
| 787 | |
| 788 factory Selector.index() | |
| 789 => new Selector(SelectorKind.INDEX, INDEX_NAME, | |
| 790 CallStructure.ONE_ARG); | |
| 791 | |
| 792 factory Selector.indexSet() | |
| 793 => new Selector(SelectorKind.INDEX, INDEX_SET_NAME, | |
| 794 CallStructure.TWO_ARGS); | |
| 795 | |
| 796 factory Selector.call(Name name, CallStructure callStructure) | |
| 797 => new Selector(SelectorKind.CALL, name, callStructure); | |
| 798 | |
| 799 factory Selector.callClosure(int arity, [List<String> namedArguments]) | |
| 800 => new Selector(SelectorKind.CALL, CALL_NAME, | |
| 801 new CallStructure(arity, namedArguments)); | |
| 802 | |
| 803 factory Selector.callClosureFrom(Selector selector) | |
| 804 => new Selector(SelectorKind.CALL, CALL_NAME, selector.callStructure); | |
| 805 | |
| 806 factory Selector.callConstructor(Name name, | |
| 807 [int arity = 0, | |
| 808 List<String> namedArguments]) | |
| 809 => new Selector(SelectorKind.CALL, name, | |
| 810 new CallStructure(arity, namedArguments)); | |
| 811 | |
| 812 factory Selector.callDefaultConstructor() | |
| 813 => new Selector( | |
| 814 SelectorKind.CALL, | |
| 815 const PublicName(''), | |
| 816 CallStructure.NO_ARGS); | |
| 817 | |
| 818 bool get isGetter => kind == SelectorKind.GETTER; | |
| 819 bool get isSetter => kind == SelectorKind.SETTER; | |
| 820 bool get isCall => kind == SelectorKind.CALL; | |
| 821 bool get isClosureCall => isCall && memberName == CALL_NAME; | |
| 822 | |
| 823 bool get isIndex => kind == SelectorKind.INDEX && argumentCount == 1; | |
| 824 bool get isIndexSet => kind == SelectorKind.INDEX && argumentCount == 2; | |
| 825 | |
| 826 bool get isOperator => kind == SelectorKind.OPERATOR; | |
| 827 bool get isUnaryOperator => isOperator && argumentCount == 0; | |
| 828 | |
| 829 /** Check whether this is a call to 'assert'. */ | |
| 830 bool get isAssert => isCall && identical(name, "assert"); | |
| 831 | |
| 832 /** | |
| 833 * The member name for invocation mirrors created from this selector. | |
| 834 */ | |
| 835 String get invocationMirrorMemberName => | |
| 836 isSetter ? '$name=' : name; | |
| 837 | |
| 838 int get invocationMirrorKind { | |
| 839 const int METHOD = 0; | |
| 840 const int GETTER = 1; | |
| 841 const int SETTER = 2; | |
| 842 int kind = METHOD; | |
| 843 if (isGetter) { | |
| 844 kind = GETTER; | |
| 845 } else if (isSetter) { | |
| 846 kind = SETTER; | |
| 847 } | |
| 848 return kind; | |
| 849 } | |
| 850 | |
| 851 bool appliesUnnamed(Element element, World world) { | |
| 852 assert(sameNameHack(element, world)); | |
| 853 return appliesUntyped(element, world); | |
| 854 } | |
| 855 | |
| 856 bool appliesUntyped(Element element, World world) { | |
| 857 assert(sameNameHack(element, world)); | |
| 858 if (Elements.isUnresolved(element)) return false; | |
| 859 if (memberName.isPrivate && memberName.library != element.library) { | |
| 860 // TODO(johnniwinther): Maybe this should be | |
| 861 // `memberName != element.memberName`. | |
| 862 return false; | |
| 863 } | |
| 864 if (world.isForeign(element)) return true; | |
| 865 if (element.isSetter) return isSetter; | |
| 866 if (element.isGetter) return isGetter || isCall; | |
| 867 if (element.isField) { | |
| 868 return isSetter | |
| 869 ? !element.isFinal && !element.isConst | |
| 870 : isGetter || isCall; | |
| 871 } | |
| 872 if (isGetter) return true; | |
| 873 if (isSetter) return false; | |
| 874 return signatureApplies(element); | |
| 875 } | |
| 876 | |
| 877 bool signatureApplies(FunctionElement function) { | |
| 878 if (Elements.isUnresolved(function)) return false; | |
| 879 return callStructure.signatureApplies(function.functionSignature); | |
| 880 } | |
| 881 | |
| 882 bool sameNameHack(Element element, World world) { | |
| 883 // TODO(ngeoffray): Remove workaround checks. | |
| 884 return element.isConstructor || | |
| 885 name == element.name || | |
| 886 name == 'assert' && world.isAssertMethod(element); | |
| 887 } | |
| 888 | |
| 889 bool applies(Element element, World world) { | |
| 890 if (!sameNameHack(element, world)) return false; | |
| 891 return appliesUnnamed(element, world); | |
| 892 } | |
| 893 | |
| 894 bool match(SelectorKind kind, | |
| 895 Name memberName, | |
| 896 CallStructure callStructure) { | |
| 897 return this.kind == kind | |
| 898 && this.memberName == memberName | |
| 899 && this.callStructure.match(callStructure); | |
| 900 } | |
| 901 | |
| 902 static int computeHashCode(SelectorKind kind, | |
| 903 Name name, | |
| 904 CallStructure callStructure) { | |
| 905 // Add bits from name and kind. | |
| 906 int hash = Hashing.mixHashCodeBits(name.hashCode, kind.hashCode); | |
| 907 // Add bits from the call structure. | |
| 908 return Hashing.mixHashCodeBits(hash, callStructure.hashCode); | |
| 909 } | |
| 910 | |
| 911 String toString() { | |
| 912 return 'Selector($kind, $name, ${callStructure.structureToString()})'; | |
| 913 } | |
| 914 | |
| 915 Selector toCallSelector() => new Selector.callClosureFrom(this); | |
| 916 } | |
| OLD | NEW |