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