| 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 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import '../common/names.dart' show | 9 import '../common/names.dart' show |
| 10 Identifiers, | 10 Identifiers, |
| 11 Names, | 11 Names, |
| 12 Selectors; | 12 Selectors; |
| 13 import '../compiler.dart' show | 13 import '../compiler.dart' show |
| 14 Compiler; | 14 Compiler; |
| 15 import '../diagnostics/invariant.dart' show | 15 import '../diagnostics/invariant.dart' show |
| 16 invariant; | 16 invariant; |
| 17 import '../diagnostics/spannable.dart' show | 17 import '../diagnostics/spannable.dart' show |
| 18 SpannableAssertionFailure; | 18 SpannableAssertionFailure; |
| 19 import '../elements/elements.dart'; | 19 import '../elements/elements.dart'; |
| 20 import '../dart_types.dart'; | 20 import '../dart_types.dart'; |
| 21 import '../tree/tree.dart'; | 21 import '../tree/tree.dart'; |
| 22 import '../types/types.dart'; | 22 import '../types/types.dart'; |
| 23 import '../util/util.dart'; | 23 import '../util/util.dart'; |
| 24 import '../world.dart' show | 24 import '../world.dart' show |
| 25 ClassWorld, | 25 ClassWorld, |
| 26 World; | 26 World; |
| 27 | 27 |
| 28 part 'call_structure.dart'; |
| 28 part 'function_set.dart'; | 29 part 'function_set.dart'; |
| 30 part 'selector.dart'; |
| 29 part 'side_effects.dart'; | 31 part 'side_effects.dart'; |
| 30 | 32 |
| 31 class UniverseSelector { | 33 class UniverseSelector { |
| 32 final Selector selector; | 34 final Selector selector; |
| 33 final ReceiverMask mask; | 35 final ReceiverMask mask; |
| 34 | 36 |
| 35 UniverseSelector(this.selector, this.mask); | 37 UniverseSelector(this.selector, this.mask); |
| 36 | 38 |
| 37 bool appliesUnnamed(Element element, ClassWorld world) { | 39 bool appliesUnnamed(Element element, ClassWorld world) { |
| 38 return selector.appliesUnnamed(element, world) && | 40 return selector.appliesUnnamed(element, world) && |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 // TODO(ahe): Replace this method with something that is O(1), for example, | 366 // TODO(ahe): Replace this method with something that is O(1), for example, |
| 365 // by using a map. | 367 // by using a map. |
| 366 List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) { | 368 List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) { |
| 367 // Return new list to guard against concurrent modifications. | 369 // Return new list to guard against concurrent modifications. |
| 368 return new List<LocalFunctionElement>.from( | 370 return new List<LocalFunctionElement>.from( |
| 369 allClosures.where((LocalFunctionElement closure) { | 371 allClosures.where((LocalFunctionElement closure) { |
| 370 return closure.executableContext == element; | 372 return closure.executableContext == element; |
| 371 })); | 373 })); |
| 372 } | 374 } |
| 373 } | 375 } |
| 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 | |
| 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 { | |
| 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 |