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

Side by Side Diff: lib/compiler/implementation/resolver.dart

Issue 10947024: Made dart2js constructor lookup logic "private"-aware, fixed 4740 bug. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixed co19-dart2js.status merge error. Created 8 years, 2 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 abstract class TreeElements { 5 abstract class TreeElements {
6 Element operator[](Node node); 6 Element operator[](Node node);
7 Selector getSelector(Send send); 7 Selector getSelector(Send send);
8 DartType getType(TypeAnnotation annotation); 8 DartType getType(TypeAnnotation annotation);
9 bool isParameterChecked(Element element); 9 bool isParameterChecked(Element element);
10 } 10 }
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 if (kind === ElementKind.PARAMETER || 80 if (kind === ElementKind.PARAMETER ||
81 kind === ElementKind.FIELD_PARAMETER) { 81 kind === ElementKind.FIELD_PARAMETER) {
82 return resolveParameter(element); 82 return resolveParameter(element);
83 } 83 }
84 84
85 compiler.unimplemented("resolve($element)", 85 compiler.unimplemented("resolve($element)",
86 node: element.parseNode(compiler)); 86 node: element.parseNode(compiler));
87 }); 87 });
88 } 88 }
89 89
90 SourceString getConstructorName(Send node) { 90 bool isNamedConstructor(Send node) => node.receiver !== null;
ahe 2012/10/11 04:55:40 Add newline between methods.
aam-me 2012/10/11 06:14:00 Done.
91 if (node.receiver !== null) { 91 SourceString getConstructorName(Send node) =>
ahe 2012/10/11 04:55:40 When the function shorthand doesn't fit on one lin
aam-me 2012/10/11 06:14:00 Done.
92 return node.selector.asIdentifier().source; 92 node.selector.asIdentifier().source;
93 } else {
94 return const SourceString('');
95 }
96 }
97 93
98 FunctionElement resolveConstructorRedirection(FunctionElement constructor) { 94 String createConstructorFullName(SourceString className,
ahe 2012/10/11 04:55:40 As far as I can tell, this is only used for diagno
aam-me 2012/10/11 06:14:00 Done.
95 SourceString constructorName) {
96 String classNameString = className.slowToString();
97 String constructorNameString = constructorName.slowToString();
98 return (constructorName === const SourceString(''))
99 ? classNameString
100 : "$classNameString.$constructorNameString";
101 }
102
103 FunctionElement resolveConstructorRedirection(InitializerResolver resolver,
104 FunctionElement constructor) {
99 if (constructor.isPatched) { 105 if (constructor.isPatched) {
100 checkMatchingPatchSignatures(constructor, constructor.patch); 106 checkMatchingPatchSignatures(constructor, constructor.patch);
101 constructor = constructor.patch; 107 constructor = constructor.patch;
102 } 108 }
103 FunctionExpression node = constructor.parseNode(compiler); 109 FunctionExpression node = constructor.parseNode(compiler);
104 110
105 // A synthetic constructor does not have a node. 111 // A synthetic constructor does not have a node.
106 if (node === null) return null; 112 if (node === null) return null;
107 if (node.initializers === null) return null; 113 if (node.initializers === null) return null;
108 Link<Node> initializers = node.initializers.nodes; 114 Link<Node> initializers = node.initializers.nodes;
109 if (!initializers.isEmpty() && 115 if (!initializers.isEmpty() &&
110 Initializers.isConstructorRedirect(initializers.head)) { 116 Initializers.isConstructorRedirect(initializers.head)) {
111 final ClassElement classElement = constructor.getEnclosingClass(); 117 final ClassElement classElement = constructor.getEnclosingClass();
112 final SourceString constructorName = 118 Selector selector;
113 getConstructorName(initializers.head); 119 if (isNamedConstructor(initializers.head)) {
114 final SourceString className = classElement.name; 120 SourceString constructorName = getConstructorName(initializers.head);
115 return classElement.lookupConstructor(className, constructorName); 121 selector = new Selector.callConstructor(
122 constructorName,
123 resolver.visitor.enclosingElement.getLibrary());
124 } else {
125 selector = new Selector.callDefaultConstructor(
126 resolver.visitor.enclosingElement.getLibrary());
127 }
128 return classElement.lookupConstructor(selector);
116 } 129 }
117 return null; 130 return null;
118 } 131 }
119 132
120 void resolveRedirectingConstructor(InitializerResolver resolver, 133 void resolveRedirectingConstructor(InitializerResolver resolver,
121 Node node, 134 Node node,
122 FunctionElement constructor, 135 FunctionElement constructor,
123 FunctionElement redirection) { 136 FunctionElement redirection) {
124 Set<FunctionElement> seen = new Set<FunctionElement>(); 137 Set<FunctionElement> seen = new Set<FunctionElement>();
125 seen.add(constructor); 138 seen.add(constructor);
126 while (redirection !== null) { 139 while (redirection !== null) {
127 if (seen.contains(redirection)) { 140 if (seen.contains(redirection)) {
128 resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE); 141 resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE);
129 return; 142 return;
130 } 143 }
131 seen.add(redirection); 144 seen.add(redirection);
132 redirection = resolveConstructorRedirection(redirection); 145 redirection = resolveConstructorRedirection(resolver, redirection);
133 } 146 }
134 } 147 }
135 148
136 void checkMatchingPatchParameters(FunctionElement origin, 149 void checkMatchingPatchParameters(FunctionElement origin,
137 Link<Element> originParameters, 150 Link<Element> originParameters,
138 Link<Element> patchParameters) { 151 Link<Element> patchParameters) {
139 while (!originParameters.isEmpty()) { 152 while (!originParameters.isEmpty()) {
140 Element originParameter = originParameters.head; 153 Element originParameter = originParameters.head;
141 Element patchParameter = patchParameters.head; 154 Element patchParameter = patchParameters.head;
142 // Hack: Use unparser to test parameter equality. This only works because 155 // Hack: Use unparser to test parameter equality. This only works because
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 assert(defaultClass.resolutionState == STATE_DONE); 296 assert(defaultClass.resolutionState == STATE_DONE);
284 assert(defaultClass.supertypeLoadState == STATE_DONE); 297 assert(defaultClass.supertypeLoadState == STATE_DONE);
285 if (defaultClass.isInterface()) { 298 if (defaultClass.isInterface()) {
286 error(node, MessageKind.CANNOT_INSTANTIATE_INTERFACE, 299 error(node, MessageKind.CANNOT_INSTANTIATE_INTERFACE,
287 [defaultClass.name]); 300 [defaultClass.name]);
288 } 301 }
289 // We have now established the following: 302 // We have now established the following:
290 // [intrface] is an interface, let's say "MyInterface". 303 // [intrface] is an interface, let's say "MyInterface".
291 // [defaultClass] is a class, let's say "MyClass". 304 // [defaultClass] is a class, let's say "MyClass".
292 305
306 Selector selector;
293 // If the default class implements the interface then we must use the 307 // If the default class implements the interface then we must use the
294 // default class' name. Otherwise we look for a factory with the name 308 // default class' name. Otherwise we look for a factory with the name
295 // of the interface. 309 // of the interface.
296 SourceString name;
297 if (defaultClass.implementsInterface(intrface)) { 310 if (defaultClass.implementsInterface(intrface)) {
298 // TODO(ahe): Don't use string replacement here. 311 var constructorNameString = constructor.name.slowToString();
ahe 2012/10/11 04:55:40 Please keep this todo. I still think it is problem
aam-me 2012/10/11 06:14:00 Done.
299 name = new SourceString(constructor.name.slowToString().replaceFirst( 312 // Create selector based on constructor.name but where interface
300 intrface.name.slowToString(), 313 // is replaced with default class name.
301 defaultClass.name.slowToString())); 314 int classNameSeparatorIndex = constructorNameString.indexOf('\$');
315 if (classNameSeparatorIndex < 0) {
316 selector = new Selector.callDefaultConstructor(
317 defaultClass.getLibrary());
318 } else {
319 selector = new Selector.callConstructor(
320 new SourceString(
321 constructorNameString.substring(classNameSeparatorIndex + 1)),
322 defaultClass.getLibrary());
323 }
324 constructor.defaultImplementation =
325 defaultClass.lookupConstructor(selector);
302 } else { 326 } else {
303 name = constructor.name; 327 selector =
328 new Selector.callConstructor(constructor.name,
329 defaultClass.getLibrary());
330 constructor.defaultImplementation =
331 defaultClass.lookupFactoryConstructor(selector);
304 } 332 }
305 constructor.defaultImplementation = defaultClass.lookupConstructor(name);
306
307 if (constructor.defaultImplementation === null) { 333 if (constructor.defaultImplementation === null) {
308 // We failed to find a constructor named either 334 // We failed to find a constructor named either
309 // "MyInterface.name" or "MyClass.name". 335 // "MyInterface.name" or "MyClass.name".
310 error(node, 336 error(node,
311 MessageKind.CANNOT_FIND_CONSTRUCTOR2, 337 MessageKind.CANNOT_FIND_CONSTRUCTOR2,
312 [name, defaultClass.name]); 338 [selector.name, defaultClass.name]);
ahe 2012/10/11 04:55:40 I think we're using MyClass$foo here. Could you ad
aam-me 2012/10/11 06:14:00 Done.
313 } 339 }
314 } 340 }
315 341
316 TreeElements resolveField(Element element) { 342 TreeElements resolveField(Element element) {
317 Node tree = element.parseNode(compiler); 343 Node tree = element.parseNode(compiler);
318 ResolverVisitor visitor = new ResolverVisitor(compiler, element); 344 ResolverVisitor visitor = new ResolverVisitor(compiler, element);
319 initializerDo(tree, visitor.visit); 345 initializerDo(tree, visitor.visit);
320 return visitor.mapping; 346 return visitor.mapping;
321 } 347 }
322 348
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
672 } else { 698 } else {
673 error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); 699 error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
674 } 700 }
675 visitor.useElement(init, target); 701 visitor.useElement(init, target);
676 visitor.world.registerStaticUse(target); 702 visitor.world.registerStaticUse(target);
677 checkForDuplicateInitializers(name, init); 703 checkForDuplicateInitializers(name, init);
678 // Resolve initializing value. 704 // Resolve initializing value.
679 visitor.visitInStaticContext(init.arguments.head); 705 visitor.visitInStaticContext(init.arguments.head);
680 } 706 }
681 707
708 ClassElement getSuperOrThisLookupTarget(FunctionElement constructor,
709 bool isSuperCall,
710 Node diagnosticNode) {
711 ClassElement lookupTarget = constructor.getEnclosingClass();
712 if (isSuperCall) {
713 // Calculate correct lookup target and constructor name.
714 if (lookupTarget === visitor.compiler.objectClass) {
715 error(diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
716 } else {
717 lookupTarget = lookupTarget.supertype.element;
ahe 2012/10/11 04:55:40 Just return?
aam-me 2012/10/11 06:14:00 Done.
718 }
719 }
720 return lookupTarget;
721 }
722
682 Element resolveSuperOrThisForSend(FunctionElement constructor, 723 Element resolveSuperOrThisForSend(FunctionElement constructor,
683 FunctionExpression functionNode, 724 FunctionExpression functionNode,
684 Send call) { 725 Send call) {
685 // Resolve the selector and the arguments. 726 // Resolve the selector and the arguments.
686 ResolverTask resolver = visitor.compiler.resolver; 727 ResolverTask resolver = visitor.compiler.resolver;
687 visitor.inStaticContext(() { 728 visitor.inStaticContext(() {
688 visitor.resolveSelector(call); 729 visitor.resolveSelector(call);
689 visitor.resolveArguments(call.argumentsNode); 730 visitor.resolveArguments(call.argumentsNode);
690 }); 731 });
691 Selector selector = visitor.mapping.getSelector(call); 732 Selector selector = visitor.mapping.getSelector(call);
692 bool isSuperCall = Initializers.isSuperConstructorCall(call); 733 bool isSuperCall = Initializers.isSuperConstructorCall(call);
693 SourceString constructorName = resolver.getConstructorName(call); 734
694 Element result = resolveSuperOrThis( 735 ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor,
695 constructor, isSuperCall, false, constructorName, selector, call); 736 isSuperCall,
696 visitor.useElement(call, result); 737 call);
697 visitor.world.registerStaticUse(result); 738 final SourceString className = lookupTarget.name;
698 return result; 739
740 SourceString constructorName;
741 Selector lookupSelector;
742 if (resolver.isNamedConstructor(call)) {
743 constructorName = resolver.getConstructorName(call);
744 lookupSelector = new Selector.callConstructor(
745 constructorName,
746 visitor.enclosingElement.getLibrary());
747 } else {
748 constructorName = const SourceString('');
749 lookupSelector = new Selector.callDefaultConstructor(
750 visitor.enclosingElement.getLibrary());
751 }
752
753 FunctionElement lookedupConstructor =
754 lookupTarget.lookupConstructor(lookupSelector);
755
756 final bool isImplicitSuperCall = false;
757 verifyThatConstructorMatchesCall(lookedupConstructor,
758 selector,
759 isImplicitSuperCall,
760 call,
761 constructorName,
762 className);
763
764 visitor.useElement(call, lookedupConstructor);
765 visitor.world.registerStaticUse(lookedupConstructor);
766 return lookedupConstructor;
699 } 767 }
700 768
701 void resolveImplicitSuperConstructorSend(FunctionElement constructor, 769 void resolveImplicitSuperConstructorSend(FunctionElement constructor,
702 FunctionExpression functionNode) { 770 FunctionExpression functionNode) {
703 // If the class has a super resolve the implicit super call. 771 // If the class has a super resolve the implicit super call.
704 ClassElement classElement = constructor.getEnclosingClass(); 772 ClassElement classElement = constructor.getEnclosingClass();
705 ClassElement superClass = classElement.superclass; 773 ClassElement superClass = classElement.superclass;
706 if (classElement != visitor.compiler.objectClass) { 774 if (classElement != visitor.compiler.objectClass) {
707 assert(superClass !== null); 775 assert(superClass !== null);
708 assert(superClass.resolutionState == STATE_DONE); 776 assert(superClass.resolutionState == STATE_DONE);
709 SourceString name = const SourceString(''); 777 SourceString constructorName = const SourceString('');
710 Selector call = new Selector.call(name, classElement.getLibrary(), 0); 778 Selector callToMatch = new Selector.call(
711 var element = resolveSuperOrThis(constructor, true, true, 779 constructorName,
712 name, call, functionNode); 780 classElement.getLibrary(),
713 visitor.world.registerStaticUse(element); 781 0);
782
783 final bool isSuperCall = true;
784 ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor,
785 isSuperCall,
786 functionNode);
787 final SourceString className = lookupTarget.name;
788 Element calledConstructor = lookupTarget.lookupConstructor(
789 new Selector.callDefaultConstructor(
790 visitor.enclosingElement.getLibrary()));
791
792 final bool isImplicitSuperCall = true;
793 verifyThatConstructorMatchesCall(calledConstructor,
794 callToMatch,
795 isImplicitSuperCall,
796 functionNode,
797 className,
798 const SourceString(''));
799
800 visitor.world.registerStaticUse(calledConstructor);
714 } 801 }
715 } 802 }
716 803
717 Element resolveSuperOrThis(FunctionElement constructor, 804 void verifyThatConstructorMatchesCall(
718 bool isSuperCall, 805 FunctionElement lookedupConstructor,
719 bool isImplicitSuperCall, 806 Selector call,
720 SourceString constructorName, 807 bool isImplicitSuperCall,
721 Selector selector, 808 Node diagnosticNode,
722 Node diagnosticNode) { 809 SourceString className,
723 ClassElement lookupTarget = constructor.getEnclosingClass(); 810 SourceString constructorName) {
724 bool validTarget = true; 811 if (lookedupConstructor === null
725 FunctionElement result; 812 || !lookedupConstructor.isGenerativeConstructor()) {
726 if (isSuperCall) { 813 var fullConstructorName =
727 // Calculate correct lookup target and constructor name. 814 visitor.compiler.resolver.createConstructorFullName(className,
728 if (lookupTarget === visitor.compiler.objectClass) { 815 constructorName);
729 error(diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
730 } else {
731 lookupTarget = lookupTarget.supertype.element;
732 }
733 }
734
735 // Lookup constructor and try to match it to the selector.
736 ResolverTask resolver = visitor.compiler.resolver;
737 final SourceString className = lookupTarget.name;
738 result = lookupTarget.lookupConstructor(className, constructorName);
739 if (result === null || !result.isGenerativeConstructor()) {
740 String classNameString = className.slowToString();
741 String constructorNameString = constructorName.slowToString();
742 String name = (constructorName === const SourceString(''))
743 ? classNameString
744 : "$classNameString.$constructorNameString";
745 MessageKind kind = isImplicitSuperCall 816 MessageKind kind = isImplicitSuperCall
746 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT 817 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT
747 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; 818 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR;
748 error(diagnosticNode, kind, [name]); 819 error(diagnosticNode, kind, [fullConstructorName]);
749 } else { 820 } else {
750 if (!selector.applies(result, visitor.compiler)) { 821 if (!call.applies(lookedupConstructor, visitor.compiler)) {
751 MessageKind kind = isImplicitSuperCall 822 MessageKind kind = isImplicitSuperCall
752 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT 823 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT
753 : MessageKind.NO_MATCHING_CONSTRUCTOR; 824 : MessageKind.NO_MATCHING_CONSTRUCTOR;
754 error(diagnosticNode, kind); 825 error(diagnosticNode, kind);
755 } 826 }
756 } 827 }
757 return result;
758 } 828 }
759 829
760 FunctionElement resolveRedirection(FunctionElement constructor, 830 FunctionElement resolveRedirection(FunctionElement constructor,
761 FunctionExpression functionNode) { 831 FunctionExpression functionNode) {
762 if (functionNode.initializers === null) return null; 832 if (functionNode.initializers === null) return null;
763 Link<Node> link = functionNode.initializers.nodes; 833 Link<Node> link = functionNode.initializers.nodes;
764 if (!link.isEmpty() && Initializers.isConstructorRedirect(link.head)) { 834 if (!link.isEmpty() && Initializers.isConstructorRedirect(link.head)) {
765 return resolveSuperOrThisForSend(constructor, functionNode, link.head); 835 return resolveSuperOrThisForSend(constructor, functionNode, link.head);
766 } 836 }
767 return null; 837 return null;
(...skipping 2023 matching lines...) Expand 10 before | Expand all | Expand 10 after
2791 return new ErroneousFunctionElement(kind, arguments, targetName, 2861 return new ErroneousFunctionElement(kind, arguments, targetName,
2792 enclosing); 2862 enclosing);
2793 } 2863 }
2794 } 2864 }
2795 2865
2796 // TODO(ngeoffray): method named lookup should not report errors. 2866 // TODO(ngeoffray): method named lookup should not report errors.
2797 FunctionElement lookupConstructor(ClassElement cls, 2867 FunctionElement lookupConstructor(ClassElement cls,
2798 Node diagnosticNode, 2868 Node diagnosticNode,
2799 SourceString constructorName) { 2869 SourceString constructorName) {
2800 cls.ensureResolved(compiler); 2870 cls.ensureResolved(compiler);
2801 Element result = cls.lookupConstructor(cls.name, constructorName); 2871 Selector selector =
2872 constructorName === const SourceString('')
ahe 2012/10/11 04:55:40 Only use == on SourceString.
aam-me 2012/10/11 06:14:00 Done.
2873 ? new Selector.callDefaultConstructor(
2874 resolver.enclosingElement.getLibrary())
2875 : new Selector.callConstructor(
2876 constructorName,
2877 resolver.enclosingElement.getLibrary());
ahe 2012/10/11 04:55:40 I think I'm seeing this pattern a few times. Would
aam-me 2012/10/11 06:14:00 I don't think this code is used anywhere besides t
2878 Element result = cls.lookupConstructor(selector);
2802 if (result === null) { 2879 if (result === null) {
2803 String fullConstructorName = cls.name.slowToString(); 2880 String fullConstructorName =
2804 if (constructorName !== const SourceString('')) { 2881 resolver.compiler.resolver.createConstructorFullName(
2805 fullConstructorName = '$fullConstructorName' 2882 cls.name,
2806 '.${constructorName.slowToString()}'; 2883 constructorName);
2807 } 2884 return failOrReturnErroneousElement(
2808 return failOrReturnErroneousElement(cls, diagnosticNode, 2885 cls,
2809 new SourceString(fullConstructorName), 2886 diagnosticNode,
2810 MessageKind.CANNOT_FIND_CONSTRUCTOR, 2887 new SourceString(fullConstructorName),
2811 [fullConstructorName]); 2888 MessageKind.CANNOT_FIND_CONSTRUCTOR,
2889 [fullConstructorName]);
2812 } else if (inConstContext && !result.modifiers.isConst()) { 2890 } else if (inConstContext && !result.modifiers.isConst()) {
2813 error(diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST); 2891 error(diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
2814 } 2892 }
2815 return result; 2893 return result;
2816 } 2894 }
2817 2895
2818 visitNewExpression(NewExpression node) { 2896 visitNewExpression(NewExpression node) {
2819 Node selector = node.send.selector; 2897 Node selector = node.send.selector;
2820 Element e = visit(selector); 2898 Element e = visit(selector);
2821 if (!Elements.isUnresolved(e) && e.kind === ElementKind.CLASS) { 2899 if (!Elements.isUnresolved(e) && e.kind === ElementKind.CLASS) {
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
3136 return result; 3214 return result;
3137 } 3215 }
3138 Element lookup(SourceString name) => localLookup(name); 3216 Element lookup(SourceString name) => localLookup(name);
3139 Element lexicalLookup(SourceString name) => localLookup(name); 3217 Element lexicalLookup(SourceString name) => localLookup(name);
3140 3218
3141 Element add(Element newElement) { 3219 Element add(Element newElement) {
3142 throw "Cannot add an element in a patch library scope"; 3220 throw "Cannot add an element in a patch library scope";
3143 } 3221 }
3144 String toString() => 'PatchLibraryScope($origin,$patch)'; 3222 String toString() => 'PatchLibraryScope($origin,$patch)';
3145 } 3223 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698