| 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 "dart2jslib.dart"; | 8 import "dart2jslib.dart"; |
| 9 import "dart_types.dart"; | 9 import "dart_types.dart"; |
| 10 import "scanner/scannerlib.dart" show Token; | 10 import "scanner/scannerlib.dart" show Token; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 new ClosureTranslator(compiler, elements, closureMappingCache, namer); | 40 new ClosureTranslator(compiler, elements, closureMappingCache, namer); |
| 41 | 41 |
| 42 // The translator will store the computed closure-mappings inside the | 42 // The translator will store the computed closure-mappings inside the |
| 43 // cache. One for given node and one for each nested closure. | 43 // cache. One for given node and one for each nested closure. |
| 44 if (node is FunctionExpression) { | 44 if (node is FunctionExpression) { |
| 45 translator.translateFunction(element, node); | 45 translator.translateFunction(element, node); |
| 46 } else if (element.isSynthesized) { | 46 } else if (element.isSynthesized) { |
| 47 return new ClosureClassMap(null, null, null, | 47 return new ClosureClassMap(null, null, null, |
| 48 new ThisElement(element, compiler.types.dynamicType)); | 48 new ThisElement(element, compiler.types.dynamicType)); |
| 49 } else { | 49 } else { |
| 50 assert(element.isField()); | 50 assert(element.isField); |
| 51 VariableElement field = element; | 51 VariableElement field = element; |
| 52 if (field.initializer != null) { | 52 if (field.initializer != null) { |
| 53 // The lazy initializer of a static. | 53 // The lazy initializer of a static. |
| 54 translator.translateLazyInitializer(element, node, field.initializer); | 54 translator.translateLazyInitializer(element, node, field.initializer); |
| 55 } else { | 55 } else { |
| 56 assert(element.isInstanceMember()); | 56 assert(element.isInstanceMember); |
| 57 closureMappingCache[node] = | 57 closureMappingCache[node] = |
| 58 new ClosureClassMap(null, null, null, | 58 new ClosureClassMap(null, null, null, |
| 59 new ThisElement(element, compiler.types.dynamicType)); | 59 new ThisElement(element, compiler.types.dynamicType)); |
| 60 } | 60 } |
| 61 } | 61 } |
| 62 assert(closureMappingCache[node] != null); | 62 assert(closureMappingCache[node] != null); |
| 63 return closureMappingCache[node]; | 63 return closureMappingCache[node]; |
| 64 }); | 64 }); |
| 65 } | 65 } |
| 66 | 66 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 86 this.variableElement, | 86 this.variableElement, |
| 87 ClassElement enclosing) | 87 ClassElement enclosing) |
| 88 : super(name, ElementKind.FIELD, enclosing); | 88 : super(name, ElementKind.FIELD, enclosing); |
| 89 | 89 |
| 90 Expression get initializer { | 90 Expression get initializer { |
| 91 throw new SpannableAssertionFailure( | 91 throw new SpannableAssertionFailure( |
| 92 variableElement, | 92 variableElement, |
| 93 'Should not access initializer of ClosureFieldElement.'); | 93 'Should not access initializer of ClosureFieldElement.'); |
| 94 } | 94 } |
| 95 | 95 |
| 96 bool isInstanceMember() => true; | 96 bool get isInstanceMember => true; |
| 97 bool isAssignable() => false; | 97 bool get isAssignable => false; |
| 98 | 98 |
| 99 DartType computeType(Compiler compiler) { | 99 DartType computeType(Compiler compiler) { |
| 100 return variableElement.type; | 100 return variableElement.type; |
| 101 } | 101 } |
| 102 | 102 |
| 103 DartType get type => variableElement.type; | 103 DartType get type => variableElement.type; |
| 104 | 104 |
| 105 String toString() => "ClosureFieldElement($name)"; | 105 String toString() => "ClosureFieldElement($name)"; |
| 106 | 106 |
| 107 accept(ElementVisitor visitor) => visitor.visitClosureFieldElement(this); | 107 accept(ElementVisitor visitor) => visitor.visitClosureFieldElement(this); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 122 Compiler compiler, | 122 Compiler compiler, |
| 123 this.methodElement, | 123 this.methodElement, |
| 124 Element enclosingElement) | 124 Element enclosingElement) |
| 125 : super(name, | 125 : super(name, |
| 126 enclosingElement, | 126 enclosingElement, |
| 127 // By assigning a fresh class-id we make sure that the hashcode | 127 // By assigning a fresh class-id we make sure that the hashcode |
| 128 // is unique, but also emit closure classes after all other | 128 // is unique, but also emit closure classes after all other |
| 129 // classes (since the emitter sorts classes by their id). | 129 // classes (since the emitter sorts classes by their id). |
| 130 compiler.getNextFreeClassId(), | 130 compiler.getNextFreeClassId(), |
| 131 STATE_DONE) { | 131 STATE_DONE) { |
| 132 ClassElement superclass = methodElement.isInstanceMember() | 132 ClassElement superclass = methodElement.isInstanceMember |
| 133 ? compiler.boundClosureClass | 133 ? compiler.boundClosureClass |
| 134 : compiler.closureClass; | 134 : compiler.closureClass; |
| 135 superclass.ensureResolved(compiler); | 135 superclass.ensureResolved(compiler); |
| 136 supertype = superclass.thisType; | 136 supertype = superclass.thisType; |
| 137 interfaces = const Link<DartType>(); | 137 interfaces = const Link<DartType>(); |
| 138 thisType = rawType = new InterfaceType(this); | 138 thisType = rawType = new InterfaceType(this); |
| 139 allSupertypesAndSelf = | 139 allSupertypesAndSelf = |
| 140 superclass.allSupertypesAndSelf.extendClass(thisType); | 140 superclass.allSupertypesAndSelf.extendClass(thisType); |
| 141 callType = methodElement.type; | 141 callType = methodElement.type; |
| 142 } | 142 } |
| 143 | 143 |
| 144 bool isClosure() => true; | 144 bool get isClosure => true; |
| 145 | 145 |
| 146 Token position() => node.getBeginToken(); | 146 Token get position => node.getBeginToken(); |
| 147 | 147 |
| 148 Node parseNode(DiagnosticListener listener) => node; | 148 Node parseNode(DiagnosticListener listener) => node; |
| 149 | 149 |
| 150 /** | 150 /** |
| 151 * The element for the declaration of the function expression. | 151 * The element for the declaration of the function expression. |
| 152 */ | 152 */ |
| 153 final TypedElement methodElement; | 153 final TypedElement methodElement; |
| 154 | 154 |
| 155 // A [ClosureClassElement] is nested inside a function or initializer in terms | 155 // A [ClosureClassElement] is nested inside a function or initializer in terms |
| 156 // of [enclosingElement], but still has to be treated as a top-level | 156 // of [enclosingElement], but still has to be treated as a top-level |
| 157 // element. | 157 // element. |
| 158 bool isTopLevel() => true; | 158 bool get isTopLevel => true; |
| 159 | 159 |
| 160 get enclosingElement => methodElement; | 160 get enclosingElement => methodElement; |
| 161 | 161 |
| 162 accept(ElementVisitor visitor) => visitor.visitClosureClassElement(this); | 162 accept(ElementVisitor visitor) => visitor.visitClosureClassElement(this); |
| 163 } | 163 } |
| 164 | 164 |
| 165 // TODO(ahe): These classes continuously cause problems. We need to | 165 // TODO(ahe): These classes continuously cause problems. We need to |
| 166 // move these classes to elements/modelx.dart or see if we can find a | 166 // move these classes to elements/modelx.dart or see if we can find a |
| 167 // more general solution. | 167 // more general solution. |
| 168 class BoxElement extends ElementX implements TypedElement { | 168 class BoxElement extends ElementX implements TypedElement { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 196 | 196 |
| 197 // TODO(ahe): These classes continuously cause problems. We need to | 197 // TODO(ahe): These classes continuously cause problems. We need to |
| 198 // move these classes to elements/modelx.dart or see if we can find a | 198 // move these classes to elements/modelx.dart or see if we can find a |
| 199 // more general solution. | 199 // more general solution. |
| 200 class ThisElement extends ElementX implements TypedElement { | 200 class ThisElement extends ElementX implements TypedElement { |
| 201 final DartType type; | 201 final DartType type; |
| 202 | 202 |
| 203 ThisElement(Element enclosing, this.type) | 203 ThisElement(Element enclosing, this.type) |
| 204 : super('this', ElementKind.PARAMETER, enclosing); | 204 : super('this', ElementKind.PARAMETER, enclosing); |
| 205 | 205 |
| 206 bool isAssignable() => false; | 206 bool get isAssignable => false; |
| 207 | 207 |
| 208 DartType computeType(Compiler compiler) => compiler.types.dynamicType; | 208 DartType computeType(Compiler compiler) => compiler.types.dynamicType; |
| 209 | 209 |
| 210 // Since there is no declaration corresponding to 'this', use the position of | 210 // Since there is no declaration corresponding to 'this', use the position of |
| 211 // the enclosing method. | 211 // the enclosing method. |
| 212 Token position() => enclosingElement.position(); | 212 Token get position => enclosingElement.position; |
| 213 | 213 |
| 214 accept(ElementVisitor visitor) => visitor.visitThisElement(this); | 214 accept(ElementVisitor visitor) => visitor.visitThisElement(this); |
| 215 } | 215 } |
| 216 | 216 |
| 217 // The box-element for a scope, and the captured variables that need to be | 217 // The box-element for a scope, and the captured variables that need to be |
| 218 // stored in the box. | 218 // stored in the box. |
| 219 class ClosureScope { | 219 class ClosureScope { |
| 220 Element boxElement; | 220 Element boxElement; |
| 221 Map<Element, Element> capturedVariableMapping; | 221 Map<Element, Element> capturedVariableMapping; |
| 222 // If the scope is attached to a [For] contains the variables that are | 222 // If the scope is attached to a [For] contains the variables that are |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 | 262 |
| 263 ClosureClassMap(this.closureElement, | 263 ClosureClassMap(this.closureElement, |
| 264 this.closureClassElement, | 264 this.closureClassElement, |
| 265 this.callElement, | 265 this.callElement, |
| 266 this.thisElement) | 266 this.thisElement) |
| 267 : this.freeVariableMapping = new Map<Element, Element>(), | 267 : this.freeVariableMapping = new Map<Element, Element>(), |
| 268 this.capturedFieldMapping = new Map<Element, Element>(), | 268 this.capturedFieldMapping = new Map<Element, Element>(), |
| 269 this.capturingScopes = new Map<Node, ClosureScope>(), | 269 this.capturingScopes = new Map<Node, ClosureScope>(), |
| 270 this.usedVariablesInTry = new Set<Element>(); | 270 this.usedVariablesInTry = new Set<Element>(); |
| 271 | 271 |
| 272 bool isClosure() => closureElement != null; | 272 bool get isClosure => closureElement != null; |
| 273 | 273 |
| 274 bool capturingScopesBox(Element element) { | 274 bool capturingScopesBox(Element element) { |
| 275 return capturingScopes.values.any((scope) { | 275 return capturingScopes.values.any((scope) { |
| 276 return scope.boxedLoopVariables.contains(element); | 276 return scope.boxedLoopVariables.contains(element); |
| 277 }); | 277 }); |
| 278 } | 278 } |
| 279 | 279 |
| 280 bool isVariableBoxed(Element element) { | 280 bool isVariableBoxed(Element element) { |
| 281 Element copy = freeVariableMapping[element]; | 281 Element copy = freeVariableMapping[element]; |
| 282 if (copy != null && !copy.isMember()) return true; | 282 if (copy != null && !copy.isMember) return true; |
| 283 return capturingScopesBox(element); | 283 return capturingScopesBox(element); |
| 284 } | 284 } |
| 285 | 285 |
| 286 void forEachCapturedVariable(void f(Element local, Element field)) { | 286 void forEachCapturedVariable(void f(Element local, Element field)) { |
| 287 freeVariableMapping.forEach((variable, copy) { | 287 freeVariableMapping.forEach((variable, copy) { |
| 288 if (variable is BoxElement) return; | 288 if (variable is BoxElement) return; |
| 289 f(variable, copy); | 289 f(variable, copy); |
| 290 }); | 290 }); |
| 291 capturingScopes.values.forEach((scope) { | 291 capturingScopes.values.forEach((scope) { |
| 292 scope.capturedVariableMapping.forEach(f); | 292 scope.capturedVariableMapping.forEach(f); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 Map<Element, Element> freeVariableMapping = data.freeVariableMapping; | 375 Map<Element, Element> freeVariableMapping = data.freeVariableMapping; |
| 376 // We get a copy of the keys and iterate over it, to avoid modifications | 376 // We get a copy of the keys and iterate over it, to avoid modifications |
| 377 // to the map while iterating over it. | 377 // to the map while iterating over it. |
| 378 freeVariableMapping.keys.toList().forEach((Element fromElement) { | 378 freeVariableMapping.keys.toList().forEach((Element fromElement) { |
| 379 assert(fromElement == freeVariableMapping[fromElement]); | 379 assert(fromElement == freeVariableMapping[fromElement]); |
| 380 Element updatedElement = capturedVariableMapping[fromElement]; | 380 Element updatedElement = capturedVariableMapping[fromElement]; |
| 381 assert(updatedElement != null); | 381 assert(updatedElement != null); |
| 382 if (fromElement == updatedElement) { | 382 if (fromElement == updatedElement) { |
| 383 assert(freeVariableMapping[fromElement] == updatedElement); | 383 assert(freeVariableMapping[fromElement] == updatedElement); |
| 384 assert(Elements.isLocal(updatedElement) | 384 assert(Elements.isLocal(updatedElement) |
| 385 || updatedElement.isTypeVariable()); | 385 || updatedElement.isTypeVariable); |
| 386 // The variable has not been boxed. | 386 // The variable has not been boxed. |
| 387 fieldCaptures.add(updatedElement); | 387 fieldCaptures.add(updatedElement); |
| 388 } else { | 388 } else { |
| 389 // A boxed element. | 389 // A boxed element. |
| 390 freeVariableMapping[fromElement] = updatedElement; | 390 freeVariableMapping[fromElement] = updatedElement; |
| 391 Element boxElement = updatedElement.enclosingElement; | 391 Element boxElement = updatedElement.enclosingElement; |
| 392 assert(boxElement is BoxElement); | 392 assert(boxElement is BoxElement); |
| 393 boxes.add(boxElement); | 393 boxes.add(boxElement); |
| 394 } | 394 } |
| 395 }); | 395 }); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 475 if (arguments != null) { | 475 if (arguments != null) { |
| 476 visit(arguments); | 476 visit(arguments); |
| 477 } | 477 } |
| 478 } else { | 478 } else { |
| 479 visit(definition); | 479 visit(definition); |
| 480 } | 480 } |
| 481 } | 481 } |
| 482 } | 482 } |
| 483 | 483 |
| 484 visitTypeAnnotation(TypeAnnotation node) { | 484 visitTypeAnnotation(TypeAnnotation node) { |
| 485 Element member = currentElement.getEnclosingMember(); | 485 Element member = currentElement.enclosingMember; |
| 486 DartType type = elements.getType(node); | 486 DartType type = elements.getType(node); |
| 487 // TODO(karlklose,johnniwinther): if the type is null, the annotation is | 487 // TODO(karlklose,johnniwinther): if the type is null, the annotation is |
| 488 // from a parameter which has been analyzed before the method has been | 488 // from a parameter which has been analyzed before the method has been |
| 489 // resolved and the result has been thrown away. | 489 // resolved and the result has been thrown away. |
| 490 if (compiler.enableTypeAssertions && type != null && | 490 if (compiler.enableTypeAssertions && type != null && |
| 491 type.containsTypeVariables) { | 491 type.containsTypeVariables) { |
| 492 if (insideClosure && member.isFactoryConstructor()) { | 492 if (insideClosure && member.isFactoryConstructor) { |
| 493 // This is a closure in a factory constructor. Since there is no | 493 // This is a closure in a factory constructor. Since there is no |
| 494 // [:this:], we have to mark the type arguments as free variables to | 494 // [:this:], we have to mark the type arguments as free variables to |
| 495 // capture them in the closure. | 495 // capture them in the closure. |
| 496 type.forEachTypeVariable((variable) => useLocal(variable.element)); | 496 type.forEachTypeVariable((variable) => useLocal(variable.element)); |
| 497 } | 497 } |
| 498 if (member.isInstanceMember() && !member.isField()) { | 498 if (member.isInstanceMember && !member.isField) { |
| 499 // In checked mode, using a type variable in a type annotation may lead | 499 // In checked mode, using a type variable in a type annotation may lead |
| 500 // to a runtime type check that needs to access the type argument and | 500 // to a runtime type check that needs to access the type argument and |
| 501 // therefore the closure needs a this-element, if it is not in a field | 501 // therefore the closure needs a this-element, if it is not in a field |
| 502 // initializer; field initatializers are evaluated in a context where | 502 // initializer; field initatializers are evaluated in a context where |
| 503 // the type arguments are available in locals. | 503 // the type arguments are available in locals. |
| 504 registerNeedsThis(); | 504 registerNeedsThis(); |
| 505 } | 505 } |
| 506 } | 506 } |
| 507 } | 507 } |
| 508 | 508 |
| 509 visitIdentifier(Identifier node) { | 509 visitIdentifier(Identifier node) { |
| 510 if (node.isThis()) { | 510 if (node.isThis()) { |
| 511 registerNeedsThis(); | 511 registerNeedsThis(); |
| 512 } else { | 512 } else { |
| 513 Element element = elements[node]; | 513 Element element = elements[node]; |
| 514 if (element != null && element.kind == ElementKind.TYPE_VARIABLE) { | 514 if (element != null && element.kind == ElementKind.TYPE_VARIABLE) { |
| 515 if (outermostElement.isConstructor()) { | 515 if (outermostElement.isConstructor) { |
| 516 useLocal(element); | 516 useLocal(element); |
| 517 } else { | 517 } else { |
| 518 registerNeedsThis(); | 518 registerNeedsThis(); |
| 519 } | 519 } |
| 520 } | 520 } |
| 521 } | 521 } |
| 522 node.visitChildren(this); | 522 node.visitChildren(this); |
| 523 } | 523 } |
| 524 | 524 |
| 525 visitSend(Send node) { | 525 visitSend(Send node) { |
| 526 Element element = elements[node]; | 526 Element element = elements[node]; |
| 527 if (Elements.isLocal(element)) { | 527 if (Elements.isLocal(element)) { |
| 528 useLocal(element); | 528 useLocal(element); |
| 529 } else if (element != null && element.isTypeVariable()) { | 529 } else if (element != null && element.isTypeVariable) { |
| 530 TypeVariableElement variable = element; | 530 TypeVariableElement variable = element; |
| 531 analyzeType(variable.type); | 531 analyzeType(variable.type); |
| 532 } else if (node.receiver == null && | 532 } else if (node.receiver == null && |
| 533 Elements.isInstanceSend(node, elements)) { | 533 Elements.isInstanceSend(node, elements)) { |
| 534 registerNeedsThis(); | 534 registerNeedsThis(); |
| 535 } else if (node.isSuperCall) { | 535 } else if (node.isSuperCall) { |
| 536 registerNeedsThis(); | 536 registerNeedsThis(); |
| 537 } else if (node.isTypeTest || node.isTypeCast) { | 537 } else if (node.isTypeTest || node.isTypeCast) { |
| 538 TypeAnnotation annotation = node.typeAnnotationFromIsCheckOrCast; | 538 TypeAnnotation annotation = node.typeAnnotationFromIsCheckOrCast; |
| 539 DartType type = elements.getType(annotation); | 539 DartType type = elements.getType(annotation); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 566 visitNewExpression(NewExpression node) { | 566 visitNewExpression(NewExpression node) { |
| 567 DartType type = elements.getType(node); | 567 DartType type = elements.getType(node); |
| 568 analyzeType(type); | 568 analyzeType(type); |
| 569 node.visitChildren(this); | 569 node.visitChildren(this); |
| 570 } | 570 } |
| 571 | 571 |
| 572 void analyzeTypeVariables(DartType type) { | 572 void analyzeTypeVariables(DartType type) { |
| 573 type.forEachTypeVariable((TypeVariableType typeVariable) { | 573 type.forEachTypeVariable((TypeVariableType typeVariable) { |
| 574 // Field initializers are inlined and access the type variable as | 574 // Field initializers are inlined and access the type variable as |
| 575 // normal parameters. | 575 // normal parameters. |
| 576 if (!outermostElement.isField() && | 576 if (!outermostElement.isField && |
| 577 !outermostElement.isConstructor()) { | 577 !outermostElement.isConstructor) { |
| 578 registerNeedsThis(); | 578 registerNeedsThis(); |
| 579 } else { | 579 } else { |
| 580 useLocal(typeVariable.element); | 580 useLocal(typeVariable.element); |
| 581 } | 581 } |
| 582 }); | 582 }); |
| 583 } | 583 } |
| 584 | 584 |
| 585 void analyzeType(DartType type) { | 585 void analyzeType(DartType type) { |
| 586 // TODO(johnniwinther): Find out why this can be null. | 586 // TODO(johnniwinther): Find out why this can be null. |
| 587 if (type == null) return; | 587 if (type == null) return; |
| 588 if (outermostElement.isMember() && | 588 if (outermostElement.isMember && |
| 589 compiler.backend.classNeedsRti(outermostElement.getEnclosingClass())) { | 589 compiler.backend.classNeedsRti(outermostElement.enclosingClass)) { |
| 590 if (outermostElement.isConstructor() || | 590 if (outermostElement.isConstructor || |
| 591 outermostElement.isField()) { | 591 outermostElement.isField) { |
| 592 analyzeTypeVariables(type); | 592 analyzeTypeVariables(type); |
| 593 } else if (outermostElement.isInstanceMember()) { | 593 } else if (outermostElement.isInstanceMember) { |
| 594 if (type.containsTypeVariables) { | 594 if (type.containsTypeVariables) { |
| 595 registerNeedsThis(); | 595 registerNeedsThis(); |
| 596 } | 596 } |
| 597 } | 597 } |
| 598 } | 598 } |
| 599 } | 599 } |
| 600 | 600 |
| 601 // If variables that are declared in the [node] scope are captured and need | 601 // If variables that are declared in the [node] scope are captured and need |
| 602 // to be boxed create a box-element and update the [capturingScopes] in the | 602 // to be boxed create a box-element and update the [capturingScopes] in the |
| 603 // current [closureData]. | 603 // current [closureData]. |
| 604 // The boxed variables are updated in the [capturedVariableMapping]. | 604 // The boxed variables are updated in the [capturedVariableMapping]. |
| 605 void attachCapturedScopeVariables(Node node) { | 605 void attachCapturedScopeVariables(Node node) { |
| 606 Element box = null; | 606 Element box = null; |
| 607 Map<Element, Element> scopeMapping = new Map<Element, Element>(); | 607 Map<Element, Element> scopeMapping = new Map<Element, Element>(); |
| 608 for (Element element in scopeVariables) { | 608 for (Element element in scopeVariables) { |
| 609 // No need to box non-assignable elements. | 609 // No need to box non-assignable elements. |
| 610 if (!element.isAssignable()) continue; | 610 if (!element.isAssignable) continue; |
| 611 if (!mutatedVariables.contains(element)) continue; | 611 if (!mutatedVariables.contains(element)) continue; |
| 612 if (capturedVariableMapping.containsKey(element)) { | 612 if (capturedVariableMapping.containsKey(element)) { |
| 613 if (box == null) { | 613 if (box == null) { |
| 614 // TODO(floitsch): construct better box names. | 614 // TODO(floitsch): construct better box names. |
| 615 String boxName = | 615 String boxName = |
| 616 namer.getClosureVariableName('box', closureFieldCounter++); | 616 namer.getClosureVariableName('box', closureFieldCounter++); |
| 617 box = new BoxElement( | 617 box = new BoxElement( |
| 618 boxName, currentElement, compiler.types.dynamicType); | 618 boxName, currentElement, compiler.types.dynamicType); |
| 619 } | 619 } |
| 620 String elementName = element.name; | 620 String elementName = element.name; |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 685 for (Element enclosingElement = element.enclosingElement; | 685 for (Element enclosingElement = element.enclosingElement; |
| 686 enclosingElement != null && | 686 enclosingElement != null && |
| 687 (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY | 687 (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY |
| 688 || enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR | 688 || enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR |
| 689 || enclosingElement.kind == ElementKind.CLASS | 689 || enclosingElement.kind == ElementKind.CLASS |
| 690 || enclosingElement.kind == ElementKind.FUNCTION | 690 || enclosingElement.kind == ElementKind.FUNCTION |
| 691 || enclosingElement.kind == ElementKind.GETTER | 691 || enclosingElement.kind == ElementKind.GETTER |
| 692 || enclosingElement.kind == ElementKind.SETTER); | 692 || enclosingElement.kind == ElementKind.SETTER); |
| 693 enclosingElement = enclosingElement.enclosingElement) { | 693 enclosingElement = enclosingElement.enclosingElement) { |
| 694 // TODO(johnniwinther): Simplify computed names. | 694 // TODO(johnniwinther): Simplify computed names. |
| 695 if (enclosingElement.isGenerativeConstructor() || | 695 if (enclosingElement.isGenerativeConstructor || |
| 696 enclosingElement.isGenerativeConstructorBody() || | 696 enclosingElement.isGenerativeConstructorBody || |
| 697 enclosingElement.isFactoryConstructor()) { | 697 enclosingElement.isFactoryConstructor) { |
| 698 parts = parts.prepend( | 698 parts = parts.prepend( |
| 699 Elements.reconstructConstructorName(enclosingElement)); | 699 Elements.reconstructConstructorName(enclosingElement)); |
| 700 } else { | 700 } else { |
| 701 String surroundingName = | 701 String surroundingName = |
| 702 Elements.operatorNameToIdentifier(enclosingElement.name); | 702 Elements.operatorNameToIdentifier(enclosingElement.name); |
| 703 parts = parts.prepend(surroundingName); | 703 parts = parts.prepend(surroundingName); |
| 704 } | 704 } |
| 705 // A generative constructors's parent is the class; the class name is | 705 // A generative constructors's parent is the class; the class name is |
| 706 // already part of the generative constructor's name. | 706 // already part of the generative constructor's name. |
| 707 if (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR) break; | 707 if (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR) break; |
| 708 } | 708 } |
| 709 StringBuffer sb = new StringBuffer(); | 709 StringBuffer sb = new StringBuffer(); |
| 710 parts.printOn(sb, '_'); | 710 parts.printOn(sb, '_'); |
| 711 return sb.toString(); | 711 return sb.toString(); |
| 712 } | 712 } |
| 713 | 713 |
| 714 ClosureClassMap globalizeClosure(FunctionExpression node, | 714 ClosureClassMap globalizeClosure(FunctionExpression node, |
| 715 TypedElement element) { | 715 TypedElement element) { |
| 716 String closureName = computeClosureName(element); | 716 String closureName = computeClosureName(element); |
| 717 ClassElement globalizedElement = new ClosureClassElement( | 717 ClassElement globalizedElement = new ClosureClassElement( |
| 718 node, closureName, compiler, element, element.getCompilationUnit()); | 718 node, closureName, compiler, element, element.compilationUnit); |
| 719 FunctionElement callElement = | 719 FunctionElement callElement = |
| 720 new SynthesizedCallMethodElementX(Compiler.CALL_OPERATOR_NAME, | 720 new SynthesizedCallMethodElementX(Compiler.CALL_OPERATOR_NAME, |
| 721 element, | 721 element, |
| 722 globalizedElement); | 722 globalizedElement); |
| 723 ClosureContainer enclosing = element.enclosingElement; | 723 ClosureContainer enclosing = element.enclosingElement; |
| 724 enclosing.nestedClosures.add(callElement); | 724 enclosing.nestedClosures.add(callElement); |
| 725 globalizedElement.addMember(callElement, compiler); | 725 globalizedElement.addMember(callElement, compiler); |
| 726 // The nested function's 'this' is the same as the one for the outer | 726 // The nested function's 'this' is the same as the one for the outer |
| 727 // function. It could be [null] if we are inside a static method. | 727 // function. It could be [null] if we are inside a static method. |
| 728 Element thisElement = closureData.thisElement; | 728 Element thisElement = closureData.thisElement; |
| 729 return new ClosureClassMap(element, globalizedElement, | 729 return new ClosureClassMap(element, globalizedElement, |
| 730 callElement, thisElement); | 730 callElement, thisElement); |
| 731 } | 731 } |
| 732 | 732 |
| 733 void visitInvokable(TypedElement element, Node node, void visitChildren()) { | 733 void visitInvokable(TypedElement element, Node node, void visitChildren()) { |
| 734 bool oldInsideClosure = insideClosure; | 734 bool oldInsideClosure = insideClosure; |
| 735 Element oldFunctionElement = currentElement; | 735 Element oldFunctionElement = currentElement; |
| 736 ClosureClassMap oldClosureData = closureData; | 736 ClosureClassMap oldClosureData = closureData; |
| 737 | 737 |
| 738 insideClosure = outermostElement != null; | 738 insideClosure = outermostElement != null; |
| 739 currentElement = element; | 739 currentElement = element; |
| 740 if (insideClosure) { | 740 if (insideClosure) { |
| 741 closures.add(node); | 741 closures.add(node); |
| 742 closureData = globalizeClosure(node, element); | 742 closureData = globalizeClosure(node, element); |
| 743 } else { | 743 } else { |
| 744 outermostElement = element; | 744 outermostElement = element; |
| 745 Element thisElement = null; | 745 Element thisElement = null; |
| 746 if (element.isInstanceMember() || element.isGenerativeConstructor()) { | 746 if (element.isInstanceMember || element.isGenerativeConstructor) { |
| 747 thisElement = new ThisElement(element, compiler.types.dynamicType); | 747 thisElement = new ThisElement(element, compiler.types.dynamicType); |
| 748 } | 748 } |
| 749 closureData = new ClosureClassMap(null, null, null, thisElement); | 749 closureData = new ClosureClassMap(null, null, null, thisElement); |
| 750 } | 750 } |
| 751 closureMappingCache[node] = closureData; | 751 closureMappingCache[node] = closureData; |
| 752 | 752 |
| 753 inNewScope(node, () { | 753 inNewScope(node, () { |
| 754 // We have to declare the implicit 'this' parameter. | 754 // We have to declare the implicit 'this' parameter. |
| 755 if (!insideClosure && closureData.thisElement != null) { | 755 if (!insideClosure && closureData.thisElement != null) { |
| 756 declareLocal(closureData.thisElement); | 756 declareLocal(closureData.thisElement); |
| 757 } | 757 } |
| 758 // If we are inside a named closure we have to declare ourselve. For | 758 // If we are inside a named closure we have to declare ourselve. For |
| 759 // simplicity we declare the local even if the closure does not have a | 759 // simplicity we declare the local even if the closure does not have a |
| 760 // name. | 760 // name. |
| 761 // It will simply not be used. | 761 // It will simply not be used. |
| 762 if (insideClosure) { | 762 if (insideClosure) { |
| 763 declareLocal(element); | 763 declareLocal(element); |
| 764 } | 764 } |
| 765 | 765 |
| 766 if (currentElement.isFactoryConstructor() && | 766 if (currentElement.isFactoryConstructor && |
| 767 compiler.backend.classNeedsRti(currentElement.enclosingElement)) { | 767 compiler.backend.classNeedsRti(currentElement.enclosingElement)) { |
| 768 // Declare the type parameters in the scope. Generative | 768 // Declare the type parameters in the scope. Generative |
| 769 // constructors just use 'this'. | 769 // constructors just use 'this'. |
| 770 ClassElement cls = currentElement.enclosingElement; | 770 ClassElement cls = currentElement.enclosingElement; |
| 771 cls.typeVariables.forEach((TypeVariableType typeVariable) { | 771 cls.typeVariables.forEach((TypeVariableType typeVariable) { |
| 772 declareLocal(typeVariable.element); | 772 declareLocal(typeVariable.element); |
| 773 }); | 773 }); |
| 774 } | 774 } |
| 775 | 775 |
| 776 DartType type = element.computeType(compiler); | 776 DartType type = element.computeType(compiler); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 803 compiler.internalError(node, 'In closure analyzer.'); | 803 compiler.internalError(node, 'In closure analyzer.'); |
| 804 } | 804 } |
| 805 capturedVariableMapping[freeElement] = freeElement; | 805 capturedVariableMapping[freeElement] = freeElement; |
| 806 useLocal(freeElement); | 806 useLocal(freeElement); |
| 807 } | 807 } |
| 808 } | 808 } |
| 809 | 809 |
| 810 visitFunctionExpression(FunctionExpression node) { | 810 visitFunctionExpression(FunctionExpression node) { |
| 811 Element element = elements[node]; | 811 Element element = elements[node]; |
| 812 | 812 |
| 813 if (element.isParameter()) { | 813 if (element.isParameter) { |
| 814 // TODO(ahe): This is a hack. This method should *not* call | 814 // TODO(ahe): This is a hack. This method should *not* call |
| 815 // visitChildren. | 815 // visitChildren. |
| 816 return node.name.accept(this); | 816 return node.name.accept(this); |
| 817 } | 817 } |
| 818 | 818 |
| 819 visitInvokable(element, node, () { | 819 visitInvokable(element, node, () { |
| 820 // TODO(ahe): This is problematic. The backend should not repeat | 820 // TODO(ahe): This is problematic. The backend should not repeat |
| 821 // the work of the resolver. It is the resolver's job to create | 821 // the work of the resolver. It is the resolver's job to create |
| 822 // parameters, etc. Other phases should only visit statements. | 822 // parameters, etc. Other phases should only visit statements. |
| 823 if (node.parameters != null) node.parameters.accept(this); | 823 if (node.parameters != null) node.parameters.accept(this); |
| 824 if (node.initializers != null) node.initializers.accept(this); | 824 if (node.initializers != null) node.initializers.accept(this); |
| 825 if (node.body != null) node.body.accept(this); | 825 if (node.body != null) node.body.accept(this); |
| 826 }); | 826 }); |
| 827 } | 827 } |
| 828 | 828 |
| 829 visitFunctionDeclaration(FunctionDeclaration node) { | 829 visitFunctionDeclaration(FunctionDeclaration node) { |
| 830 node.visitChildren(this); | 830 node.visitChildren(this); |
| 831 declareLocal(elements[node]); | 831 declareLocal(elements[node]); |
| 832 } | 832 } |
| 833 | 833 |
| 834 visitTryStatement(TryStatement node) { | 834 visitTryStatement(TryStatement node) { |
| 835 // TODO(ngeoffray): implement finer grain state. | 835 // TODO(ngeoffray): implement finer grain state. |
| 836 bool oldInTryStatement = inTryStatement; | 836 bool oldInTryStatement = inTryStatement; |
| 837 inTryStatement = true; | 837 inTryStatement = true; |
| 838 node.visitChildren(this); | 838 node.visitChildren(this); |
| 839 inTryStatement = oldInTryStatement; | 839 inTryStatement = oldInTryStatement; |
| 840 } | 840 } |
| 841 } | 841 } |
| OLD | NEW |