| 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 #library("closureToClassMapper"); | 5 #library("closureToClassMapper"); |
| 6 | 6 |
| 7 #import("elements/elements.dart"); | 7 #import("elements/elements.dart"); |
| 8 #import("leg.dart"); | 8 #import("leg.dart"); |
| 9 #import("scanner/scannerlib.dart"); | 9 #import("scanner/scannerlib.dart"); |
| 10 #import("tree/tree.dart"); | 10 #import("tree/tree.dart"); |
| 11 #import("util/util.dart"); | 11 #import("util/util.dart"); |
| 12 | 12 |
| 13 class ClosureTask extends CompilerTask { | 13 class ClosureTask extends CompilerTask { |
| 14 Map<Node, ClosureClassMap> closureMappingCache; | 14 Map<Node, ClosureClassMap> closureMappingCache; |
| 15 ClosureTask(Compiler compiler) | 15 ClosureTask(Compiler compiler) |
| 16 : closureMappingCache = new Map<Node, ClosureClassMap>(), | 16 : closureMappingCache = new Map<Node, ClosureClassMap>(), |
| 17 super(compiler); | 17 super(compiler); |
| 18 | 18 |
| 19 String get name => "Closure Simplifier"; | 19 String get name => "Closure Simplifier"; |
| 20 | 20 |
| 21 ClosureClassMap computeClosureToClassMapping(Element element, | 21 ClosureClassMap computeClosureToClassMapping(FunctionExpression node, |
| 22 Expression node, | |
| 23 TreeElements elements) { | 22 TreeElements elements) { |
| 24 return measure(() { | 23 return measure(() { |
| 25 ClosureClassMap cached = closureMappingCache[node]; | 24 ClosureClassMap cached = closureMappingCache[node]; |
| 26 if (cached !== null) return cached; | 25 if (cached !== null) return cached; |
| 27 | 26 |
| 28 ClosureTranslator translator = | 27 ClosureTranslator translator = |
| 29 new ClosureTranslator(compiler, elements, closureMappingCache); | 28 new ClosureTranslator(compiler, elements, closureMappingCache); |
| 30 | |
| 31 // The translator will store the computed closure-mappings inside the | 29 // The translator will store the computed closure-mappings inside the |
| 32 // cache. One for given node and one for each nested closure. | 30 // cache. One for given method and one for each nested closure. |
| 33 if (node is FunctionExpression) { | 31 translator.translate(node); |
| 34 translator.translateFunction(element, node); | |
| 35 } else { | |
| 36 // Must be the lazy initializer of a static. | |
| 37 assert(node is SendSet); | |
| 38 translator.translateLazyInitializer(element, node); | |
| 39 } | |
| 40 assert(closureMappingCache[node] != null); | 32 assert(closureMappingCache[node] != null); |
| 41 return closureMappingCache[node]; | 33 return closureMappingCache[node]; |
| 42 }); | 34 }); |
| 43 } | 35 } |
| 44 | 36 |
| 45 ClosureClassMap getMappingForNestedFunction(FunctionExpression node) { | 37 ClosureClassMap getMappingForNestedFunction(FunctionExpression node) { |
| 46 return measure(() { | 38 return measure(() { |
| 47 ClosureClassMap nestedClosureData = closureMappingCache[node]; | 39 ClosureClassMap nestedClosureData = closureMappingCache[node]; |
| 48 if (nestedClosureData === null) { | 40 if (nestedClosureData === null) { |
| 49 // TODO(floitsch): we can only assume that the reason for not having a | 41 // TODO(floitsch): we can only assume that the reason for not having a |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 List<Element> boxedLoopVariables; | 106 List<Element> boxedLoopVariables; |
| 115 | 107 |
| 116 ClosureScope(this.boxElement, this.capturedVariableMapping) | 108 ClosureScope(this.boxElement, this.capturedVariableMapping) |
| 117 : boxedLoopVariables = const <Element>[]; | 109 : boxedLoopVariables = const <Element>[]; |
| 118 | 110 |
| 119 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty(); | 111 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty(); |
| 120 } | 112 } |
| 121 | 113 |
| 122 class ClosureClassMap { | 114 class ClosureClassMap { |
| 123 // The closure's element before any translation. Will be null for methods. | 115 // The closure's element before any translation. Will be null for methods. |
| 124 final Element closureElement; | 116 final FunctionElement closureElement; |
| 125 // The closureClassElement will be null for methods that are not local | 117 // The closureClassElement will be null for methods that are not local |
| 126 // closures. | 118 // closures. |
| 127 final ClassElement closureClassElement; | 119 final ClassElement closureClassElement; |
| 128 // The callElement will be null for methods that are not local closures. | 120 // The callElement will be null for methods that are not local closures. |
| 129 final FunctionElement callElement; | 121 final FunctionElement callElement; |
| 130 // The [thisElement] makes handling 'this' easier by treating it like any | 122 // The [thisElement] makes handling 'this' easier by treating it like any |
| 131 // other argument. It is only set for instance-members. | 123 // other argument. It is only set for instance-members. |
| 132 final ThisElement thisElement; | 124 final ThisElement thisElement; |
| 133 | 125 |
| 134 // Maps free locals, arguments and function elements to their captured | 126 // Maps free locals, arguments and function elements to their captured |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 final TreeElements elements; | 163 final TreeElements elements; |
| 172 int closureFieldCounter = 0; | 164 int closureFieldCounter = 0; |
| 173 bool inTryStatement = false; | 165 bool inTryStatement = false; |
| 174 final Map<Node, ClosureClassMap> closureMappingCache; | 166 final Map<Node, ClosureClassMap> closureMappingCache; |
| 175 | 167 |
| 176 // Map of captured variables. Initially they will map to themselves. If | 168 // Map of captured variables. Initially they will map to themselves. If |
| 177 // a variable needs to be boxed then the scope declaring the variable | 169 // a variable needs to be boxed then the scope declaring the variable |
| 178 // will update this mapping. | 170 // will update this mapping. |
| 179 Map<Element, Element> capturedVariableMapping; | 171 Map<Element, Element> capturedVariableMapping; |
| 180 // List of encountered closures. | 172 // List of encountered closures. |
| 181 List<Expression> closures; | 173 List<FunctionExpression> closures; |
| 182 | 174 |
| 183 // The variables that have been declared in the current scope. | 175 // The variables that have been declared in the current scope. |
| 184 List<Element> scopeVariables; | 176 List<Element> scopeVariables; |
| 185 | 177 |
| 186 // Keep track of the mutated variables so that we don't need to box | 178 // Keep track of the mutated variables so that we don't need to box |
| 187 // non-mutated variables. | 179 // non-mutated variables. |
| 188 Set<Element> mutatedVariables; | 180 Set<Element> mutatedVariables; |
| 189 | 181 |
| 190 Element outermostElement; | 182 FunctionElement outermostFunctionElement; |
| 191 Element currentElement; | 183 FunctionElement currentFunctionElement; |
| 192 | 184 |
| 193 // The closureData of the currentFunctionElement. | 185 // The closureData of the currentFunctionElement. |
| 194 ClosureClassMap closureData; | 186 ClosureClassMap closureData; |
| 195 | 187 |
| 196 bool insideClosure = false; | 188 bool insideClosure = false; |
| 197 | 189 |
| 198 ClosureTranslator(this.compiler, this.elements, this.closureMappingCache) | 190 ClosureTranslator(this.compiler, this.elements, this.closureMappingCache) |
| 199 : capturedVariableMapping = new Map<Element, Element>(), | 191 : capturedVariableMapping = new Map<Element, Element>(), |
| 200 closures = <Expression>[], | 192 closures = <FunctionExpression>[], |
| 201 mutatedVariables = new Set<Element>(); | 193 mutatedVariables = new Set<Element>(); |
| 202 | 194 |
| 203 void translateFunction(Element element, FunctionExpression node) { | 195 void translate(Node node) { |
| 204 // For constructors the [element] and the [:elements[node]:] may differ. | 196 visit(node); |
| 205 // The [:elements[node]:] always points to the generative-constructor | |
| 206 // element, whereas the [element] might be the constructor-body element. | |
| 207 visit(node); // [visitFunctionExpression] will call [visitInvokable]. | |
| 208 // When variables need to be boxed their [capturedVariableMapping] is | 197 // When variables need to be boxed their [capturedVariableMapping] is |
| 209 // updated, but we delay updating the similar freeVariableMapping in the | 198 // updated, but we delay updating the similar freeVariableMapping in the |
| 210 // closure datas that capture these variables. | 199 // closure datas that capture these variables. |
| 211 // The closures don't have their fields (in the closure class) set, either. | 200 // The closures don't have their fields (in the closure class) set, either. |
| 212 updateClosures(); | 201 updateClosures(); |
| 213 } | 202 } |
| 214 | 203 |
| 215 void translateLazyInitializer(Element element, SendSet node) { | |
| 216 assert(node.assignmentOperator.source == const SourceString("=")); | |
| 217 Expression initialValue = node.argumentsNode.nodes.head; | |
| 218 visitInvokable(element, node, () { visit(initialValue); }); | |
| 219 updateClosures(); | |
| 220 } | |
| 221 | |
| 222 // This function runs through all of the existing closures and updates their | 204 // This function runs through all of the existing closures and updates their |
| 223 // free variables to the boxed value. It also adds the field-elements to the | 205 // free variables to the boxed value. It also adds the field-elements to the |
| 224 // class representing the closure. At the same time it fills the | 206 // class representing the closure. At the same time it fills the |
| 225 // [capturedFieldMapping]. | 207 // [capturedFieldMapping]. |
| 226 void updateClosures() { | 208 void updateClosures() { |
| 227 for (Expression closure in closures) { | 209 for (FunctionExpression closure in closures) { |
| 228 // The captured variables that need to be stored in a field of the closure | 210 // The captured variables that need to be stored in a field of the closure |
| 229 // class. | 211 // class. |
| 230 Set<Element> fieldCaptures = new Set<Element>(); | 212 Set<Element> fieldCaptures = new Set<Element>(); |
| 231 ClosureClassMap data = closureMappingCache[closure]; | 213 ClosureClassMap data = closureMappingCache[closure]; |
| 232 Map<Element, Element> freeVariableMapping = data.freeVariableMapping; | 214 Map<Element, Element> freeVariableMapping = data.freeVariableMapping; |
| 233 // We get a copy of the keys and iterate over it, to avoid modifications | 215 // We get a copy of the keys and iterate over it, to avoid modifications |
| 234 // to the map while iterating over it. | 216 // to the map while iterating over it. |
| 235 freeVariableMapping.getKeys().forEach((Element fromElement) { | 217 freeVariableMapping.getKeys().forEach((Element fromElement) { |
| 236 assert(fromElement == freeVariableMapping[fromElement]); | 218 assert(fromElement == freeVariableMapping[fromElement]); |
| 237 Element updatedElement = capturedVariableMapping[fromElement]; | 219 Element updatedElement = capturedVariableMapping[fromElement]; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 } | 253 } |
| 272 | 254 |
| 273 void useLocal(Element element) { | 255 void useLocal(Element element) { |
| 274 // If the element is not declared in the current function and the element | 256 // If the element is not declared in the current function and the element |
| 275 // is not the closure itself we need to mark the element as free variable. | 257 // is not the closure itself we need to mark the element as free variable. |
| 276 // Note that the check on [insideClosure] is not just an | 258 // Note that the check on [insideClosure] is not just an |
| 277 // optimization: factories have type parameters as function | 259 // optimization: factories have type parameters as function |
| 278 // parameters, and type parameters are declared in the class, not | 260 // parameters, and type parameters are declared in the class, not |
| 279 // the factory. | 261 // the factory. |
| 280 if (insideClosure && | 262 if (insideClosure && |
| 281 element.enclosingElement != currentElement && | 263 element.enclosingElement != currentFunctionElement && |
| 282 element != currentElement) { | 264 element != currentFunctionElement) { |
| 283 assert(closureData.freeVariableMapping[element] == null || | 265 assert(closureData.freeVariableMapping[element] == null || |
| 284 closureData.freeVariableMapping[element] == element); | 266 closureData.freeVariableMapping[element] == element); |
| 285 closureData.freeVariableMapping[element] = element; | 267 closureData.freeVariableMapping[element] = element; |
| 286 } else if (inTryStatement) { | 268 } else if (inTryStatement) { |
| 287 // Don't mark the this-element. This would complicate things in the | 269 // Don't mark the this-element. This would complicate things in the |
| 288 // builder. | 270 // builder. |
| 289 if (element != closureData.thisElement) { | 271 if (element != closureData.thisElement) { |
| 290 // TODO(ngeoffray): only do this if the variable is mutated. | 272 // TODO(ngeoffray): only do this if the variable is mutated. |
| 291 closureData.usedVariablesInTry.add(element); | 273 closureData.usedVariablesInTry.add(element); |
| 292 } | 274 } |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 384 void analyzeTypeVariables(DartType type) { | 366 void analyzeTypeVariables(DartType type) { |
| 385 if (type is TypeVariableType) { | 367 if (type is TypeVariableType) { |
| 386 useLocal(type.element); | 368 useLocal(type.element); |
| 387 } else if (type is InterfaceType) { | 369 } else if (type is InterfaceType) { |
| 388 InterfaceType ifcType = type; | 370 InterfaceType ifcType = type; |
| 389 for (DartType argument in ifcType.arguments) { | 371 for (DartType argument in ifcType.arguments) { |
| 390 analyzeTypeVariables(argument); | 372 analyzeTypeVariables(argument); |
| 391 } | 373 } |
| 392 } | 374 } |
| 393 } | 375 } |
| 394 if (outermostElement.isMember() && | 376 if (outermostFunctionElement.isMember() && |
| 395 compiler.world.needsRti(outermostElement.getEnclosingClass())) { | 377 compiler.world.needsRti(outermostFunctionElement.getEnclosingClass())) { |
| 396 if (outermostElement.isInstanceMember() | 378 if (outermostFunctionElement.isInstanceMember() |
| 397 || outermostElement.isGenerativeConstructor()) { | 379 || outermostFunctionElement.isGenerativeConstructor()) { |
| 398 if (hasTypeVariable(type)) useLocal(closureData.thisElement); | 380 if (hasTypeVariable(type)) useLocal(closureData.thisElement); |
| 399 } else if (outermostElement.isFactoryConstructor()) { | 381 } else if (outermostFunctionElement.isFactoryConstructor()) { |
| 400 analyzeTypeVariables(type); | 382 analyzeTypeVariables(type); |
| 401 } | 383 } |
| 402 } | 384 } |
| 403 | 385 |
| 404 node.visitChildren(this); | 386 node.visitChildren(this); |
| 405 } | 387 } |
| 406 | 388 |
| 407 // If variables that are declared in the [node] scope are captured and need | 389 // If variables that are declared in the [node] scope are captured and need |
| 408 // to be boxed create a box-element and update the [capturingScopes] in the | 390 // to be boxed create a box-element and update the [capturingScopes] in the |
| 409 // current [closureData]. | 391 // current [closureData]. |
| 410 // The boxed variables are updated in the [capturedVariableMapping]. | 392 // The boxed variables are updated in the [capturedVariableMapping]. |
| 411 void attachCapturedScopeVariables(Node node) { | 393 void attachCapturedScopeVariables(Node node) { |
| 412 Element box = null; | 394 Element box = null; |
| 413 Map<Element, Element> scopeMapping = new Map<Element, Element>(); | 395 Map<Element, Element> scopeMapping = new Map<Element, Element>(); |
| 414 for (Element element in scopeVariables) { | 396 for (Element element in scopeVariables) { |
| 415 // No need to box non-assignable elements. | 397 // No need to box non-assignable elements. |
| 416 if (!element.isAssignable()) continue; | 398 if (!element.isAssignable()) continue; |
| 417 if (!mutatedVariables.contains(element)) continue; | 399 if (!mutatedVariables.contains(element)) continue; |
| 418 if (capturedVariableMapping.containsKey(element)) { | 400 if (capturedVariableMapping.containsKey(element)) { |
| 419 if (box == null) { | 401 if (box == null) { |
| 420 // TODO(floitsch): construct better box names. | 402 // TODO(floitsch): construct better box names. |
| 421 SourceString boxName = | 403 SourceString boxName = |
| 422 new SourceString("box_${closureFieldCounter++}"); | 404 new SourceString("box_${closureFieldCounter++}"); |
| 423 box = new BoxElement(boxName, currentElement); | 405 box = new BoxElement(boxName, currentFunctionElement); |
| 424 } | 406 } |
| 425 // TODO(floitsch): construct better boxed names. | 407 // TODO(floitsch): construct better boxed names. |
| 426 String elementName = element.name.slowToString(); | 408 String elementName = element.name.slowToString(); |
| 427 // We are currently using the name in an HForeign which could replace | 409 // We are currently using the name in an HForeign which could replace |
| 428 // "$X" with something else. | 410 // "$X" with something else. |
| 429 String escaped = elementName.replaceAll("\$", "_"); | 411 String escaped = elementName.replaceAll("\$", "_"); |
| 430 SourceString boxedName = | 412 SourceString boxedName = |
| 431 new SourceString("${escaped}_${closureFieldCounter++}"); | 413 new SourceString("${escaped}_${closureFieldCounter++}"); |
| 432 Element boxed = new Element(boxedName, ElementKind.FIELD, box); | 414 Element boxed = new Element(boxedName, ElementKind.FIELD, box); |
| 433 scopeMapping[element] = boxed; | 415 scopeMapping[element] = boxed; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 globalizedElement); | 502 globalizedElement); |
| 521 globalizedElement.backendMembers = | 503 globalizedElement.backendMembers = |
| 522 const EmptyLink<Element>().prepend(callElement); | 504 const EmptyLink<Element>().prepend(callElement); |
| 523 // The nested function's 'this' is the same as the one for the outer | 505 // The nested function's 'this' is the same as the one for the outer |
| 524 // function. It could be [null] if we are inside a static method. | 506 // function. It could be [null] if we are inside a static method. |
| 525 Element thisElement = closureData.thisElement; | 507 Element thisElement = closureData.thisElement; |
| 526 return new ClosureClassMap(element, globalizedElement, | 508 return new ClosureClassMap(element, globalizedElement, |
| 527 callElement, thisElement); | 509 callElement, thisElement); |
| 528 } | 510 } |
| 529 | 511 |
| 530 void visitInvokable(Element element, Expression node, void visitChildren()) { | 512 visitFunctionExpression(FunctionExpression node) { |
| 513 Element element = elements[node]; |
| 514 if (element.isParameter()) { |
| 515 // TODO(ahe): This is a hack. This method should *not* call |
| 516 // visitChildren. |
| 517 return node.name.accept(this); |
| 518 } |
| 519 |
| 531 bool oldInsideClosure = insideClosure; | 520 bool oldInsideClosure = insideClosure; |
| 532 Element oldFunctionElement = currentElement; | 521 FunctionElement oldFunctionElement = currentFunctionElement; |
| 533 ClosureClassMap oldClosureData = closureData; | 522 ClosureClassMap oldClosureData = closureData; |
| 534 | 523 |
| 535 insideClosure = outermostElement != null; | 524 insideClosure = outermostFunctionElement != null; |
| 536 currentElement = element; | 525 currentFunctionElement = element; |
| 537 if (insideClosure) { | 526 if (insideClosure) { |
| 538 closures.add(node); | 527 closures.add(node); |
| 539 closureData = globalizeClosure(node, element); | 528 closureData = globalizeClosure(node, element); |
| 540 } else { | 529 } else { |
| 541 outermostElement = element; | 530 outermostFunctionElement = element; |
| 542 Element thisElement = null; | 531 Element thisElement = null; |
| 543 if (element.isInstanceMember() || element.isGenerativeConstructor()) { | 532 if (element.isInstanceMember() || element.isGenerativeConstructor()) { |
| 544 thisElement = new ThisElement(element); | 533 thisElement = new ThisElement(element); |
| 545 } | 534 } |
| 546 closureData = new ClosureClassMap(null, null, null, thisElement); | 535 closureData = new ClosureClassMap(null, null, null, thisElement); |
| 547 } | 536 } |
| 548 closureMappingCache[node] = closureData; | 537 closureMappingCache[node] = closureData; |
| 549 | 538 |
| 550 inNewScope(node, () { | 539 inNewScope(node, () { |
| 551 // We have to declare the implicit 'this' parameter. | 540 // We have to declare the implicit 'this' parameter. |
| 552 if (!insideClosure && closureData.thisElement !== null) { | 541 if (!insideClosure && closureData.thisElement !== null) { |
| 553 declareLocal(closureData.thisElement); | 542 declareLocal(closureData.thisElement); |
| 554 } | 543 } |
| 555 // If we are inside a named closure we have to declare ourselve. For | 544 // If we are inside a named closure we have to declare ourselve. For |
| 556 // simplicity we declare the local even if the closure does not have a | 545 // simplicity we declare the local even if the closure does not have a |
| 557 // name. | 546 // name. |
| 558 // It will simply not be used. | 547 // It will simply not be used. |
| 559 if (insideClosure) { | 548 if (insideClosure) { |
| 560 declareLocal(element); | 549 declareLocal(element); |
| 561 } | 550 } |
| 562 | 551 |
| 563 if (currentElement.isFactoryConstructor() | 552 if (currentFunctionElement.isFactoryConstructor() |
| 564 && compiler.world.needsRti(currentElement.enclosingElement)) { | 553 && compiler.world.needsRti(currentFunctionElement.enclosingElement)) { |
| 565 // Declare the type parameters in the scope. Generative | 554 // Declare the type parameters in the scope. Generative |
| 566 // constructors just use 'this'. | 555 // constructors just use 'this'. |
| 567 ClassElement cls = currentElement.enclosingElement; | 556 ClassElement cls = currentFunctionElement.enclosingElement; |
| 568 cls.typeVariables.forEach((TypeVariableType typeVariable) { | 557 cls.typeVariables.forEach((TypeVariableType typeVariable) { |
| 569 declareLocal(typeVariable.element); | 558 declareLocal(typeVariable.element); |
| 570 }); | 559 }); |
| 571 } | 560 } |
| 572 | 561 |
| 573 visitChildren(); | 562 // TODO(ahe): This is problematic. The backend should not repeat |
| 563 // the work of the resolver. It is the resolver's job to create |
| 564 // parameters, etc. Other phases should only visit statements. |
| 565 // TODO(floitsch): we avoid visiting the initializers on purpose so that |
| 566 // we get an error-message later in the builder. |
| 567 if (node.parameters !== null) node.parameters.accept(this); |
| 568 if (node.body !== null) node.body.accept(this); |
| 574 }); | 569 }); |
| 575 | 570 |
| 576 | 571 |
| 577 ClosureClassMap savedClosureData = closureData; | 572 ClosureClassMap savedClosureData = closureData; |
| 578 bool savedInsideClosure = insideClosure; | 573 bool savedInsideClosure = insideClosure; |
| 579 | 574 |
| 580 // Restore old values. | 575 // Restore old values. |
| 581 insideClosure = oldInsideClosure; | 576 insideClosure = oldInsideClosure; |
| 582 closureData = oldClosureData; | 577 closureData = oldClosureData; |
| 583 currentElement = oldFunctionElement; | 578 currentFunctionElement = oldFunctionElement; |
| 584 | 579 |
| 585 // Mark all free variables as captured and use them in the outer function. | 580 // Mark all free variables as captured and use them in the outer function. |
| 586 List<Element> freeVariables = | 581 List<Element> freeVariables = |
| 587 savedClosureData.freeVariableMapping.getKeys(); | 582 savedClosureData.freeVariableMapping.getKeys(); |
| 588 assert(freeVariables.isEmpty() || savedInsideClosure); | 583 assert(freeVariables.isEmpty() || savedInsideClosure); |
| 589 for (Element freeElement in freeVariables) { | 584 for (Element freeElement in freeVariables) { |
| 590 if (capturedVariableMapping[freeElement] != null && | 585 if (capturedVariableMapping[freeElement] != null && |
| 591 capturedVariableMapping[freeElement] != freeElement) { | 586 capturedVariableMapping[freeElement] != freeElement) { |
| 592 compiler.internalError('In closure analyzer', node: node); | 587 compiler.internalError('In closure analyzer', node: node); |
| 593 } | 588 } |
| 594 capturedVariableMapping[freeElement] = freeElement; | 589 capturedVariableMapping[freeElement] = freeElement; |
| 595 useLocal(freeElement); | 590 useLocal(freeElement); |
| 596 } | 591 } |
| 597 } | 592 } |
| 598 | 593 |
| 599 visitFunctionExpression(FunctionExpression node) { | |
| 600 Element element = elements[node]; | |
| 601 | |
| 602 if (element.isParameter()) { | |
| 603 // TODO(ahe): This is a hack. This method should *not* call | |
| 604 // visitChildren. | |
| 605 return node.name.accept(this); | |
| 606 } | |
| 607 | |
| 608 visitInvokable(element, node, () { | |
| 609 // TODO(ahe): This is problematic. The backend should not repeat | |
| 610 // the work of the resolver. It is the resolver's job to create | |
| 611 // parameters, etc. Other phases should only visit statements. | |
| 612 // TODO(floitsch): we avoid visiting the initializers on purpose so that | |
| 613 // we get an error-message later in the builder. | |
| 614 if (node.parameters !== null) node.parameters.accept(this); | |
| 615 if (node.body !== null) node.body.accept(this); | |
| 616 }); | |
| 617 } | |
| 618 | |
| 619 visitFunctionDeclaration(FunctionDeclaration node) { | 594 visitFunctionDeclaration(FunctionDeclaration node) { |
| 620 node.visitChildren(this); | 595 node.visitChildren(this); |
| 621 declareLocal(elements[node]); | 596 declareLocal(elements[node]); |
| 622 } | 597 } |
| 623 | 598 |
| 624 visitTryStatement(TryStatement node) { | 599 visitTryStatement(TryStatement node) { |
| 625 // TODO(ngeoffray): implement finer grain state. | 600 // TODO(ngeoffray): implement finer grain state. |
| 626 bool oldInTryStatement = inTryStatement; | 601 bool oldInTryStatement = inTryStatement; |
| 627 inTryStatement = true; | 602 inTryStatement = true; |
| 628 node.visitChildren(this); | 603 node.visitChildren(this); |
| 629 inTryStatement = oldInTryStatement; | 604 inTryStatement = oldInTryStatement; |
| 630 } | 605 } |
| 631 } | 606 } |
| OLD | NEW |