Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(204)

Unified Diff: pkg/kernel/lib/transformations/closure/converter.dart

Issue 2639253003: Handle constructor bodies (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/kernel/lib/transformations/closure/invalidate_closures.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/kernel/lib/transformations/closure/converter.dart
diff --git a/pkg/kernel/lib/transformations/closure/converter.dart b/pkg/kernel/lib/transformations/closure/converter.dart
index 8f40b7cd7a1bf22efbdeb0637252d68cfc89510a..91a36dfc5e17e4933a479a8f6bb807851dedf391 100644
--- a/pkg/kernel/lib/transformations/closure/converter.dart
+++ b/pkg/kernel/lib/transformations/closure/converter.dart
@@ -147,7 +147,7 @@ class ClosureConverter extends Transformer {
if (currentMember is Constructor) return currentClass.fileUri;
if (currentMember is Field) return (currentMember as Field).fileUri;
if (currentMember is Procedure) return (currentMember as Procedure).fileUri;
- throw "No file uri";
+ throw "No file uri for ${currentMember.runtimeType}";
}
void insert(Statement statement) {
@@ -171,6 +171,7 @@ class ClosureConverter extends Transformer {
TreeNode visitLibrary(Library node) {
assert(newLibraryMembers.isEmpty);
if (node == contextClass.enclosingLibrary) return node;
+
currentLibrary = node;
node = super.visitLibrary(node);
for (TreeNode member in newLibraryMembers) {
@@ -196,7 +197,22 @@ class ClosureConverter extends Transformer {
}
TreeNode visitConstructor(Constructor node) {
- // TODO(ahe): Convert closures in constructors as well.
+ assert(isEmptyContext);
+
+ currentMember = node;
+
+ FunctionNode function = node.function;
+ if (function.body != null && function.body is! EmptyStatement) {
+ setupContextForFunctionBody(function);
+ VariableDeclaration self = thisAccess[currentMemberFunction];
+ // TODO(karlklose): transform initializers
+ if (self != null) {
+ context.extend(self, new ThisExpression());
+ }
+ node.function.accept(this);
+ resetContext();
+ }
+
return node;
}
@@ -341,12 +357,9 @@ class ClosureConverter extends Transformer {
}
TreeNode visitProcedure(Procedure node) {
- currentMember = node;
- assert(_currentBlock == null);
- assert(_insertionIndex == 0);
- assert(context == null);
+ assert(isEmptyContext);
- Statement body = node.function.body;
+ currentMember = node;
if (node.isInstanceMember) {
Name tearOffName = tearOffGetterNames[node.name];
@@ -362,36 +375,47 @@ class ClosureConverter extends Transformer {
}
}
- if (body == null) return node;
+ FunctionNode function = node.function;
+ if (function.body != null) {
+ setupContextForFunctionBody(function);
+ VariableDeclaration self = thisAccess[currentMemberFunction];
+ if (self != null) {
+ context.extend(self, new ThisExpression());
+ }
+ node.transformChildren(this);
+ resetContext();
+ }
- currentMemberFunction = node.function;
+ return node;
+ }
+ void setupContextForFunctionBody(FunctionNode function) {
+ Statement body = function.body;
+ assert(body != null);
+ currentMemberFunction = function;
// Ensure that the body is a block which becomes the current block.
if (body is Block) {
_currentBlock = body;
} else {
_currentBlock = new Block(<Statement>[body]);
- node.function.body = body.parent = _currentBlock;
+ function.body = body.parent = _currentBlock;
}
_insertionIndex = 0;
-
// Start with no context. This happens after setting up _currentBlock
// so statements can be emitted into _currentBlock if necessary.
context = new NoContext(this);
+ }
- VariableDeclaration self = thisAccess[currentMemberFunction];
- if (self != null) {
- context.extend(self, new ThisExpression());
- }
-
- node.transformChildren(this);
-
+ void resetContext() {
_currentBlock = null;
_insertionIndex = 0;
context = null;
currentMemberFunction = null;
currentMember = null;
- return node;
+ }
+
+ bool get isEmptyContext {
+ return _currentBlock == null && _insertionIndex == 0 && context == null;
}
TreeNode visitLocalInitializer(LocalInitializer node) {
@@ -418,28 +442,30 @@ class ClosureConverter extends Transformer {
return node;
}
- TreeNode visitBlock(Block node) => saveContext(() {
- if (_currentBlock != node) {
- _currentBlock = node;
- _insertionIndex = 0;
- }
+ TreeNode visitBlock(Block node) {
+ return saveContext(() {
+ if (_currentBlock != node) {
+ _currentBlock = node;
+ _insertionIndex = 0;
+ }
- while (_insertionIndex < _currentBlock.statements.length) {
- assert(_currentBlock == node);
-
- var original = _currentBlock.statements[_insertionIndex];
- var transformed = original.accept(this);
- assert(_currentBlock.statements[_insertionIndex] == original);
- if (transformed == null) {
- _currentBlock.statements.removeAt(_insertionIndex);
- } else {
- _currentBlock.statements[_insertionIndex++] = transformed;
- transformed.parent = _currentBlock;
- }
+ while (_insertionIndex < _currentBlock.statements.length) {
+ assert(_currentBlock == node);
+
+ var original = _currentBlock.statements[_insertionIndex];
+ var transformed = original.accept(this);
+ assert(_currentBlock.statements[_insertionIndex] == original);
+ if (transformed == null) {
+ _currentBlock.statements.removeAt(_insertionIndex);
+ } else {
+ _currentBlock.statements[_insertionIndex++] = transformed;
+ transformed.parent = _currentBlock;
}
+ }
- return node;
- });
+ return node;
+ });
+ }
TreeNode visitVariableDeclaration(VariableDeclaration node) {
node.transformChildren(this);
@@ -447,14 +473,14 @@ class ClosureConverter extends Transformer {
if (!capturedVariables.contains(node)) return node;
context.extend(node, node.initializer ?? new NullLiteral());
- if (node.parent == currentFunction) return node;
- if (node.parent is Block) {
+ if (node.parent == currentFunction) {
+ return node;
+ } else {
+ assert(node.parent is Block);
// When returning null, the parent block will remove this node from its
// list of statements.
- // TODO(ahe): I'd like to avoid testing on the parent pointer.
return null;
}
- throw "Unexpected parent for $node: ${node.parent.parent}";
}
TreeNode visitVariableGet(VariableGet node) {
« no previous file with comments | « no previous file | pkg/kernel/lib/transformations/closure/invalidate_closures.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698