| 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 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 Loading... |
| 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; |
| 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 Loading... |
| 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 Loading... |
| 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; // If there was no redirection 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |