| 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 part of resolution; | 5 part of resolution; |
| 6 | 6 |
| 7 abstract class TreeElements { | 7 abstract class TreeElements { |
| 8 Element operator[](Node node); | 8 Element operator[](Node node); |
| 9 Selector getSelector(Send send); | 9 Selector getSelector(Send send); |
| 10 DartType getType(Node node); | 10 DartType getType(Node node); |
| 11 bool isParameterChecked(Element element); | 11 bool isParameterChecked(Element element); |
| 12 Set<Node> get superUses; |
| 12 } | 13 } |
| 13 | 14 |
| 14 class TreeElementMapping implements TreeElements { | 15 class TreeElementMapping implements TreeElements { |
| 15 final Element currentElement; | 16 final Element currentElement; |
| 16 final Map<Node, Selector> selectors; | 17 final Map<Node, Selector> selectors = new LinkedHashMap<Node, Selector>(); |
| 17 final Map<Node, DartType> types; | 18 final Map<Node, DartType> types = new LinkedHashMap<Node, DartType>(); |
| 18 final Set<Element> checkedParameters; | 19 final Set<Element> checkedParameters = new Set<Element>(); |
| 20 final Set<Node> superUses = new Set<Node>(); |
| 19 | 21 |
| 20 TreeElementMapping(this.currentElement) | 22 TreeElementMapping(this.currentElement); |
| 21 : selectors = new LinkedHashMap<Node, Selector>(), | |
| 22 types = new LinkedHashMap<Node, DartType>(), | |
| 23 checkedParameters = new Set<Element>(); | |
| 24 | 23 |
| 25 operator []=(Node node, Element element) { | 24 operator []=(Node node, Element element) { |
| 26 assert(invariant(node, () { | 25 assert(invariant(node, () { |
| 27 if (node is FunctionExpression) { | 26 if (node is FunctionExpression) { |
| 28 return !node.modifiers.isExternal(); | 27 return !node.modifiers.isExternal(); |
| 29 } | 28 } |
| 30 return true; | 29 return true; |
| 31 })); | 30 })); |
| 32 // TODO(johnniwinther): Simplify this invariant to use only declarations in | 31 // TODO(johnniwinther): Simplify this invariant to use only declarations in |
| 33 // [TreeElements]. | 32 // [TreeElements]. |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 FunctionElement redirection = | 260 FunctionElement redirection = |
| 262 resolver.resolveInitializers(element, tree); | 261 resolver.resolveInitializers(element, tree); |
| 263 if (redirection != null) { | 262 if (redirection != null) { |
| 264 resolveRedirectingConstructor(resolver, tree, element, redirection); | 263 resolveRedirectingConstructor(resolver, tree, element, redirection); |
| 265 } | 264 } |
| 266 } else if (tree.initializers != null) { | 265 } else if (tree.initializers != null) { |
| 267 error(tree, MessageKind.FUNCTION_WITH_INITIALIZER); | 266 error(tree, MessageKind.FUNCTION_WITH_INITIALIZER); |
| 268 } | 267 } |
| 269 visitBody(visitor, tree.body); | 268 visitBody(visitor, tree.body); |
| 270 | 269 |
| 271 return visitor.mapping; | 270 // Get the resolution tree and check that the resolved |
| 271 // function doesn't use 'super' if it is mixed into another |
| 272 // class. This is the part of the 'super' mixin check that |
| 273 // happens when a function is resolved after the mixin |
| 274 // application has been performed. |
| 275 TreeElements resolutionTree = visitor.mapping; |
| 276 ClassElement enclosingClass = element.getEnclosingClass(); |
| 277 if (enclosingClass != null) { |
| 278 Set<MixinApplicationElement> mixinUses = |
| 279 compiler.world.mixinUses[enclosingClass]; |
| 280 if (mixinUses != null) { |
| 281 ClassElement mixin = enclosingClass; |
| 282 for (MixinApplicationElement mixinApplication in mixinUses) { |
| 283 checkMixinSuperUses(resolutionTree, mixinApplication, mixin); |
| 284 } |
| 285 } |
| 286 } |
| 287 return resolutionTree; |
| 272 }); | 288 }); |
| 273 }); | 289 }); |
| 274 } | 290 } |
| 275 | 291 |
| 276 /// This method should only be used by this library (or tests of | 292 /// This method should only be used by this library (or tests of |
| 277 /// this library). | 293 /// this library). |
| 278 ResolverVisitor visitorFor(Element element) { | 294 ResolverVisitor visitorFor(Element element) { |
| 279 var mapping = new TreeElementMapping(element); | 295 var mapping = new TreeElementMapping(element); |
| 280 return new ResolverVisitor(compiler, element, mapping); | 296 return new ResolverVisitor(compiler, element, mapping); |
| 281 } | 297 } |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 515 ClassElement mixin = mixinApplication.mixin; | 531 ClassElement mixin = mixinApplication.mixin; |
| 516 if (mixin == null) return; | 532 if (mixin == null) return; |
| 517 | 533 |
| 518 // Check that the mixed in class has Object as its superclass. | 534 // Check that the mixed in class has Object as its superclass. |
| 519 if (!mixin.superclass.isObject(compiler)) { | 535 if (!mixin.superclass.isObject(compiler)) { |
| 520 CompilationError error = MessageKind.ILLEGAL_MIXIN_SUPERCLASS.error(); | 536 CompilationError error = MessageKind.ILLEGAL_MIXIN_SUPERCLASS.error(); |
| 521 compiler.reportMessage(compiler.spanFromElement(mixin), | 537 compiler.reportMessage(compiler.spanFromElement(mixin), |
| 522 error, Diagnostic.ERROR); | 538 error, Diagnostic.ERROR); |
| 523 } | 539 } |
| 524 | 540 |
| 525 // Check that the mixed in class doesn't have any constructors. | 541 // Check that the mixed in class doesn't have any constructors and |
| 542 // make sure we aren't mixing in methods that use 'super'. |
| 526 mixin.forEachLocalMember((Element member) { | 543 mixin.forEachLocalMember((Element member) { |
| 527 if (member.isGenerativeConstructor() && !member.isSynthesized) { | 544 if (member.isGenerativeConstructor() && !member.isSynthesized) { |
| 528 CompilationError error = MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR.error(); | 545 CompilationError error = MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR.error(); |
| 529 compiler.reportMessage(compiler.spanFromElement(member), | 546 compiler.reportMessage(compiler.spanFromElement(member), |
| 530 error, Diagnostic.ERROR); | 547 error, Diagnostic.ERROR); |
| 548 } else { |
| 549 // Get the resolution tree and check that the resolved member |
| 550 // doesn't use 'super'. This is the part of the 'super' mixin |
| 551 // check that happens when a function is resolved before the |
| 552 // mixin application has been performed. |
| 553 checkMixinSuperUses( |
| 554 compiler.enqueuer.resolution.resolvedElements[member], |
| 555 mixinApplication, |
| 556 mixin); |
| 531 } | 557 } |
| 532 }); | 558 }); |
| 533 } | 559 } |
| 534 | 560 |
| 561 void checkMixinSuperUses(TreeElements resolutionTree, |
| 562 MixinApplicationElement mixinApplication, |
| 563 ClassElement mixin) { |
| 564 if (resolutionTree == null) return; |
| 565 Set<Node> superUses = resolutionTree.superUses; |
| 566 if (superUses.isEmpty) return; |
| 567 CompilationError error = MessageKind.ILLEGAL_MIXIN_WITH_SUPER.error( |
| 568 [mixin.name]); |
| 569 compiler.reportMessage(compiler.spanFromElement(mixinApplication), |
| 570 error, Diagnostic.ERROR); |
| 571 // Show the user the problematic uses of 'super' in the mixin. |
| 572 for (Node use in superUses) { |
| 573 CompilationError error = MessageKind.ILLEGAL_MIXIN_SUPER_USE.error(); |
| 574 compiler.reportMessage(compiler.spanFromNode(use), |
| 575 error, Diagnostic.INFO); |
| 576 } |
| 577 } |
| 578 |
| 535 void checkClassMembers(ClassElement cls) { | 579 void checkClassMembers(ClassElement cls) { |
| 536 assert(invariant(cls, cls.isDeclaration)); | 580 assert(invariant(cls, cls.isDeclaration)); |
| 537 if (cls.isObject(compiler)) return; | 581 if (cls.isObject(compiler)) return; |
| 538 // TODO(johnniwinther): Should this be done on the implementation element as | 582 // TODO(johnniwinther): Should this be done on the implementation element as |
| 539 // well? | 583 // well? |
| 540 cls.forEachMember((holder, member) { | 584 cls.forEachMember((holder, member) { |
| 541 compiler.withCurrentElement(member, () { | 585 compiler.withCurrentElement(member, () { |
| 542 // Perform various checks as side effect of "computing" the type. | 586 // Perform various checks as side effect of "computing" the type. |
| 543 member.computeType(compiler); | 587 member.computeType(compiler); |
| 544 | 588 |
| (...skipping 1220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1765 visit(node.elsePart); | 1809 visit(node.elsePart); |
| 1766 } | 1810 } |
| 1767 | 1811 |
| 1768 static bool isLogicalOperator(Identifier op) { | 1812 static bool isLogicalOperator(Identifier op) { |
| 1769 String str = op.source.stringValue; | 1813 String str = op.source.stringValue; |
| 1770 return (identical(str, '&&') || str == '||' || str == '!'); | 1814 return (identical(str, '&&') || str == '||' || str == '!'); |
| 1771 } | 1815 } |
| 1772 | 1816 |
| 1773 Element resolveSend(Send node) { | 1817 Element resolveSend(Send node) { |
| 1774 Selector selector = resolveSelector(node); | 1818 Selector selector = resolveSelector(node); |
| 1819 if (node.isSuperCall) mapping.superUses.add(node); |
| 1775 | 1820 |
| 1776 if (node.receiver == null) { | 1821 if (node.receiver == null) { |
| 1777 // If this send is of the form "assert(expr);", then | 1822 // If this send is of the form "assert(expr);", then |
| 1778 // this is an assertion. | 1823 // this is an assertion. |
| 1779 if (selector.isAssert()) { | 1824 if (selector.isAssert()) { |
| 1780 if (selector.argumentCount != 1) { | 1825 if (selector.argumentCount != 1) { |
| 1781 error(node.selector, | 1826 error(node.selector, |
| 1782 MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT, | 1827 MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT, |
| 1783 [selector.argumentCount]); | 1828 [selector.argumentCount]); |
| 1784 } else if (selector.namedArgumentCount != 0) { | 1829 } else if (selector.namedArgumentCount != 0) { |
| (...skipping 1138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2923 compiler.reportMessage(compiler.spanFromElement(mixinApplication), | 2968 compiler.reportMessage(compiler.spanFromElement(mixinApplication), |
| 2924 error, Diagnostic.ERROR); | 2969 error, Diagnostic.ERROR); |
| 2925 // We have found a cycle in the mixin chain. Return null as | 2970 // We have found a cycle in the mixin chain. Return null as |
| 2926 // the mixin for this application to avoid getting into | 2971 // the mixin for this application to avoid getting into |
| 2927 // infinite recursion when traversing members. | 2972 // infinite recursion when traversing members. |
| 2928 return null; | 2973 return null; |
| 2929 } | 2974 } |
| 2930 previous = current; | 2975 previous = current; |
| 2931 current = currentMixinApplication.mixin; | 2976 current = currentMixinApplication.mixin; |
| 2932 } | 2977 } |
| 2978 compiler.world.registerMixinUse(mixinApplication, mixin); |
| 2933 return mixin; | 2979 return mixin; |
| 2934 } | 2980 } |
| 2935 | 2981 |
| 2936 // TODO(johnniwinther): Remove when default class is no longer supported. | 2982 // TODO(johnniwinther): Remove when default class is no longer supported. |
| 2937 DartType visitTypeAnnotation(TypeAnnotation node) { | 2983 DartType visitTypeAnnotation(TypeAnnotation node) { |
| 2938 return visit(node.typeName); | 2984 return visit(node.typeName); |
| 2939 } | 2985 } |
| 2940 | 2986 |
| 2941 // TODO(johnniwinther): Remove when default class is no longer supported. | 2987 // TODO(johnniwinther): Remove when default class is no longer supported. |
| 2942 DartType visitIdentifier(Identifier node) { | 2988 DartType visitIdentifier(Identifier node) { |
| (...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3538 return e; | 3584 return e; |
| 3539 } | 3585 } |
| 3540 | 3586 |
| 3541 /// Assumed to be called by [resolveRedirectingFactory]. | 3587 /// Assumed to be called by [resolveRedirectingFactory]. |
| 3542 Element visitReturn(Return node) { | 3588 Element visitReturn(Return node) { |
| 3543 Node expression = node.expression; | 3589 Node expression = node.expression; |
| 3544 return finishConstructorReference(visit(expression), | 3590 return finishConstructorReference(visit(expression), |
| 3545 expression, expression); | 3591 expression, expression); |
| 3546 } | 3592 } |
| 3547 } | 3593 } |
| OLD | NEW |