| 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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 } | 60 } |
| 61 return nestedClosureData; | 61 return nestedClosureData; |
| 62 }); | 62 }); |
| 63 } | 63 } |
| 64 } | 64 } |
| 65 | 65 |
| 66 // TODO(ahe): These classes continuously cause problems. We need to | 66 // TODO(ahe): These classes continuously cause problems. We need to |
| 67 // move these classes to elements/modelx.dart or see if we can find a | 67 // move these classes to elements/modelx.dart or see if we can find a |
| 68 // more general solution. | 68 // more general solution. |
| 69 class ClosureFieldElement extends ElementX { | 69 class ClosureFieldElement extends ElementX { |
| 70 ClosureFieldElement(SourceString name, ClassElement enclosing) | 70 ClosureFieldElement(SourceString name, |
| 71 this.variableElement, |
| 72 ClassElement enclosing) |
| 71 : super(name, ElementKind.FIELD, enclosing); | 73 : super(name, ElementKind.FIELD, enclosing); |
| 72 | 74 |
| 73 bool isInstanceMember() => true; | 75 bool isInstanceMember() => true; |
| 74 bool isAssignable() => false; | 76 bool isAssignable() => false; |
| 75 // The names of closure variables don't need renaming, since their use is very | 77 // The names of closure variables don't need renaming, since their use is very |
| 76 // simple and they have 1-character names in the minified mode. | 78 // simple and they have 1-character names in the minified mode. |
| 77 bool hasFixedBackendName() => true; | 79 bool hasFixedBackendName() => true; |
| 78 String fixedBackendName() => name.slowToString(); | 80 String fixedBackendName() => name.slowToString(); |
| 79 | 81 |
| 80 DartType computeType(Compiler compiler) => compiler.types.dynamicType; | 82 DartType computeType(Compiler compiler) { |
| 83 return variableElement.computeType(compiler); |
| 84 } |
| 81 | 85 |
| 82 String toString() => "ClosureFieldElement($name)"; | 86 String toString() => "ClosureFieldElement($name)"; |
| 87 |
| 88 /** |
| 89 * The source variable this element refers to. |
| 90 */ |
| 91 final Element variableElement; |
| 83 } | 92 } |
| 84 | 93 |
| 85 // TODO(ahe): These classes continuously cause problems. We need to | 94 // TODO(ahe): These classes continuously cause problems. We need to |
| 86 // move these classes to elements/modelx.dart or see if we can find a | 95 // move these classes to elements/modelx.dart or see if we can find a |
| 87 // more general solution. | 96 // more general solution. |
| 88 class ClosureClassElement extends ClassElementX { | 97 class ClosureClassElement extends ClassElementX { |
| 89 DartType rawType; | 98 DartType rawType; |
| 90 DartType thisType; | 99 DartType thisType; |
| 91 /// Node that corresponds to this closure, used for source position. | 100 /// Node that corresponds to this closure, used for source position. |
| 92 final FunctionExpression node; | 101 final FunctionExpression node; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 112 | 121 |
| 113 bool isClosure() => true; | 122 bool isClosure() => true; |
| 114 | 123 |
| 115 Token position() => node.getBeginToken(); | 124 Token position() => node.getBeginToken(); |
| 116 | 125 |
| 117 Node parseNode(DiagnosticListener listener) => node; | 126 Node parseNode(DiagnosticListener listener) => node; |
| 118 | 127 |
| 119 /** | 128 /** |
| 120 * The most outer method this closure is declared into. | 129 * The most outer method this closure is declared into. |
| 121 */ | 130 */ |
| 122 Element methodElement; | 131 final Element methodElement; |
| 123 } | 132 } |
| 124 | 133 |
| 125 // TODO(ahe): These classes continuously cause problems. We need to | 134 // TODO(ahe): These classes continuously cause problems. We need to |
| 126 // move these classes to elements/modelx.dart or see if we can find a | 135 // move these classes to elements/modelx.dart or see if we can find a |
| 127 // more general solution. | 136 // more general solution. |
| 128 class BoxElement extends ElementX { | 137 class BoxElement extends ElementX { |
| 129 BoxElement(SourceString name, Element enclosingElement) | 138 BoxElement(SourceString name, Element enclosingElement) |
| 130 : super(name, ElementKind.VARIABLE, enclosingElement); | 139 : super(name, ElementKind.VARIABLE, enclosingElement); |
| 140 |
| 141 DartType computeType(Compiler compiler) => compiler.types.dynamicType; |
| 142 } |
| 143 |
| 144 // TODO(ngeoffray, ahe): These classes continuously cause problems. We need to |
| 145 // move these classes to elements/modelx.dart or see if we can find a |
| 146 // more general solution. |
| 147 class BoxFieldElement extends ElementX { |
| 148 BoxFieldElement(SourceString name, |
| 149 this.variableElement, |
| 150 BoxElement enclosingBox) |
| 151 : super(name, ElementKind.FIELD, enclosingBox); |
| 152 |
| 153 DartType computeType(Compiler compiler) { |
| 154 return variableElement.computeType(compiler); |
| 155 } |
| 156 |
| 157 final Element variableElement; |
| 131 } | 158 } |
| 132 | 159 |
| 133 // TODO(ahe): These classes continuously cause problems. We need to | 160 // TODO(ahe): These classes continuously cause problems. We need to |
| 134 // move these classes to elements/modelx.dart or see if we can find a | 161 // move these classes to elements/modelx.dart or see if we can find a |
| 135 // more general solution. | 162 // more general solution. |
| 136 class ThisElement extends ElementX { | 163 class ThisElement extends ElementX { |
| 137 ThisElement(Element enclosing) | 164 ThisElement(Element enclosing) |
| 138 : super(const SourceString('this'), ElementKind.PARAMETER, enclosing); | 165 : super(const SourceString('this'), ElementKind.PARAMETER, enclosing); |
| 139 | 166 |
| 140 bool isAssignable() => false; | 167 bool isAssignable() => false; |
| 141 | 168 |
| 169 DartType computeType(Compiler compiler) => compiler.types.dynamicType; |
| 170 |
| 142 // Since there is no declaration corresponding to 'this', use the position of | 171 // Since there is no declaration corresponding to 'this', use the position of |
| 143 // the enclosing method. | 172 // the enclosing method. |
| 144 Token position() => enclosingElement.position(); | 173 Token position() => enclosingElement.position(); |
| 145 } | 174 } |
| 146 | 175 |
| 147 // TODO(ahe): These classes continuously cause problems. We need to | 176 // TODO(ahe): These classes continuously cause problems. We need to |
| 148 // move these classes to elements/modelx.dart or see if we can find a | 177 // move these classes to elements/modelx.dart or see if we can find a |
| 149 // more general solution. | 178 // more general solution. |
| 150 class CheckVariableElement extends ElementX { | 179 class CheckVariableElement extends ElementX { |
| 151 Element parameter; | 180 Element parameter; |
| 152 CheckVariableElement(SourceString name, this.parameter, Element enclosing) | 181 CheckVariableElement(SourceString name, this.parameter, Element enclosing) |
| 153 : super(name, ElementKind.VARIABLE, enclosing); | 182 : super(name, ElementKind.VARIABLE, enclosing); |
| 154 | 183 |
| 184 DartType computeType(Compiler compiler) => compiler.types.dynamicType; |
| 185 |
| 155 // Since there is no declaration for the synthetic 'check' variable, use | 186 // Since there is no declaration for the synthetic 'check' variable, use |
| 156 // parameter. | 187 // parameter. |
| 157 Token position() => parameter.position(); | 188 Token position() => parameter.position(); |
| 158 } | 189 } |
| 159 | 190 |
| 160 // The box-element for a scope, and the captured variables that need to be | 191 // The box-element for a scope, and the captured variables that need to be |
| 161 // stored in the box. | 192 // stored in the box. |
| 162 class ClosureScope { | 193 class ClosureScope { |
| 163 Element boxElement; | 194 Element boxElement; |
| 164 Map<Element, Element> capturedVariableMapping; | 195 Map<Element, Element> capturedVariableMapping; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 | 252 |
| 222 bool isVariableCaptured(Element element) { | 253 bool isVariableCaptured(Element element) { |
| 223 freeVariableMapping.containsKey(element); | 254 freeVariableMapping.containsKey(element); |
| 224 } | 255 } |
| 225 | 256 |
| 226 bool isVariableBoxed(Element element) { | 257 bool isVariableBoxed(Element element) { |
| 227 Element copy = freeVariableMapping[element]; | 258 Element copy = freeVariableMapping[element]; |
| 228 return copy != null && !copy.isMember(); | 259 return copy != null && !copy.isMember(); |
| 229 } | 260 } |
| 230 | 261 |
| 231 void forEachCapturedVariable(void f(Element element)) { | 262 void forEachCapturedVariable(void f(Element local, Element field)) { |
| 232 freeVariableMapping.forEach((variable, _) { | 263 freeVariableMapping.forEach((variable, copy) { |
| 233 if (variable is BoxElement) return; | 264 if (variable is BoxElement) return; |
| 234 f(variable); | 265 f(variable, copy); |
| 235 }); | 266 }); |
| 236 } | 267 } |
| 237 | 268 |
| 238 void forEachBoxedVariable(void f(Element element)) { | 269 void forEachBoxedVariable(void f(Element local, Element field)) { |
| 239 freeVariableMapping.forEach((variable, copy) { | 270 freeVariableMapping.forEach((variable, copy) { |
| 240 if (!isVariableBoxed(variable)) return; | 271 if (!isVariableBoxed(variable)) return; |
| 241 f(variable); | 272 f(variable, copy); |
| 242 }); | 273 }); |
| 243 } | 274 } |
| 244 | 275 |
| 245 void forEachNonBoxedCapturedVariable(void f(Element element)) { | 276 void forEachNonBoxedCapturedVariable(void f(Element local, Element field)) { |
| 246 freeVariableMapping.forEach((variable, copy) { | 277 freeVariableMapping.forEach((variable, copy) { |
| 247 if (variable is BoxElement) return; | 278 if (variable is BoxElement) return; |
| 248 if (isVariableBoxed(variable)) return; | 279 if (isVariableBoxed(variable)) return; |
| 249 f(variable); | 280 f(variable, copy); |
| 250 }); | 281 }); |
| 251 } | 282 } |
| 252 } | 283 } |
| 253 | 284 |
| 254 class ClosureTranslator extends Visitor { | 285 class ClosureTranslator extends Visitor { |
| 255 final Compiler compiler; | 286 final Compiler compiler; |
| 256 final TreeElements elements; | 287 final TreeElements elements; |
| 257 int closureFieldCounter = 0; | 288 int closureFieldCounter = 0; |
| 258 int boxedFieldCounter = 0; | 289 int boxedFieldCounter = 0; |
| 259 bool inTryStatement = false; | 290 bool inTryStatement = false; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 freeVariableMapping[fromElement] = updatedElement; | 368 freeVariableMapping[fromElement] = updatedElement; |
| 338 Element boxElement = updatedElement.enclosingElement; | 369 Element boxElement = updatedElement.enclosingElement; |
| 339 assert(boxElement.kind == ElementKind.VARIABLE); | 370 assert(boxElement.kind == ElementKind.VARIABLE); |
| 340 boxes.add(boxElement); | 371 boxes.add(boxElement); |
| 341 } | 372 } |
| 342 }); | 373 }); |
| 343 ClassElement closureElement = data.closureClassElement; | 374 ClassElement closureElement = data.closureClassElement; |
| 344 assert(closureElement != null || | 375 assert(closureElement != null || |
| 345 (fieldCaptures.isEmpty && boxes.isEmpty)); | 376 (fieldCaptures.isEmpty && boxes.isEmpty)); |
| 346 void addElement(Element element, SourceString name) { | 377 void addElement(Element element, SourceString name) { |
| 347 Element fieldElement = new ClosureFieldElement(name, closureElement); | 378 Element fieldElement = new ClosureFieldElement( |
| 379 name, element, closureElement); |
| 348 closureElement.addMember(fieldElement, compiler); | 380 closureElement.addMember(fieldElement, compiler); |
| 349 data.capturedFieldMapping[fieldElement] = element; | 381 data.capturedFieldMapping[fieldElement] = element; |
| 350 freeVariableMapping[element] = fieldElement; | 382 freeVariableMapping[element] = fieldElement; |
| 351 } | 383 } |
| 352 // Add the box elements first so we get the same ordering. | 384 // Add the box elements first so we get the same ordering. |
| 353 // TODO(sra): What is the canonical order of multiple boxes? | 385 // TODO(sra): What is the canonical order of multiple boxes? |
| 354 for (Element capturedElement in boxes) { | 386 for (Element capturedElement in boxes) { |
| 355 addElement(capturedElement, capturedElement.name); | 387 addElement(capturedElement, capturedElement.name); |
| 356 } | 388 } |
| 357 for (Element capturedElement in | 389 for (Element capturedElement in |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 563 SourceString boxName = | 595 SourceString boxName = |
| 564 namer.getClosureVariableName(const SourceString('box'), | 596 namer.getClosureVariableName(const SourceString('box'), |
| 565 closureFieldCounter++); | 597 closureFieldCounter++); |
| 566 box = new BoxElement(boxName, currentElement); | 598 box = new BoxElement(boxName, currentElement); |
| 567 } | 599 } |
| 568 String elementName = element.name.slowToString(); | 600 String elementName = element.name.slowToString(); |
| 569 SourceString boxedName = | 601 SourceString boxedName = |
| 570 namer.getClosureVariableName(new SourceString(elementName), | 602 namer.getClosureVariableName(new SourceString(elementName), |
| 571 boxedFieldCounter++); | 603 boxedFieldCounter++); |
| 572 // TODO(kasperl): Should this be a FieldElement instead? | 604 // TODO(kasperl): Should this be a FieldElement instead? |
| 573 Element boxed = new ElementX(boxedName, ElementKind.FIELD, box); | 605 Element boxed = new BoxFieldElement(boxedName, element, box); |
| 574 // No need to rename the fields of a box, so we give them a native name | 606 // No need to rename the fields of a box, so we give them a native name |
| 575 // right now. | 607 // right now. |
| 576 boxed.setFixedBackendName(boxedName.slowToString()); | 608 boxed.setFixedBackendName(boxedName.slowToString()); |
| 577 scopeMapping[element] = boxed; | 609 scopeMapping[element] = boxed; |
| 578 capturedVariableMapping[element] = boxed; | 610 capturedVariableMapping[element] = boxed; |
| 579 } | 611 } |
| 580 } | 612 } |
| 581 if (!scopeMapping.isEmpty) { | 613 if (!scopeMapping.isEmpty) { |
| 582 ClosureScope scope = new ClosureScope(box, scopeMapping); | 614 ClosureScope scope = new ClosureScope(box, scopeMapping); |
| 583 closureData.capturingScopes[node] = scope; | 615 closureData.capturingScopes[node] = scope; |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 767 } | 799 } |
| 768 | 800 |
| 769 visitTryStatement(TryStatement node) { | 801 visitTryStatement(TryStatement node) { |
| 770 // TODO(ngeoffray): implement finer grain state. | 802 // TODO(ngeoffray): implement finer grain state. |
| 771 bool oldInTryStatement = inTryStatement; | 803 bool oldInTryStatement = inTryStatement; |
| 772 inTryStatement = true; | 804 inTryStatement = true; |
| 773 node.visitChildren(this); | 805 node.visitChildren(this); |
| 774 inTryStatement = oldInTryStatement; | 806 inTryStatement = oldInTryStatement; |
| 775 } | 807 } |
| 776 } | 808 } |
| OLD | NEW |