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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/resolution/members.dart

Issue 12033049: Disallow mixing in classes that use 'super'. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Merge from master. Created 7 years, 11 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 | Annotate | Revision Log
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 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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698