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