| 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 | 6 |
| 375 class SelectorKind { | 7 class SelectorKind { |
| 376 final String name; | 8 final String name; |
| 377 final int hashCode; | 9 final int hashCode; |
| 378 const SelectorKind(this.name, this.hashCode); | 10 const SelectorKind(this.name, this.hashCode); |
| 379 | 11 |
| 380 static const SelectorKind GETTER = const SelectorKind('getter', 0); | 12 static const SelectorKind GETTER = const SelectorKind('getter', 0); |
| 381 static const SelectorKind SETTER = const SelectorKind('setter', 1); | 13 static const SelectorKind SETTER = const SelectorKind('setter', 1); |
| 382 static const SelectorKind CALL = const SelectorKind('call', 2); | 14 static const SelectorKind CALL = const SelectorKind('call', 2); |
| 383 static const SelectorKind OPERATOR = const SelectorKind('operator', 3); | 15 static const SelectorKind OPERATOR = const SelectorKind('operator', 3); |
| 384 static const SelectorKind INDEX = const SelectorKind('index', 4); | 16 static const SelectorKind INDEX = const SelectorKind('index', 4); |
| 385 | 17 |
| 386 String toString() => name; | 18 String toString() => name; |
| 387 } | 19 } |
| 388 | 20 |
| 389 /// The structure of the arguments at a call-site. | |
| 390 // TODO(johnniwinther): Should these be cached? | |
| 391 // TODO(johnniwinther): Should isGetter/isSetter be part of the call structure | |
| 392 // instead of the selector? | |
| 393 class CallStructure { | |
| 394 static const CallStructure NO_ARGS = const CallStructure.unnamed(0); | |
| 395 static const CallStructure ONE_ARG = const CallStructure.unnamed(1); | |
| 396 static const CallStructure TWO_ARGS = const CallStructure.unnamed(2); | |
| 397 | |
| 398 /// The numbers of arguments of the call. Includes named arguments. | |
| 399 final int argumentCount; | |
| 400 | |
| 401 /// The number of named arguments of the call. | |
| 402 int get namedArgumentCount => 0; | |
| 403 | |
| 404 /// The number of positional argument of the call. | |
| 405 int get positionalArgumentCount => argumentCount; | |
| 406 | |
| 407 const CallStructure.unnamed(this.argumentCount); | |
| 408 | |
| 409 factory CallStructure(int argumentCount, [List<String> namedArguments]) { | |
| 410 if (namedArguments == null || namedArguments.isEmpty) { | |
| 411 return new CallStructure.unnamed(argumentCount); | |
| 412 } | |
| 413 return new NamedCallStructure(argumentCount, namedArguments); | |
| 414 } | |
| 415 | |
| 416 /// `true` if this call has named arguments. | |
| 417 bool get isNamed => false; | |
| 418 | |
| 419 /// `true` if this call has no named arguments. | |
| 420 bool get isUnnamed => true; | |
| 421 | |
| 422 /// The names of the named arguments in call-site order. | |
| 423 List<String> get namedArguments => const <String>[]; | |
| 424 | |
| 425 /// The names of the named arguments in canonicalized order. | |
| 426 List<String> getOrderedNamedArguments() => const <String>[]; | |
| 427 | |
| 428 /// A description of the argument structure. | |
| 429 String structureToString() => 'arity=$argumentCount'; | |
| 430 | |
| 431 String toString() => 'CallStructure(${structureToString()})'; | |
| 432 | |
| 433 Selector get callSelector { | |
| 434 return new Selector(SelectorKind.CALL, Selector.CALL_NAME, this); | |
| 435 } | |
| 436 | |
| 437 bool match(CallStructure other) { | |
| 438 if (identical(this, other)) return true; | |
| 439 return this.argumentCount == other.argumentCount | |
| 440 && this.namedArgumentCount == other.namedArgumentCount | |
| 441 && sameNames(this.namedArguments, other.namedArguments); | |
| 442 } | |
| 443 | |
| 444 // TODO(johnniwinther): Cache hash code? | |
| 445 int get hashCode { | |
| 446 return Hashing.listHash(namedArguments, | |
| 447 Hashing.objectHash(argumentCount, namedArguments.length)); | |
| 448 } | |
| 449 | |
| 450 bool operator ==(other) { | |
| 451 if (other is! CallStructure) return false; | |
| 452 return match(other); | |
| 453 } | |
| 454 | |
| 455 bool signatureApplies(FunctionSignature parameters) { | |
| 456 if (argumentCount > parameters.parameterCount) return false; | |
| 457 int requiredParameterCount = parameters.requiredParameterCount; | |
| 458 int optionalParameterCount = parameters.optionalParameterCount; | |
| 459 if (positionalArgumentCount < requiredParameterCount) return false; | |
| 460 | |
| 461 if (!parameters.optionalParametersAreNamed) { | |
| 462 // We have already checked that the number of arguments are | |
| 463 // not greater than the number of parameters. Therefore the | |
| 464 // number of positional arguments are not greater than the | |
| 465 // number of parameters. | |
| 466 assert(positionalArgumentCount <= parameters.parameterCount); | |
| 467 return namedArguments.isEmpty; | |
| 468 } else { | |
| 469 if (positionalArgumentCount > requiredParameterCount) return false; | |
| 470 assert(positionalArgumentCount == requiredParameterCount); | |
| 471 if (namedArgumentCount > optionalParameterCount) return false; | |
| 472 Set<String> nameSet = new Set<String>(); | |
| 473 parameters.optionalParameters.forEach((Element element) { | |
| 474 nameSet.add(element.name); | |
| 475 }); | |
| 476 for (String name in namedArguments) { | |
| 477 if (!nameSet.contains(name)) return false; | |
| 478 // TODO(5213): By removing from the set we are checking | |
| 479 // that we are not passing the name twice. We should have this | |
| 480 // check in the resolver also. | |
| 481 nameSet.remove(name); | |
| 482 } | |
| 483 return true; | |
| 484 } | |
| 485 } | |
| 486 | |
| 487 /** | |
| 488 * Returns a `List` with the evaluated arguments in the normalized order. | |
| 489 * | |
| 490 * [compileDefaultValue] is a function that returns a compiled constant | |
| 491 * of an optional argument that is not in [compiledArguments]. | |
| 492 * | |
| 493 * Precondition: `this.applies(element, world)`. | |
| 494 * | |
| 495 * Invariant: [element] must be the implementation element. | |
| 496 */ | |
| 497 /*<T>*/ List/*<T>*/ makeArgumentsList( | |
| 498 Link<Node> arguments, | |
| 499 FunctionElement element, | |
| 500 /*T*/ compileArgument(Node argument), | |
| 501 /*T*/ compileDefaultValue(ParameterElement element)) { | |
| 502 assert(invariant(element, element.isImplementation)); | |
| 503 List/*<T>*/ result = new List(); | |
| 504 | |
| 505 FunctionSignature parameters = element.functionSignature; | |
| 506 parameters.forEachRequiredParameter((ParameterElement element) { | |
| 507 result.add(compileArgument(arguments.head)); | |
| 508 arguments = arguments.tail; | |
| 509 }); | |
| 510 | |
| 511 if (!parameters.optionalParametersAreNamed) { | |
| 512 parameters.forEachOptionalParameter((ParameterElement element) { | |
| 513 if (!arguments.isEmpty) { | |
| 514 result.add(compileArgument(arguments.head)); | |
| 515 arguments = arguments.tail; | |
| 516 } else { | |
| 517 result.add(compileDefaultValue(element)); | |
| 518 } | |
| 519 }); | |
| 520 } else { | |
| 521 // Visit named arguments and add them into a temporary list. | |
| 522 List compiledNamedArguments = []; | |
| 523 for (; !arguments.isEmpty; arguments = arguments.tail) { | |
| 524 NamedArgument namedArgument = arguments.head; | |
| 525 compiledNamedArguments.add(compileArgument(namedArgument.expression)); | |
| 526 } | |
| 527 // Iterate over the optional parameters of the signature, and try to | |
| 528 // find them in [compiledNamedArguments]. If found, we use the | |
| 529 // value in the temporary list, otherwise the default value. | |
| 530 parameters.orderedOptionalParameters.forEach((ParameterElement element) { | |
| 531 int foundIndex = namedArguments.indexOf(element.name); | |
| 532 if (foundIndex != -1) { | |
| 533 result.add(compiledNamedArguments[foundIndex]); | |
| 534 } else { | |
| 535 result.add(compileDefaultValue(element)); | |
| 536 } | |
| 537 }); | |
| 538 } | |
| 539 return result; | |
| 540 } | |
| 541 | |
| 542 /** | |
| 543 * Fills [list] with the arguments in the order expected by | |
| 544 * [callee], and where [caller] is a synthesized element | |
| 545 * | |
| 546 * [compileArgument] is a function that returns a compiled version | |
| 547 * of a parameter of [callee]. | |
| 548 * | |
| 549 * [compileConstant] is a function that returns a compiled constant | |
| 550 * of an optional argument that is not in the parameters of [callee]. | |
| 551 * | |
| 552 * Returns [:true:] if the signature of the [caller] matches the | |
| 553 * signature of the [callee], [:false:] otherwise. | |
| 554 */ | |
| 555 static /*<T>*/ bool addForwardingElementArgumentsToList( | |
| 556 ConstructorElement caller, | |
| 557 List/*<T>*/ list, | |
| 558 ConstructorElement callee, | |
| 559 /*T*/ compileArgument(ParameterElement element), | |
| 560 /*T*/ compileConstant(ParameterElement element)) { | |
| 561 assert(invariant(caller, !callee.isErroneous, | |
| 562 message: "Cannot compute arguments to erroneous constructor: " | |
| 563 "$caller calling $callee.")); | |
| 564 | |
| 565 FunctionSignature signature = caller.functionSignature; | |
| 566 Map<Node, ParameterElement> mapping = <Node, ParameterElement>{}; | |
| 567 | |
| 568 // TODO(ngeoffray): This is a hack that fakes up AST nodes, so | |
| 569 // that we can call [addArgumentsToList]. | |
| 570 Link<Node> computeCallNodesFromParameters() { | |
| 571 LinkBuilder<Node> builder = new LinkBuilder<Node>(); | |
| 572 signature.forEachRequiredParameter((ParameterElement element) { | |
| 573 Node node = element.node; | |
| 574 mapping[node] = element; | |
| 575 builder.addLast(node); | |
| 576 }); | |
| 577 if (signature.optionalParametersAreNamed) { | |
| 578 signature.forEachOptionalParameter((ParameterElement element) { | |
| 579 mapping[element.initializer] = element; | |
| 580 builder.addLast(new NamedArgument(null, null, element.initializer)); | |
| 581 }); | |
| 582 } else { | |
| 583 signature.forEachOptionalParameter((ParameterElement element) { | |
| 584 Node node = element.node; | |
| 585 mapping[node] = element; | |
| 586 builder.addLast(node); | |
| 587 }); | |
| 588 } | |
| 589 return builder.toLink(); | |
| 590 } | |
| 591 | |
| 592 /*T*/ internalCompileArgument(Node node) { | |
| 593 return compileArgument(mapping[node]); | |
| 594 } | |
| 595 | |
| 596 Link<Node> nodes = computeCallNodesFromParameters(); | |
| 597 | |
| 598 // Synthesize a structure for the call. | |
| 599 // TODO(ngeoffray): Should the resolver do it instead? | |
| 600 List<String> namedParameters; | |
| 601 if (signature.optionalParametersAreNamed) { | |
| 602 namedParameters = | |
| 603 signature.optionalParameters.map((e) => e.name).toList(); | |
| 604 } | |
| 605 CallStructure callStructure = | |
| 606 new CallStructure(signature.parameterCount, namedParameters); | |
| 607 if (!callStructure.signatureApplies(signature)) { | |
| 608 return false; | |
| 609 } | |
| 610 list.addAll(callStructure.makeArgumentsList( | |
| 611 nodes, | |
| 612 callee, | |
| 613 internalCompileArgument, | |
| 614 compileConstant)); | |
| 615 | |
| 616 return true; | |
| 617 } | |
| 618 | |
| 619 static bool sameNames(List<String> first, List<String> second) { | |
| 620 for (int i = 0; i < first.length; i++) { | |
| 621 if (first[i] != second[i]) return false; | |
| 622 } | |
| 623 return true; | |
| 624 } | |
| 625 } | |
| 626 | |
| 627 /// | |
| 628 class NamedCallStructure extends CallStructure { | |
| 629 final List<String> namedArguments; | |
| 630 final List<String> _orderedNamedArguments = <String>[]; | |
| 631 | |
| 632 NamedCallStructure(int argumentCount, this.namedArguments) | |
| 633 : super.unnamed(argumentCount) { | |
| 634 assert(namedArguments.isNotEmpty); | |
| 635 } | |
| 636 | |
| 637 @override | |
| 638 bool get isNamed => true; | |
| 639 | |
| 640 @override | |
| 641 bool get isUnnamed => false; | |
| 642 | |
| 643 @override | |
| 644 int get namedArgumentCount => namedArguments.length; | |
| 645 | |
| 646 @override | |
| 647 int get positionalArgumentCount => argumentCount - namedArgumentCount; | |
| 648 | |
| 649 @override | |
| 650 List<String> getOrderedNamedArguments() { | |
| 651 if (!_orderedNamedArguments.isEmpty) return _orderedNamedArguments; | |
| 652 | |
| 653 _orderedNamedArguments.addAll(namedArguments); | |
| 654 _orderedNamedArguments.sort((String first, String second) { | |
| 655 return first.compareTo(second); | |
| 656 }); | |
| 657 return _orderedNamedArguments; | |
| 658 } | |
| 659 | |
| 660 @override | |
| 661 String structureToString() { | |
| 662 return 'arity=$argumentCount, named=[${namedArguments.join(', ')}]'; | |
| 663 } | |
| 664 } | |
| 665 | |
| 666 class Selector { | 21 class Selector { |
| 667 final SelectorKind kind; | 22 final SelectorKind kind; |
| 668 final Name memberName; | 23 final Name memberName; |
| 669 final CallStructure callStructure; | 24 final CallStructure callStructure; |
| 670 | 25 |
| 671 final int hashCode; | 26 final int hashCode; |
| 672 | 27 |
| 673 int get argumentCount => callStructure.argumentCount; | 28 int get argumentCount => callStructure.argumentCount; |
| 674 int get namedArgumentCount => callStructure.namedArgumentCount; | 29 int get namedArgumentCount => callStructure.namedArgumentCount; |
| 675 int get positionalArgumentCount => callStructure.positionalArgumentCount; | 30 int get positionalArgumentCount => callStructure.positionalArgumentCount; |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 907 // Add bits from the call structure. | 262 // Add bits from the call structure. |
| 908 return Hashing.mixHashCodeBits(hash, callStructure.hashCode); | 263 return Hashing.mixHashCodeBits(hash, callStructure.hashCode); |
| 909 } | 264 } |
| 910 | 265 |
| 911 String toString() { | 266 String toString() { |
| 912 return 'Selector($kind, $name, ${callStructure.structureToString()})'; | 267 return 'Selector($kind, $name, ${callStructure.structureToString()})'; |
| 913 } | 268 } |
| 914 | 269 |
| 915 Selector toCallSelector() => new Selector.callClosureFrom(this); | 270 Selector toCallSelector() => new Selector.callClosureFrom(this); |
| 916 } | 271 } |
| OLD | NEW |