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

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

Issue 10083007: Resolve implicit super calls. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 8 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
« no previous file with comments | « no previous file | lib/compiler/implementation/warnings.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 interface TreeElements { 5 interface TreeElements {
6 Element operator[](Node node); 6 Element operator[](Node node);
7 Selector getSelector(Send send); 7 Selector getSelector(Send send);
8 } 8 }
9 9
10 class TreeElementMapping implements TreeElements { 10 class TreeElementMapping implements TreeElements {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 } 62 }
63 63
64 SourceString getConstructorName(Send node) { 64 SourceString getConstructorName(Send node) {
65 if (node.receiver !== null) { 65 if (node.receiver !== null) {
66 return node.selector.asIdentifier().source; 66 return node.selector.asIdentifier().source;
67 } else { 67 } else {
68 return const SourceString(''); 68 return const SourceString('');
69 } 69 }
70 } 70 }
71 71
72 FunctionElement lookupConstructor(ClassElement classElement, Send send,
73 [noConstructor(Element)]) {
74 final SourceString constructorName = getConstructorName(send);
75 final SourceString className = classElement.name;
76 return classElement.lookupConstructor(className,
77 constructorName,
78 noConstructor);
79 }
80
81 FunctionElement resolveConstructorRedirection(FunctionElement constructor) { 72 FunctionElement resolveConstructorRedirection(FunctionElement constructor) {
82 FunctionExpression node = constructor.parseNode(compiler); 73 FunctionExpression node = constructor.parseNode(compiler);
83 // A synthetic constructor does not have a node. 74 // A synthetic constructor does not have a node.
84 if (node === null) return null; 75 if (node === null) return null;
85 if (node.initializers === null) return null; 76 if (node.initializers === null) return null;
86 Link<Node> initializers = node.initializers.nodes; 77 Link<Node> initializers = node.initializers.nodes;
87 if (!initializers.isEmpty() && 78 if (!initializers.isEmpty() &&
88 Initializers.isConstructorRedirect(initializers.head)) { 79 Initializers.isConstructorRedirect(initializers.head)) {
89 return lookupConstructor(constructor.enclosingElement, initializers.head); 80 final ClassElement classElement = constructor.enclosingElement;
floitsch 2012/04/13 18:08:47 I inlined the code from above here. I can undo thi
karlklose 2012/04/16 13:01:51 I am fine with inlining the code here.
81 final SourceString constructorName =
82 getConstructorName(initializers.head);
83 final SourceString className = classElement.name;
84 return classElement.lookupConstructor(className, constructorName);
90 } 85 }
91 return null; 86 return null;
92 } 87 }
93 88
94 void resolveRedirectingConstructor(InitializerResolver resolver, 89 void resolveRedirectingConstructor(InitializerResolver resolver,
95 Node node, 90 Node node,
96 FunctionElement constructor, 91 FunctionElement constructor,
97 FunctionElement redirection) { 92 FunctionElement redirection) {
98 Set<FunctionElement> seen = new Set<FunctionElement>(); 93 Set<FunctionElement> seen = new Set<FunctionElement>();
99 seen.add(constructor); 94 seen.add(constructor);
(...skipping 16 matching lines...) Expand all
116 if (elements !== null) return elements; 111 if (elements !== null) return elements;
117 } 112 }
118 FunctionExpression tree = element.parseNode(compiler); 113 FunctionExpression tree = element.parseNode(compiler);
119 if (isConstructor) { 114 if (isConstructor) {
120 resolveConstructorImplementation(element, tree); 115 resolveConstructorImplementation(element, tree);
121 } 116 }
122 ResolverVisitor visitor = new ResolverVisitor(compiler, element); 117 ResolverVisitor visitor = new ResolverVisitor(compiler, element);
123 visitor.useElement(tree, element); 118 visitor.useElement(tree, element);
124 visitor.setupFunction(tree, element); 119 visitor.setupFunction(tree, element);
125 120
126 if (tree.initializers != null) { 121 if (isConstructor) {
127 if (!isConstructor) { 122 // Even if there is no initializer list we still have to do the
128 error(tree, MessageKind.FUNCTION_WITH_INITIALIZER); 123 // resolution in case there is an implicit super constructor call.
129 }
130 InitializerResolver resolver = new InitializerResolver(visitor); 124 InitializerResolver resolver = new InitializerResolver(visitor);
131 FunctionElement redirection = 125 FunctionElement redirection =
132 resolver.resolveInitializers(element, tree); 126 resolver.resolveInitializers(element, tree);
133 if (redirection !== null) { 127 if (redirection !== null) {
134 resolveRedirectingConstructor(resolver, tree, element, redirection); 128 resolveRedirectingConstructor(resolver, tree, element, redirection);
135 } 129 }
130 } else if (tree.initializers != null) {
131 error(tree, MessageKind.FUNCTION_WITH_INITIALIZER);
136 } 132 }
137 visitor.visit(tree.body); 133 visitor.visit(tree.body);
138 134
139 // Resolve the type annotations encountered in the method. 135 // Resolve the type annotations encountered in the method.
140 while (!toResolve.isEmpty()) { 136 while (!toResolve.isEmpty()) {
141 ClassElement classElement = toResolve.removeFirst(); 137 ClassElement classElement = toResolve.removeFirst();
142 classElement.ensureResolved(compiler); 138 classElement.ensureResolved(compiler);
143 } 139 }
144 if (isConstructor) { 140 if (isConstructor) {
145 constructorElements[element] = visitor.mapping; 141 constructorElements[element] = visitor.mapping;
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 // Check for duplicate initializers. 270 // Check for duplicate initializers.
275 if (initialized.containsKey(name)) { 271 if (initialized.containsKey(name)) {
276 error(init, MessageKind.DUPLICATE_INITIALIZER, [name]); 272 error(init, MessageKind.DUPLICATE_INITIALIZER, [name]);
277 warning(initialized[name], MessageKind.ALREADY_INITIALIZED, [name]); 273 warning(initialized[name], MessageKind.ALREADY_INITIALIZED, [name]);
278 } 274 }
279 initialized[name] = init; 275 initialized[name] = init;
280 // Resolve initializing value. 276 // Resolve initializing value.
281 visitor.visitInStaticContext(init.arguments.head); 277 visitor.visitInStaticContext(init.arguments.head);
282 } 278 }
283 279
280 Element resolveSuperOrThisForSend(FunctionElement constructor,
281 FunctionExpression functionNode,
282 Send call) {
283 // Resolve the arguments, and make sure the call gets a selector
284 // by calling handleArguments.
285 ResolverTask resolver = visitor.compiler.resolver;
286 visitor.inStaticContext( () => visitor.handleArguments(call) );
287 Selector selector = visitor.mapping.getSelector(call);
288 bool isSuperCall = Initializers.isSuperConstructorCall(call);
289 SourceString constructorName = resolver.getConstructorName(call);
290 Element result = resolveSuperOrThis(
291 constructor, isSuperCall, false, constructorName, selector, call);
292 visitor.useElement(call, result);
293 return result;
294 }
295
296 void resolveImplicitSuperConstructorSend(FunctionElement constructor,
297 FunctionExpression functionNode) {
298 // If the class has a super resolve the implicit super call.
299 ClassElement classElement = constructor.enclosingElement;
300 ClassElement superClass = classElement.superclass;
301 if (classElement != visitor.compiler.objectClass) {
302 assert(superClass !== null);
303 assert(superClass.isResolved);
304 resolveSuperOrThis(constructor, true, true, const SourceString(''),
305 Selector.INVOCATION_0, functionNode);
306 }
307 }
308
284 Element resolveSuperOrThis(FunctionElement constructor, 309 Element resolveSuperOrThis(FunctionElement constructor,
285 FunctionExpression functionNode, 310 bool isSuperCall,
286 Send call) { 311 bool isImplicitSuperCall,
287 noConstructor(e) { 312 SourceString constructorName,
288 if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]); 313 Selector selector,
289 } 314 Node diagnosticNode) {
290
291 ClassElement lookupTarget = constructor.enclosingElement; 315 ClassElement lookupTarget = constructor.enclosingElement;
292 bool validTarget = true; 316 bool validTarget = true;
293 FunctionElement result; 317 FunctionElement result;
294 if (Initializers.isSuperConstructorCall(call)) { 318 if (isSuperCall) {
295 // Check for invalid initializers.
296 if (hasSuper) {
297 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
298 }
299 hasSuper = true;
300 // Calculate correct lookup target and constructor name. 319 // Calculate correct lookup target and constructor name.
301 if (lookupTarget.name == Types.OBJECT) { 320 if (lookupTarget.name == Types.OBJECT) {
302 error(call, MessageKind.SUPER_INITIALIZER_IN_OBJECT); 321 error(diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
303 } else { 322 } else {
304 lookupTarget = lookupTarget.supertype.element; 323 lookupTarget = lookupTarget.supertype.element;
305 } 324 }
306 } else if (Initializers.isConstructorRedirect(call)) {
307 // Check that there is no body (Language specification 7.5.1).
308 if (functionNode.hasBody()) {
309 error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY);
310 }
311 // Check that there are no other initializers.
312 if (!initializers.tail.isEmpty()) {
313 error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER);
314 }
315 } else {
316 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
317 validTarget = false;
318 } 325 }
319 326
320 if (validTarget) { 327 // Lookup constructor and try to match it to the selector.
321 // Resolve the arguments, and make sure the call gets a selector 328 ResolverTask resolver = visitor.compiler.resolver;
322 // by calling handleArguments. 329 final SourceString className = lookupTarget.name;
323 visitor.inStaticContext( () => visitor.handleArguments(call) ); 330 result = lookupTarget.lookupConstructor(className, constructorName);
324 // Lookup constructor and try to match it to the selector. 331 if (result === null) {
325 ResolverTask resolver = visitor.compiler.resolver; 332 String classNameString = className.slowToString();
326 result = resolver.lookupConstructor(lookupTarget, call); 333 String constructorNameString = constructorName.slowToString();
327 if (result === null) { 334 String name = (constructorName === const SourceString(''))
328 SourceString constructorName = resolver.getConstructorName(call); 335 ? classNameString
329 String className = lookupTarget.name.slowToString(); 336 : "$classNameString.$constructorNameString";
330 String name = (constructorName === const SourceString('')) 337 MessageKind kind = isImplicitSuperCall
331 ? className 338 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT
332 : "$className.${constructorName.slowToString()}"; 339 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR;
333 error(call, MessageKind.CANNOT_RESOLVE_CONSTRUCTOR, [name]); 340 error(diagnosticNode, kind, [name]);
334 } else { 341 } else {
335 final Compiler compiler = visitor.compiler; 342 final Compiler compiler = visitor.compiler;
336 Selector selector = visitor.mapping.getSelector(call); 343 FunctionParameters parameters = result.computeParameters(compiler);
337 FunctionParameters parameters = result.computeParameters(compiler); 344 if (!selector.applies(parameters)) {
338 // TODO(karlklose): support optional arguments. 345 MessageKind kind = isImplicitSuperCall
339 if (!selector.applies(parameters)) { 346 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT
340 error(call, MessageKind.NO_MATCHING_CONSTRUCTOR); 347 : MessageKind.NO_MATCHING_CONSTRUCTOR;
341 } 348 error(diagnosticNode, kind);
342 } 349 }
343 visitor.useElement(call, result);
344 } 350 }
345 return result; 351 return result;
346 } 352 }
347 353
348 FunctionElement resolveRedirection(FunctionElement constructor, 354 FunctionElement resolveRedirection(FunctionElement constructor,
349 FunctionExpression functionNode) { 355 FunctionExpression functionNode) {
350 if (functionNode.initializers === null) return null; 356 if (functionNode.initializers === null) return null;
351 Link<Node> link = functionNode.initializers.nodes; 357 Link<Node> link = functionNode.initializers.nodes;
352 if (!link.isEmpty() && Initializers.isConstructorRedirect(link.head)) { 358 if (!link.isEmpty() && Initializers.isConstructorRedirect(link.head)) {
353 return resolveSuperOrThis(constructor, functionNode, link.head); 359 return resolveSuperOrThisForSend(constructor, functionNode, link.head);
354 } 360 }
355 return null; 361 return null;
356 } 362 }
357 363
358 /** 364 /**
359 * Resolve all initializers of this constructor. In the case of a redirecting 365 * Resolve all initializers of this constructor. In the case of a redirecting
360 * constructor, the resolved constructor's function element is returned. 366 * constructor, the resolved constructor's function element is returned.
361 */ 367 */
362 FunctionElement resolveInitializers(FunctionElement constructor, 368 FunctionElement resolveInitializers(FunctionElement constructor,
363 FunctionExpression functionNode) { 369 FunctionExpression functionNode) {
364 if (functionNode.initializers === null) return null; 370 if (functionNode.initializers === null) {
365 initializers = functionNode.initializers.nodes; 371 initializers = const EmptyLink<Node>();
372 } else {
373 initializers = functionNode.initializers.nodes;
374 }
366 FunctionElement result; 375 FunctionElement result;
376 bool resolvedSuper = false;
367 for (Link<Node> link = initializers; 377 for (Link<Node> link = initializers;
368 !link.isEmpty(); 378 !link.isEmpty();
369 link = link.tail) { 379 link = link.tail) {
370 if (link.head.asSendSet() != null) { 380 if (link.head.asSendSet() != null) {
371 final SendSet init = link.head.asSendSet(); 381 final SendSet init = link.head.asSendSet();
372 resolveFieldInitializer(constructor, init); 382 resolveFieldInitializer(constructor, init);
373 } else if (link.head.asSend() !== null) { 383 } else if (link.head.asSend() !== null) {
374 final Send call = link.head.asSend(); 384 final Send call = link.head.asSend();
375 result = resolveSuperOrThis(constructor, functionNode, call); 385 if (Initializers.isSuperConstructorCall(call)) {
386 if (resolvedSuper) {
387 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
388 }
389 resolveSuperOrThisForSend(constructor, functionNode, call);
390 resolvedSuper = true;
391 } else if (Initializers.isConstructorRedirect(call)) {
392 // Check that there is no body (Language specification 7.5.1).
393 if (functionNode.hasBody()) {
394 error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY);
395 }
396 // Check that there are no other initializers.
397 if (!initializers.tail.isEmpty()) {
398 error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER);
399 }
400 return resolveSuperOrThisForSend(constructor, functionNode, call);
401 } else {
402 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
403 return null;
404 }
376 } else { 405 } else {
377 error(link.head, MessageKind.INVALID_INITIALIZER); 406 error(link.head, MessageKind.INVALID_INITIALIZER);
378 } 407 }
379 } 408 }
380 return result; 409 if (!resolvedSuper) {
410 resolveImplicitSuperConstructorSend(constructor, functionNode);
411 }
412 return null; // Super initializers always return null.
381 } 413 }
382 } 414 }
383 415
384 class CommonResolverVisitor<R> extends AbstractVisitor<R> { 416 class CommonResolverVisitor<R> extends AbstractVisitor<R> {
385 final Compiler compiler; 417 final Compiler compiler;
386 418
387 CommonResolverVisitor(Compiler this.compiler); 419 CommonResolverVisitor(Compiler this.compiler);
388 420
389 R visitNode(Node node) { 421 R visitNode(Node node) {
390 cancel(node, 'internal error'); 422 cancel(node, 'internal error');
(...skipping 770 matching lines...) Expand 10 before | Expand all | Expand 10 after
1161 } else { 1193 } else {
1162 // It's only a warning if it shadows another label. 1194 // It's only a warning if it shadows another label.
1163 existingElement = statementScope.lookupLabel(labelName); 1195 existingElement = statementScope.lookupLabel(labelName);
1164 if (existingElement !== null) { 1196 if (existingElement !== null) {
1165 warning(labelIdentifier, MessageKind.DUPLICATE_LABEL, [labelName]); 1197 warning(labelIdentifier, MessageKind.DUPLICATE_LABEL, [labelName]);
1166 warning(existingElement.label, 1198 warning(existingElement.label,
1167 MessageKind.EXISTING_LABEL, [labelName]); 1199 MessageKind.EXISTING_LABEL, [labelName]);
1168 } 1200 }
1169 } 1201 }
1170 1202
1171 TargetElement TargetElement = 1203 TargetElement targetElement =
1172 new TargetElement(switchCase, 1204 new TargetElement(switchCase,
1173 statementScope.nestingLevel, 1205 statementScope.nestingLevel,
1174 enclosingElement); 1206 enclosingElement);
1175 mapping[switchCase] = TargetElement; 1207 mapping[switchCase] = targetElement;
1176 1208
1177 LabelElement label = 1209 LabelElement label =
1178 new LabelElement(labelIdentifier, labelName, 1210 new LabelElement(labelIdentifier, labelName,
1179 TargetElement, enclosingElement); 1211 targetElement, enclosingElement);
1180 mapping[labelIdentifier] = label; 1212 mapping[labelIdentifier] = label;
1181 continueLabels[labelName] = label; 1213 continueLabels[labelName] = label;
1182 } 1214 }
1183 cases = cases.tail; 1215 cases = cases.tail;
1184 if (switchCase.defaultKeyword !== null && !cases.isEmpty()) { 1216 if (switchCase.defaultKeyword !== null && !cases.isEmpty()) {
1185 error(switchCase, MessageKind.INVALID_CASE_DEFAULT); 1217 error(switchCase, MessageKind.INVALID_CASE_DEFAULT);
1186 } 1218 }
1187 } 1219 }
1188 statementScope.enterSwitch(breakElement, continueLabels); 1220 statementScope.enterSwitch(breakElement, continueLabels);
1189 node.cases.accept(this); 1221 node.cases.accept(this);
1190 statementScope.exitSwitch(); 1222 statementScope.exitSwitch();
1191 1223
1192 // Clean-up unused labels 1224 // Clean-up unused labels
1193 continueLabels.forEach((String key, LabelElement label) { 1225 continueLabels.forEach((String key, LabelElement label) {
1194 TargetElement TargetElement = label.target; 1226 TargetElement targetElement = label.target;
1195 SwitchCase switchCase = TargetElement.statement; 1227 SwitchCase switchCase = targetElement.statement;
1196 if (!label.isContinueTarget) { 1228 if (!label.isContinueTarget) {
1197 mapping.remove(switchCase); 1229 mapping.remove(switchCase);
1198 mapping.remove(label.label); 1230 mapping.remove(label.label);
1199 } 1231 }
1200 }); 1232 });
1201 } 1233 }
1202 1234
1203 visitSwitchCase(SwitchCase node) { 1235 visitSwitchCase(SwitchCase node) {
1204 // The label was handled in [visitSwitchStatement(SwitchStatement)]. 1236 // The label was handled in [visitSwitchStatement(SwitchStatement)].
1205 node.expressions.accept(this); 1237 node.expressions.accept(this);
(...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after
1794 1826
1795 TopScope(LibraryElement library) : super(null, library); 1827 TopScope(LibraryElement library) : super(null, library);
1796 Element lookup(SourceString name) { 1828 Element lookup(SourceString name) {
1797 return library.find(name); 1829 return library.find(name);
1798 } 1830 }
1799 1831
1800 Element add(Element element) { 1832 Element add(Element element) {
1801 throw "Cannot add an element in the top scope"; 1833 throw "Cannot add an element in the top scope";
1802 } 1834 }
1803 } 1835 }
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/warnings.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698