Chromium Code Reviews| 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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 60 TreeElements resolveMethodElement(FunctionElement element) { | 60 TreeElements resolveMethodElement(FunctionElement element) { |
| 61 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR && | 61 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR && |
| 62 constructorElements[element] !== null) { | 62 constructorElements[element] !== null) { |
| 63 return constructorElements[element]; | 63 return constructorElements[element]; |
| 64 } | 64 } |
| 65 FunctionExpression tree = element.parseNode(compiler); | 65 FunctionExpression tree = element.parseNode(compiler); |
| 66 ResolverVisitor visitor = new ResolverVisitor(compiler, element); | 66 ResolverVisitor visitor = new ResolverVisitor(compiler, element); |
| 67 visitor.useElement(tree, element); | 67 visitor.useElement(tree, element); |
| 68 visitor.setupFunction(tree, element); | 68 visitor.setupFunction(tree, element); |
| 69 | 69 |
| 70 if (tree.initializers != null) { | 70 if (tree.initializers != null) { |
|
floitsch
2012/02/14 16:38:02
maybe verify in here that we have a constructor.
karlklose
2012/02/15 13:10:35
Done.
| |
| 71 new InitializerResolver(visitor, element).resolveInitializers(tree); | 71 InitializerResolver resolver = new InitializerResolver(visitor); |
| 72 FunctionElement redirection = resolver.resolveInitializers(element, tree); | |
| 73 Set<FunctionElement> seen; // Initialized lazily. | |
| 74 while (redirection !== null) { | |
| 75 if (seen === null) { | |
| 76 seen = new Set<FunctionElement>(); | |
| 77 seen.add(element); | |
| 78 } | |
| 79 if (seen.contains(redirection)) { | |
| 80 visitor.error(tree, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE); | |
| 81 break; | |
| 82 } | |
| 83 seen.add(redirection); | |
| 84 FunctionExpression functionNode = redirection.parseNode(compiler); | |
| 85 if (functionNode !== null) { | |
| 86 redirection = resolver.resolveRedirection(redirection, functionNode); | |
| 87 } else { | |
| 88 // A synthetic constructor does not have a node. | |
| 89 redirection = null; | |
| 90 } | |
| 91 } | |
| 72 } | 92 } |
| 73 visitor.visit(tree.body); | 93 visitor.visit(tree.body); |
| 74 | 94 |
| 75 // Resolve the type annotations encountered in the method. | 95 // Resolve the type annotations encountered in the method. |
| 76 Link<ClassElement> newResolvedClasses = const EmptyLink<ClassElement>(); | 96 Link<ClassElement> newResolvedClasses = const EmptyLink<ClassElement>(); |
| 77 while (!toResolve.isEmpty()) { | 97 while (!toResolve.isEmpty()) { |
| 78 ClassElement classElement = toResolve.removeFirst(); | 98 ClassElement classElement = toResolve.removeFirst(); |
| 79 if (!classElement.isResolved) { | 99 if (!classElement.isResolved) { |
| 80 classElement.resolve(compiler); | 100 classElement.resolve(compiler); |
| 81 } | 101 } |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 // TODO(karlklose): check if type arguments match, if a classelement occurs | 153 // TODO(karlklose): check if type arguments match, if a classelement occurs |
| 134 // more than once in the supertypes. | 154 // more than once in the supertypes. |
| 135 if (classElement.allSupertypes !== null) return; | 155 if (classElement.allSupertypes !== null) return; |
| 136 final Type supertype = classElement.supertype; | 156 final Type supertype = classElement.supertype; |
| 137 if (seen.contains(classElement)) { | 157 if (seen.contains(classElement)) { |
| 138 error(classElement.parseNode(compiler), | 158 error(classElement.parseNode(compiler), |
| 139 MessageKind.CYCLIC_CLASS_HIERARCHY, | 159 MessageKind.CYCLIC_CLASS_HIERARCHY, |
| 140 [classElement.name]); | 160 [classElement.name]); |
| 141 classElement.allSupertypes = const EmptyLink<Type>(); | 161 classElement.allSupertypes = const EmptyLink<Type>(); |
| 142 } else if (supertype != null) { | 162 } else if (supertype != null) { |
| 143 Type supertype = classElement.supertype; | |
| 144 seen.add(classElement); | 163 seen.add(classElement); |
| 145 Link<Type> superSupertypes = | 164 Link<Type> superSupertypes = |
| 146 getOrCalculateAllSupertypes(supertype.element, seen); | 165 getOrCalculateAllSupertypes(supertype.element, seen); |
| 147 Link<Type> supertypes = new Link<Type>(supertype, superSupertypes); | 166 Link<Type> supertypes = new Link<Type>(supertype, superSupertypes); |
| 148 for (Link<Type> interfaces = classElement.interfaces; | 167 for (Link<Type> interfaces = classElement.interfaces; |
| 149 !interfaces.isEmpty(); | 168 !interfaces.isEmpty(); |
| 150 interfaces = interfaces.tail) { | 169 interfaces = interfaces.tail) { |
| 151 Element element = interfaces.head.element; | 170 Element element = interfaces.head.element; |
| 152 Link<Type> interfaceSupertypes = | 171 Link<Type> interfaceSupertypes = |
| 153 getOrCalculateAllSupertypes(element, seen); | 172 getOrCalculateAllSupertypes(element, seen); |
| 154 supertypes = supertypes.reversePrependAll(interfaceSupertypes); | 173 supertypes = supertypes.reversePrependAll(interfaceSupertypes); |
| 155 } | 174 } |
| 156 seen.remove(classElement); | 175 seen.remove(classElement); |
| 157 classElement.allSupertypes = supertypes; | 176 classElement.allSupertypes = supertypes; |
| 158 } else { | 177 } else { |
| 159 classElement.allSupertypes = const EmptyLink<Type>(); | 178 classElement.allSupertypes = const EmptyLink<Type>(); |
| 160 } | 179 } |
| 161 } | 180 } |
| 162 | 181 |
| 163 error(Node node, MessageKind kind, [arguments = const []]) { | 182 error(Node node, MessageKind kind, [arguments = const []]) { |
| 164 ResolutionError error = new ResolutionError(kind, arguments); | 183 ResolutionError message = new ResolutionError(kind, arguments); |
| 165 compiler.reportError(node, error); | 184 compiler.reportError(node, error); |
|
floitsch
2012/02/14 16:38:02
message?
karlklose
2012/02/15 13:10:35
Done.
| |
| 166 } | 185 } |
| 167 } | 186 } |
| 168 | 187 |
| 169 class InitializerResolver { | 188 class InitializerResolver { |
| 170 final ResolverVisitor visitor; | 189 final ResolverVisitor visitor; |
| 171 final FunctionElement constructor; | |
| 172 final Map<SourceString, Node> initialized; | 190 final Map<SourceString, Node> initialized; |
| 173 Link<Node> initializers; | 191 Link<Node> initializers; |
| 174 bool hasSuper; | 192 bool hasSuper; |
| 175 | 193 |
| 176 InitializerResolver(this.visitor, this.constructor) | 194 InitializerResolver(this.visitor) |
| 177 : initialized = new Map<SourceString, Node>(), hasSuper = false; | 195 : initialized = new Map<SourceString, Node>(), hasSuper = false; |
| 178 | 196 |
| 179 error(Node node, MessageKind kind, [arguments = const []]) { | 197 error(Node node, MessageKind kind, [arguments = const []]) { |
| 180 visitor.error(node, kind, arguments); | 198 visitor.error(node, kind, arguments); |
| 181 } | 199 } |
| 182 | 200 |
| 183 warning(Node node, MessageKind kind, [arguments = const []]) { | 201 warning(Node node, MessageKind kind, [arguments = const []]) { |
| 184 visitor.warning(node, kind, arguments); | 202 visitor.warning(node, kind, arguments); |
| 185 } | 203 } |
| 186 | 204 |
| 187 bool isFieldInitializer(SendSet node) { | 205 bool isFieldInitializer(SendSet node) { |
| 188 if (node.selector.asIdentifier() == null) return false; | 206 if (node.selector.asIdentifier() == null) return false; |
| 189 if (node.receiver == null) return true; | 207 if (node.receiver == null) return true; |
| 190 if (node.receiver.asIdentifier() == null) return false; | 208 if (node.receiver.asIdentifier() == null) return false; |
| 191 return node.receiver.asIdentifier().isThis(); | 209 return node.receiver.asIdentifier().isThis(); |
| 192 } | 210 } |
| 193 | 211 |
| 194 void resolveFieldInitializer(SendSet init) { | 212 void resolveFieldInitializer(FunctionElement constructor, SendSet init) { |
| 195 // init is of the form [this.]field = value. | 213 // init is of the form [this.]field = value. |
| 196 final Node selector = init.selector; | 214 final Node selector = init.selector; |
| 197 final SourceString name = selector.asIdentifier().source; | 215 final SourceString name = selector.asIdentifier().source; |
| 198 // Lookup target field. | 216 // Lookup target field. |
| 199 Element target; | 217 Element target; |
| 200 if (isFieldInitializer(init)) { | 218 if (isFieldInitializer(init)) { |
| 201 final ClassElement classElement = constructor.enclosingElement; | 219 final ClassElement classElement = constructor.enclosingElement; |
| 202 target = classElement.lookupLocalMember(name); | 220 target = classElement.lookupLocalMember(name); |
| 203 if (target === null) { | 221 if (target === null) { |
| 204 error(selector, MessageKind.CANNOT_RESOLVE, [name]); | 222 error(selector, MessageKind.CANNOT_RESOLVE, [name]); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 222 } | 240 } |
| 223 | 241 |
| 224 SourceString getConstructorName(Send node) { | 242 SourceString getConstructorName(Send node) { |
| 225 if (node.receiver !== null) { | 243 if (node.receiver !== null) { |
| 226 return node.selector.asIdentifier().source; | 244 return node.selector.asIdentifier().source; |
| 227 } else { | 245 } else { |
| 228 return const SourceString(''); | 246 return const SourceString(''); |
| 229 } | 247 } |
| 230 } | 248 } |
| 231 | 249 |
| 232 void resolveSuperOrThis(Send call) { | 250 Element resolveSuperOrThis(FunctionElement constructor, |
| 251 FunctionExpression functionNode, | |
| 252 Send call) { | |
| 233 noConstructor(e) { | 253 noConstructor(e) { |
| 234 if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]); | 254 if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]); |
| 235 } | 255 } |
| 236 | 256 |
| 237 ClassElement lookupTarget = constructor.enclosingElement; | 257 ClassElement lookupTarget = constructor.enclosingElement; |
| 238 bool validTarget = true; | 258 bool validTarget = true; |
| 259 FunctionElement result; | |
| 239 if (Initializers.isSuperConstructorCall(call)) { | 260 if (Initializers.isSuperConstructorCall(call)) { |
| 240 // Check for invalid initializers. | 261 // Check for invalid initializers. |
| 241 if (hasSuper) { | 262 if (hasSuper) { |
| 242 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER); | 263 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER); |
| 243 } | 264 } |
| 244 hasSuper = true; | 265 hasSuper = true; |
| 245 // Calculate correct lookup target and constructor name. | 266 // Calculate correct lookup target and constructor name. |
| 246 if (lookupTarget.name == Types.OBJECT) { | 267 if (lookupTarget.name == Types.OBJECT) { |
| 247 error(call, MessageKind.SUPER_INITIALIZER_IN_OBJECT); | 268 error(call, MessageKind.SUPER_INITIALIZER_IN_OBJECT); |
| 248 } else { | 269 } else { |
| 249 lookupTarget = lookupTarget.supertype.element; | 270 lookupTarget = lookupTarget.supertype.element; |
| 250 } | 271 } |
| 251 } else if (Initializers.isConstructorRedirect(call)) { | 272 } else if (Initializers.isConstructorRedirect(call)) { |
| 273 // Check that there is no body (Language specification 7.5.1). | |
| 274 if (functionNode.hasBody()) { | |
| 275 error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY); | |
| 276 } | |
| 252 // Check that there are no other initializers. | 277 // Check that there are no other initializers. |
| 253 if (!initializers.tail.isEmpty()) { | 278 if (!initializers.tail.isEmpty()) { |
| 254 error(call, MessageKind.REDIRECTING_CTOR_HAS_INITIALIZER); | 279 error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER); |
| 255 } | 280 } |
| 256 } else { | 281 } else { |
| 257 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); | 282 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); |
| 258 validTarget = false; | 283 validTarget = false; |
| 259 } | 284 } |
| 260 | 285 |
| 261 if (validTarget) { | 286 if (validTarget) { |
| 262 final SourceString className = lookupTarget.name; | 287 final SourceString className = lookupTarget.name; |
| 263 final SourceString constructorName = getConstructorName(call); | 288 final SourceString constructorName = getConstructorName(call); |
| 264 FunctionElement target = | 289 result = lookupTarget.lookupConstructor(className, constructorName, |
| 265 lookupTarget.lookupConstructor(className, constructorName, | |
| 266 noConstructor); | 290 noConstructor); |
|
floitsch
2012/02/14 16:38:02
indendation
karlklose
2012/02/15 13:10:35
Done.
| |
| 267 if (target === null && call.arguments.isEmpty()) { | 291 if (result === null && call.arguments.isEmpty()) { |
| 268 target = lookupTarget.getSynthesizedConstructor(); | 292 result = lookupTarget.getSynthesizedConstructor(); |
| 269 } | 293 } |
| 270 if (target === null) { | 294 if (result === null) { |
| 271 String name = (constructorName === const SourceString('')) | 295 String name = (constructorName === const SourceString('')) |
| 272 ? className.stringValue | 296 ? className.stringValue |
| 273 : "$className.$constructorName"; | 297 : "$className.$constructorName"; |
| 274 error(call, MessageKind.CANNOT_RESOLVE_CONSTRUCTOR, [name]); | 298 error(call, MessageKind.CANNOT_RESOLVE_CONSTRUCTOR, [name]); |
| 275 } else { | 299 } else { |
| 276 final Compiler compiler = visitor.compiler; | 300 final Compiler compiler = visitor.compiler; |
| 277 // TODO(karlklose): support optional arguments. | 301 // TODO(karlklose): support optional arguments. |
| 278 if (target.parameterCount(compiler) != call.argumentCount()) { | 302 if (result.parameterCount(compiler) != call.argumentCount()) { |
| 279 error(call, MessageKind.NO_MATCHING_CONSTRUCTOR); | 303 error(call, MessageKind.NO_MATCHING_CONSTRUCTOR); |
| 280 } | 304 } |
| 281 } | 305 } |
| 282 visitor.useElement(call, target); | 306 visitor.useElement(call, result); |
| 283 } | 307 } |
| 284 // Resolve the arguments of the call. | 308 // Resolve the arguments of the call. |
| 285 for (Link<Node> arguments = call.arguments; | 309 for (Link<Node> arguments = call.arguments; |
| 286 !arguments.isEmpty(); | 310 !arguments.isEmpty(); |
| 287 arguments = arguments.tail) { | 311 arguments = arguments.tail) { |
| 288 visitor.visitInStaticContext(arguments.head); | 312 visitor.visitInStaticContext(arguments.head); |
| 289 } | 313 } |
| 314 return result; | |
| 290 } | 315 } |
| 291 | 316 |
| 292 void resolveInitializers(FunctionExpression node) { | 317 FunctionElement resolveRedirection(FunctionElement constructor, |
| 293 if (node.initializers === null) return; | 318 FunctionExpression functionNode) { |
| 294 initializers = node.initializers.nodes; | 319 if (functionNode.initializers === null) return null; |
| 295 Compiler compiler = visitor.compiler; | 320 Link<Node> link = functionNode.initializers.nodes; |
| 321 if (!link.isEmpty() && Initializers.isConstructorRedirect(link.head)) { | |
| 322 return resolveSuperOrThis(constructor, functionNode, link.head); | |
| 323 } | |
| 324 return null; | |
| 325 } | |
| 326 | |
| 327 /** | |
| 328 * Resolve all initializers of this constructor. In the case of a redirecting | |
| 329 * constructor, the resolved constructor's function element is returned. | |
| 330 */ | |
| 331 FunctionElement resolveInitializers(FunctionElement constructor, | |
| 332 FunctionExpression functionNode) { | |
| 333 if (functionNode.initializers === null) return null; | |
| 334 initializers = functionNode.initializers.nodes; | |
| 335 FunctionElement result; | |
| 296 for (Link<Node> link = initializers; | 336 for (Link<Node> link = initializers; |
| 297 !link.isEmpty(); | 337 !link.isEmpty(); |
| 298 link = link.tail) { | 338 link = link.tail) { |
| 299 if (link.head.asSendSet() != null) { | 339 if (link.head.asSendSet() != null) { |
| 300 final SendSet init = link.head.asSendSet(); | 340 final SendSet init = link.head.asSendSet(); |
| 301 resolveFieldInitializer(init); | 341 resolveFieldInitializer(constructor, init); |
| 302 } else if (link.head.asSend() !== null) { | 342 } else if (link.head.asSend() !== null) { |
| 303 final Send call = link.head.asSend(); | 343 final Send call = link.head.asSend(); |
| 304 resolveSuperOrThis(call); | 344 result = resolveSuperOrThis(constructor, functionNode, call); |
| 305 } else { | 345 } else { |
| 306 visitor.compiler.cancel('internal error: invalid initializer', | 346 visitor.compiler.cancel('internal error: invalid initializer', |
|
floitsch
2012/02/14 16:38:02
This is not an internal error. The parser accepts
karlklose
2012/02/15 13:10:35
Done.
| |
| 307 node: link.head); | 347 node: link.head); |
| 308 } | 348 } |
| 309 } | 349 } |
| 350 return result; | |
| 310 } | 351 } |
| 311 } | 352 } |
| 312 | 353 |
| 313 class CommonResolverVisitor<R> extends AbstractVisitor<Element> { | 354 class CommonResolverVisitor<R> extends AbstractVisitor<R> { |
| 314 final Compiler compiler; | 355 final Compiler compiler; |
| 315 | 356 |
| 316 CommonResolverVisitor(Compiler this.compiler); | 357 CommonResolverVisitor(Compiler this.compiler); |
| 317 | 358 |
| 318 R visitNode(Node node) { | 359 R visitNode(Node node) { |
| 319 cancel(node, 'internal error'); | 360 cancel(node, 'internal error'); |
| 320 } | 361 } |
| 321 | 362 |
| 322 /** Convenience method for visiting nodes that may be null. */ | 363 /** Convenience method for visiting nodes that may be null. */ |
| 323 R visit(Node node) => (node == null) ? null : node.accept(this); | 364 R visit(Node node) => (node == null) ? null : node.accept(this); |
| 324 | 365 |
| 325 void error(Node node, MessageKind kind, [arguments = const []]) { | 366 void error(Node node, MessageKind kind, [arguments = const []]) { |
| 326 ResolutionError error = new ResolutionError(kind, arguments); | 367 ResolutionError message = new ResolutionError(kind, arguments); |
| 327 compiler.reportError(node, error); | 368 compiler.reportError(node, message); |
| 328 } | 369 } |
| 329 | 370 |
| 330 void warning(Node node, MessageKind kind, [arguments = const []]) { | 371 void warning(Node node, MessageKind kind, [arguments = const []]) { |
| 331 ResolutionWarning warning = new ResolutionWarning(kind, arguments); | 372 ResolutionWarning message = new ResolutionWarning(kind, arguments); |
| 332 compiler.reportWarning(node, warning); | 373 compiler.reportWarning(node, message); |
| 333 } | 374 } |
| 334 | 375 |
| 335 void cancel(Node node, String message) { | 376 void cancel(Node node, String message) { |
| 336 compiler.cancel(message, node: node); | 377 compiler.cancel(message, node: node); |
| 337 } | 378 } |
| 338 | 379 |
| 339 void internalError(Node node, String message) { | 380 void internalError(Node node, String message) { |
| 340 compiler.internalError(message, node: node); | 381 compiler.internalError(message, node: node); |
| 341 } | 382 } |
| 342 | 383 |
| (...skipping 807 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1150 class TopScope extends Scope { | 1191 class TopScope extends Scope { |
| 1151 LibraryElement get library() => element; | 1192 LibraryElement get library() => element; |
| 1152 | 1193 |
| 1153 TopScope(LibraryElement library) : super(null, library); | 1194 TopScope(LibraryElement library) : super(null, library); |
| 1154 Element lookup(SourceString name) => library.find(name); | 1195 Element lookup(SourceString name) => library.find(name); |
| 1155 | 1196 |
| 1156 Element add(Element element) { | 1197 Element add(Element element) { |
| 1157 throw "Cannot add an element in the top scope"; | 1198 throw "Cannot add an element in the top scope"; |
| 1158 } | 1199 } |
| 1159 } | 1200 } |
| OLD | NEW |