Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1015)

Side by Side Diff: pkg/compiler/lib/src/resolution/members.dart

Issue 1182563003: Handle most qualified sends. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Handle qualified access of ambiguous static members. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 part of resolution; 5 part of resolution;
6 6
7 /** 7 /**
8 * Core implementation of resolution. 8 * Core implementation of resolution.
9 * 9 *
10 * Do not subclass or instantiate this class outside this library 10 * Do not subclass or instantiate this class outside this library
(...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 if (node.isConditional) { 533 if (node.isConditional) {
534 sendIsMemberAccess = oldSendIsMemberAccess; 534 sendIsMemberAccess = oldSendIsMemberAccess;
535 allowedCategory = oldAllowedCategory; 535 allowedCategory = oldAllowedCategory;
536 } 536 }
537 537
538 allowedCategory = oldCategory; 538 allowedCategory = oldCategory;
539 539
540 Element target; 540 Element target;
541 String name = node.selector.asIdentifier().source; 541 String name = node.selector.asIdentifier().source;
542 if (identical(name, 'this')) { 542 if (identical(name, 'this')) {
543 // TODO(ahe): Why is this using GENERIC? 543 error(node.selector, MessageKind.THIS_PROPERTY);
544 error(node.selector, MessageKind.GENERIC,
545 {'text': "expected an identifier"});
546 return const NoneResult(); 544 return const NoneResult();
547 } else if (node.isSuperCall) { 545 } else if (node.isSuperCall) {
548 if (node.isOperator) { 546 if (node.isOperator) {
549 if (isUserDefinableOperator(name)) { 547 if (isUserDefinableOperator(name)) {
550 name = selector.name; 548 name = selector.name;
551 } else { 549 } else {
552 error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, {'name': name}); 550 error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, {'name': name});
553 return const NoneResult(); 551 return const NoneResult();
554 } 552 }
555 } 553 }
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after
950 target = error; 948 target = error;
951 } 949 }
952 // We still need to register the invocation, because we might 950 // We still need to register the invocation, because we might
953 // call [:super.noSuchMethod:] which calls [JSInvocationMirror._invokeOn]. 951 // call [:super.noSuchMethod:] which calls [JSInvocationMirror._invokeOn].
954 registry.registerDynamicInvocation(selector); 952 registry.registerDynamicInvocation(selector);
955 registry.registerSuperNoSuchMethod(); 953 registry.registerSuperNoSuchMethod();
956 } 954 }
957 return computeSuperAccessSemantics(node, target); 955 return computeSuperAccessSemantics(node, target);
958 } 956 }
959 957
960 /// Resolve [node] as subexpression that is _not_ the prefix of a member 958 /// Resolve [node] as a subexpression that is _not_ the prefix of a member
961 /// access. For instance `a` in `a + b`, as opposed to `a` in `a.b`. 959 /// access. For instance `a` in `a + b`, as opposed to `a` in `a.b`.
962 ResolutionResult visitExpression(Node node) { 960 ResolutionResult visitExpression(Node node) {
963 bool oldSendIsMemberAccess = sendIsMemberAccess; 961 bool oldSendIsMemberAccess = sendIsMemberAccess;
964 sendIsMemberAccess = false; 962 sendIsMemberAccess = false;
965 ResolutionResult result = visit(node); 963 ResolutionResult result = visit(node);
966 sendIsMemberAccess = oldSendIsMemberAccess; 964 sendIsMemberAccess = oldSendIsMemberAccess;
967 return result; 965 return result;
968 } 966 }
969 967
968 /// Resolve [node] as a subexpression that _is_ the prefix of a member access.
969 /// For instance `a` in `a.b`, as opposed to `a` in `a + b`.
970 ResolutionResult visitExpressionPrefix(Node node) {
971 int oldAllowedCategory = allowedCategory;
972 bool oldSendIsMemberAccess = sendIsMemberAccess;
973 allowedCategory |= ElementCategory.PREFIX | ElementCategory.SUPER;
974 sendIsMemberAccess = true;
975 ResolutionResult result = visit(node);
976 sendIsMemberAccess = oldSendIsMemberAccess;
977 allowedCategory = oldAllowedCategory;
978 return result;
979 }
980
981 /// Resolved [node] as a subexpression that is the prefix of a conditional
982 /// access. For instance `a` in `a?.b`.
983 // TODO(johnniwinther): Is this equivalent to [visitExpression]?
984 ResolutionResult visitConditionalPrefix(Node node) {
985 // Conditional sends like `e?.foo` treat the receiver as an expression. So
986 // `C?.foo` needs to be treated like `(C).foo`, not like C.foo. Prefixes and
987 // super are not allowed on their own in that context.
988 int oldAllowedCategory = allowedCategory;
989 bool oldSendIsMemberAccess = sendIsMemberAccess;
990 sendIsMemberAccess = false;
991 allowedCategory =
992 ElementCategory.VARIABLE |
993 ElementCategory.FUNCTION |
994 ElementCategory.IMPLIES_TYPE;
995 ResolutionResult result = visit(node);
996 sendIsMemberAccess = oldSendIsMemberAccess;
997 allowedCategory = oldAllowedCategory;
998 return result;
999 }
1000
970 /// Handle a type test expression, like `a is T` and `a is! T`. 1001 /// Handle a type test expression, like `a is T` and `a is! T`.
971 ResolutionResult handleIs(Send node) { 1002 ResolutionResult handleIs(Send node) {
972 Node expression = node.receiver; 1003 Node expression = node.receiver;
973 visitExpression(expression); 1004 visitExpression(expression);
974 1005
975 // TODO(johnniwinther): Use seen type tests to avoid registration of 1006 // TODO(johnniwinther): Use seen type tests to avoid registration of
976 // mutation/access to unpromoted variables. 1007 // mutation/access to unpromoted variables.
977 1008
978 Send notTypeNode = node.arguments.head.asSend(); 1009 Send notTypeNode = node.arguments.head.asSend();
979 DartType type; 1010 DartType type;
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after
1382 sendStructure = const InvalidAssertStructure(); 1413 sendStructure = const InvalidAssertStructure();
1383 } 1414 }
1384 registry.registerAssert(node); 1415 registry.registerAssert(node);
1385 registry.registerSendStructure(node, sendStructure); 1416 registry.registerSendStructure(node, sendStructure);
1386 return const AssertResult(); 1417 return const AssertResult();
1387 } 1418 }
1388 1419
1389 /// Handle access of a property of [name] on `this`, like `this.name` and 1420 /// Handle access of a property of [name] on `this`, like `this.name` and
1390 /// `this.name()`, or `name` and `name()` in instance context. 1421 /// `this.name()`, or `name` and `name()` in instance context.
1391 ResolutionResult handleThisPropertyAccess(Send node, Name name) { 1422 ResolutionResult handleThisPropertyAccess(Send node, Name name) {
1392 AccessSemantics accessSemantics = new AccessSemantics.thisProperty(); 1423 AccessSemantics semantics = new AccessSemantics.thisProperty();
1393 SendStructure sendStructure; 1424 return handleDynamicAccessSemantics(node, name, semantics);
1394 Selector selector;
1395 if (node.isCall) {
1396 CallStructure callStructure = resolveArguments(node.argumentsNode);
1397 selector = new Selector(SelectorKind.CALL, name, callStructure);
1398 registry.registerDynamicInvocation(selector);
1399 sendStructure = new InvokeStructure(accessSemantics, selector);
1400 } else {
1401 assert(invariant(node, node.isPropertyAccess));
1402 selector = new Selector(
1403 SelectorKind.GETTER, name, CallStructure.NO_ARGS);
1404 registry.registerDynamicGetter(selector);
1405 sendStructure = new GetStructure(accessSemantics, selector);
1406 }
1407 registry.registerSendStructure(node, sendStructure);
1408 // TODO(johnniwinther): Remove this when all information goes through
1409 // the [SendStructure].
1410 registry.setSelector(node, selector);
1411 return const NoneResult();
1412 } 1425 }
1413 1426
1414 /// Handle access on `this`, like `this()` and `this` when it is parsed as a 1427 /// Handle access on `this`, like `this()` and `this` when it is parsed as a
1415 /// [Send] node. 1428 /// [Send] node.
1416 ResolutionResult handleThisAccess(Send node) { 1429 ResolutionResult handleThisAccess(Send node) {
1417 AccessSemantics accessSemantics = new AccessSemantics.thisAccess(); 1430 AccessSemantics accessSemantics = new AccessSemantics.thisAccess();
1418 if (node.isCall) { 1431 if (node.isCall) {
1419 CallStructure callStructure = resolveArguments(node.argumentsNode); 1432 CallStructure callStructure = resolveArguments(node.argumentsNode);
1420 Selector selector = callStructure.callSelector; 1433 Selector selector = callStructure.callSelector;
1421 // TODO(johnniwinther): Handle invalid this access as an 1434 // TODO(johnniwinther): Handle invalid this access as an
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
1569 case BinaryOperatorKind.LT: 1582 case BinaryOperatorKind.LT:
1570 case BinaryOperatorKind.AND: 1583 case BinaryOperatorKind.AND:
1571 case BinaryOperatorKind.OR: 1584 case BinaryOperatorKind.OR:
1572 case BinaryOperatorKind.XOR: 1585 case BinaryOperatorKind.XOR:
1573 return handleUserDefinableBinary(node, operator); 1586 return handleUserDefinableBinary(node, operator);
1574 } 1587 }
1575 } 1588 }
1576 } 1589 }
1577 } 1590 }
1578 1591
1592 /// Handle qualified access to an unresolved static class member, like `a.b`
1593 /// or `a.b()` where `a` is a class and `b` is unresolved.
1594 ResolutionResult handleUnresolvedStaticMemberAccess(
1595 Send node, Name name, ClassElement receiverClass) {
1596 // TODO(johnniwinther): Share code with [handleStaticInstanceMemberAccess]
1597 // and [handlePrivateStaticMemberAccess].
1598 registry.registerThrowNoSuchMethod();
1599 // TODO(johnniwinther): Produce a different error if [name] is resolves to
1600 // a constructor.
1601
1602 // TODO(johnniwinther): With the simplified [TreeElements] invariant,
1603 // try to resolve injected elements if [currentClass] is in the patch
1604 // library of [receiverClass].
1605
1606 // TODO(karlklose): this should be reported by the caller of
1607 // [resolveSend] to select better warning messages for getters and
1608 // setters.
1609 ErroneousElement error = reportAndCreateErroneousElement(
1610 node, name.text, MessageKind.MEMBER_NOT_FOUND,
1611 {'className': receiverClass.name, 'memberName': name.text});
1612 // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static
1613 // member access.
1614 return handleErroneousAccess(
1615 node, name, error, new StaticAccess.unresolved(error));
1616 }
1617
1618 /// Handle qualified access of an instance member, like `a.b` or `a.b()` where
1619 /// `a` is a class and `b` is a non-static member.
1620 ResolutionResult handleStaticInstanceMemberAccess(
1621 Send node, Name name, ClassElement receiverClass, Element member) {
1622
1623 registry.registerThrowNoSuchMethod();
1624 // TODO(johnniwinther): With the simplified [TreeElements] invariant,
1625 // try to resolve injected elements if [currentClass] is in the patch
1626 // library of [receiverClass].
1627
1628 // TODO(karlklose): this should be reported by the caller of
1629 // [resolveSend] to select better warning messages for getters and
1630 // setters.
1631 ErroneousElement error = reportAndCreateErroneousElement(
1632 node, name.text, MessageKind.MEMBER_NOT_STATIC,
1633 {'className': receiverClass.name, 'memberName': name});
1634
1635 // TODO(johnniwinther): Add an [AccessSemantics] for statically accessed
1636 // instance members.
1637 return handleErroneousAccess(
1638 node, name, error, new StaticAccess.unresolved(error));
1639 }
1640
1641 /// Handle qualified access of an inaccessible private static class member,
1642 /// like `a._b` or `a.b()` where `a` is class, `_b` is static member of `a`
1643 /// but `a` is not defined in the current library.
1644 ResolutionResult handlePrivateStaticMemberAccess(
1645 Send node, Name name, ClassElement receiverClass, Element member) {
1646 registry.registerThrowNoSuchMethod();
1647 ErroneousElement error = reportAndCreateErroneousElement(
1648 node, name.text, MessageKind.PRIVATE_ACCESS,
1649 {'libraryName': member.library.getLibraryOrScriptName(),
1650 'name': name});
1651 // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static
1652 // member access.
1653 return handleErroneousAccess(
1654 node, name, error, new StaticAccess.unresolved(error));
1655 }
1656
1657 /// Handle qualified access to a static member, like `a.b` or `a.b()` where
1658 /// `a` is a class and `b` is a static member of `a`.
1659 ResolutionResult handleStaticMemberAccess(
1660 Send node, Name memberName, ClassElement receiverClass) {
1661 String name = memberName.text;
1662 receiverClass.ensureResolved(compiler);
1663 if (node.isOperator) {
1664 // When the resolved receiver is a class, we can have two cases:
1665 // 1) a static send: C.foo, or
1666 // 2) an operator send, where the receiver is a class literal: 'C + 1'.
1667 // The following code that looks up the selector on the resolved
1668 // receiver will treat the second as the invocation of a static operator
1669 // if the resolved receiver is not null.
1670 return const NoneResult();
1671 }
1672 MembersCreator.computeClassMembersByName(
1673 compiler, receiverClass.declaration, name);
1674 Element member = receiverClass.lookupLocalMember(name);
1675 if (member == null) {
1676 return handleUnresolvedStaticMemberAccess(
1677 node, memberName, receiverClass);
1678 } else if (member.isAmbiguous) {
1679 return handleAmbiguousSend(node, memberName, member);
1680 } else if (member.isInstanceMember) {
1681 return handleStaticInstanceMemberAccess(
1682 node, memberName, receiverClass, member);
1683 } else if (memberName.isPrivate && memberName.library != member.library) {
1684 return handlePrivateStaticMemberAccess(
1685 node, memberName, receiverClass, member);
1686 } else {
1687 return handleStaticOrTopLevelAccess(node, memberName, member);
1688 }
1689 }
1690
1691 /// Handle qualified [Send] where the receiver resolves to an [Element], like
1692 /// `a.b` where `a` is a local, field, class, or prefix, etc.
1693 ResolutionResult handleResolvedQualifiedSend(
1694 Send node, Name name, Element element) {
1695 if (element.isPrefix) {
1696 return oldVisitSend(node);
1697 } else if (element.isClass) {
1698 return handleStaticMemberAccess(node, name, element);
1699 }
1700 return oldVisitSend(node);
1701 }
1702
1703 /// Handle dynamic access of [semantics].
1704 ResolutionResult handleDynamicAccessSemantics(
1705 Send node, Name name, AccessSemantics semantics) {
1706 SendStructure sendStructure;
1707 Selector selector;
1708 if (node.isCall) {
1709 CallStructure callStructure = resolveArguments(node.argumentsNode);
1710 selector = new Selector(SelectorKind.CALL, name, callStructure);
1711 registry.registerDynamicInvocation(selector);
1712 sendStructure = new InvokeStructure(semantics, selector);
1713 } else {
1714 assert(invariant(node, node.isPropertyAccess));
1715 selector = new Selector(
1716 SelectorKind.GETTER, name, CallStructure.NO_ARGS);
1717 registry.registerDynamicGetter(selector);
1718 sendStructure = new GetStructure(semantics, selector);
1719 }
1720 registry.registerSendStructure(node, sendStructure);
1721 // TODO(johnniwinther): Remove this when all information goes through
1722 // the [SendStructure].
1723 registry.setSelector(node, selector);
1724 return const NoneResult();
1725 }
1726
1727 /// Handle dynamic property access, like `a.b` or `a.b()` where `a` is not a
1728 /// prefix or class.
1729 ResolutionResult handleDynamicPropertyAccess(Send node, Name name) {
1730 AccessSemantics semantics =
1731 new DynamicAccess.dynamicProperty(node.receiver);
1732 return handleDynamicAccessSemantics(node, name, semantics);
1733 }
1734
1735 /// Handle conditional access, like `a?.b` or `a?.b()`.
1736 ResolutionResult handleConditionalAccess(Send node, Name name) {
1737 Node receiver = node.receiver;
1738 visitConditionalPrefix(receiver);
1739 AccessSemantics semantics =
1740 new DynamicAccess.ifNotNullProperty(receiver);
1741 return handleDynamicAccessSemantics(node, name, semantics);
1742 }
1743
1744 /// Handle `this` as a qualified property, like `a.this`.
1745 ResolutionResult handleQualifiedThisAccess(Send node, Name name) {
1746 ErroneousElement error = reportAndCreateErroneousElement(
1747 node.selector,
1748 name.text,
1749 MessageKind.THIS_PROPERTY, {},
1750 isError: true);
1751 // TODO(johnniwinther): Support `this` as property as an [AccessSemantics].
1752 AccessSemantics accessSemantics = new StaticAccess.unresolved(error);
1753 return handleErroneousAccess(node, name, error, accessSemantics);
1754 }
1755
1579 /// Handle a qualified [Send], that is where the receiver is non-null, like 1756 /// Handle a qualified [Send], that is where the receiver is non-null, like
1580 /// `a.b`, `a.b()`, `this.a()` and `super.a()`. 1757 /// `a.b`, `a.b()`, `this.a()` and `super.a()`.
1581 ResolutionResult handleQualifiedSend(Send node) { 1758 ResolutionResult handleQualifiedSend(Send node) {
1582 Identifier selector = node.selector.asIdentifier(); 1759 Identifier selector = node.selector.asIdentifier();
1583 Name name = new Name(selector.source, enclosingElement.library); 1760 String text = selector.source;
1584 if (node.isSuperCall) { 1761 Name name = new Name(text, enclosingElement.library);
1762 if (text == 'this') {
1763 return handleQualifiedThisAccess(node, name);
1764 } else if (node.isSuperCall) {
1585 return handleSuperPropertyAccess(node, name); 1765 return handleSuperPropertyAccess(node, name);
1586 } else if (node.receiver.isThis()) { 1766 } else if (node.receiver.isThis()) {
1587 if (checkThisAccess(node)) { 1767 if (checkThisAccess(node)) {
1588 return handleThisPropertyAccess(node, name); 1768 return handleThisPropertyAccess(node, name);
1589 } 1769 }
1590 // TODO(johnniwinther): Handle invalid this access as an 1770 // TODO(johnniwinther): Handle invalid this access as an
1591 // [AccessSemantics]. 1771 // [AccessSemantics].
1592 return const NoneResult(); 1772 return const NoneResult();
1773 } else if (node.isConditional) {
1774 return handleConditionalAccess(node, name);
1593 } 1775 }
1594 // TODO(johnniwinther): Handle remaining qualified sends. 1776 ResolutionResult result = visitExpressionPrefix(node.receiver);
1595 return oldVisitSend(node); 1777 if (result.element != null) {
1778 return handleResolvedQualifiedSend(node, name, result.element);
1779 } else {
1780 return handleDynamicPropertyAccess(node, name);
1781 }
1596 } 1782 }
1597 1783
1598 /// Handle access unresolved access to [name] in a non-instance context. 1784 /// Handle access unresolved access to [name] in a non-instance context.
1599 ResolutionResult handleUnresolvedAccess( 1785 ResolutionResult handleUnresolvedAccess(
1600 Send node, Name name, Element element) { 1786 Send node, Name name, Element element) {
1601 // TODO(johnniwinther): Support unresolved top level access as an 1787 // TODO(johnniwinther): Support unresolved top level access as an
1602 // [AccessSemantics]. 1788 // [AccessSemantics].
1603 AccessSemantics accessSemantics = new StaticAccess.unresolved(element); 1789 AccessSemantics accessSemantics = new StaticAccess.unresolved(element);
1604 return handleErroneousAccess(node, name, element, accessSemantics); 1790 return handleErroneousAccess(node, name, element, accessSemantics);
1605 } 1791 }
(...skipping 851 matching lines...) Expand 10 before | Expand all | Expand 10 after
2457 ResolutionResult visitWhile(While node) { 2643 ResolutionResult visitWhile(While node) {
2458 visit(node.condition); 2644 visit(node.condition);
2459 visitLoopBodyIn(node, node.body, new BlockScope(scope)); 2645 visitLoopBodyIn(node, node.body, new BlockScope(scope));
2460 return const NoneResult(); 2646 return const NoneResult();
2461 } 2647 }
2462 2648
2463 ResolutionResult visitParenthesizedExpression(ParenthesizedExpression node) { 2649 ResolutionResult visitParenthesizedExpression(ParenthesizedExpression node) {
2464 bool oldSendIsMemberAccess = sendIsMemberAccess; 2650 bool oldSendIsMemberAccess = sendIsMemberAccess;
2465 sendIsMemberAccess = false; 2651 sendIsMemberAccess = false;
2466 var oldCategory = allowedCategory; 2652 var oldCategory = allowedCategory;
2467 allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION 2653 allowedCategory =
2468 | ElementCategory.IMPLIES_TYPE; 2654 ElementCategory.VARIABLE |
2655 ElementCategory.FUNCTION |
2656 ElementCategory.IMPLIES_TYPE;
2469 ResolutionResult result = visit(node.expression); 2657 ResolutionResult result = visit(node.expression);
2470 allowedCategory = oldCategory; 2658 allowedCategory = oldCategory;
2471 sendIsMemberAccess = oldSendIsMemberAccess; 2659 sendIsMemberAccess = oldSendIsMemberAccess;
2472 if (result.kind == ResultKind.CONSTANT) { 2660 if (result.kind == ResultKind.CONSTANT) {
2473 return result; 2661 return result;
2474 } 2662 }
2475 return const NoneResult(); 2663 return const NoneResult();
2476 } 2664 }
2477 2665
2478 ResolutionResult visitNewExpression(NewExpression node) { 2666 ResolutionResult visitNewExpression(NewExpression node) {
(...skipping 794 matching lines...) Expand 10 before | Expand all | Expand 10 after
3273 } 3461 }
3274 return const NoneResult(); 3462 return const NoneResult();
3275 } 3463 }
3276 } 3464 }
3277 3465
3278 /// Looks up [name] in [scope] and unwraps the result. 3466 /// Looks up [name] in [scope] and unwraps the result.
3279 Element lookupInScope(Compiler compiler, Node node, 3467 Element lookupInScope(Compiler compiler, Node node,
3280 Scope scope, String name) { 3468 Scope scope, String name) {
3281 return Elements.unwrap(scope.lookup(name), compiler, node); 3469 return Elements.unwrap(scope.lookup(name), compiler, node);
3282 } 3470 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/resolution/access_semantics.dart ('k') | pkg/compiler/lib/src/resolution/resolution_common.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698