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

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

Issue 2712473003: closure conversion: Support closures in initializers (Closed)
Patch Set: Address comments Created 3 years, 10 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
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 91a36dfc5e17e4933a479a8f6bb807851dedf391..325d9e54abdc5fb050024fc2b00409feaa271f8d 100644
--- a/pkg/kernel/lib/transformations/closure/converter.dart
+++ b/pkg/kernel/lib/transformations/closure/converter.dart
@@ -27,6 +27,7 @@ import '../../ast.dart'
Initializer,
InvalidExpression,
InvocationExpression,
+ Let,
Library,
LocalInitializer,
Member,
@@ -67,6 +68,8 @@ import 'context.dart' show Context, NoContext;
import 'info.dart' show ClosureInfo;
+import 'rewriter.dart' show AstRewriter, BlockRewriter, InitializerRewriter;
+
class ClosureConverter extends Transformer {
final CoreTypes coreTypes;
final Class contextClass;
@@ -103,12 +106,10 @@ class ClosureConverter extends Transformer {
FunctionNode currentFunction;
- Block _currentBlock;
-
- int _insertionIndex = 0;
-
Context context;
+ AstRewriter rewriter;
+
/// Maps original type variable (aka type parameter) to a hoisted type
/// variable type.
///
@@ -150,20 +151,13 @@ class ClosureConverter extends Transformer {
throw "No file uri for ${currentMember.runtimeType}";
}
- void insert(Statement statement) {
- _currentBlock.statements.insert(_insertionIndex++, statement);
- statement.parent = _currentBlock;
- }
-
TreeNode saveContext(TreeNode f()) {
- Block savedBlock = _currentBlock;
- int savedIndex = _insertionIndex;
+ AstRewriter old = rewriter;
Context savedContext = context;
try {
return f();
} finally {
- _currentBlock = savedBlock;
- _insertionIndex = savedIndex;
+ rewriter = old;
context = savedContext;
}
}
@@ -196,26 +190,68 @@ class ClosureConverter extends Transformer {
return node;
}
+ void extendContextWith(VariableDeclaration parameter) {
+ context.extend(parameter, new VariableGet(parameter));
+ }
+
TreeNode visitConstructor(Constructor node) {
assert(isEmptyContext);
-
currentMember = node;
-
+ // Transform initializers.
+ for (Initializer initializer in node.initializers) {
+ if (initializer is FieldInitializer) {
+ // Create a rewriter and a context for the initializer expression.
+ rewriter = new InitializerRewriter(initializer.value);
+ context = new NoContext(this);
+ // Save the expression to visit it in the extended context, since the
+ // rewriter will modify `initializer.value`.
+ Expression initializerExpression = initializer.value;
+ // Extend the context with all captured parameters of the constructor.
+ // TODO(karlklose): add a fine-grained analysis of captured parameters.
+ node.function.positionalParameters
+ .where(capturedVariables.contains)
+ .forEach(extendContextWith);
+ node.function.namedParameters
+ .where(capturedVariables.contains)
+ .forEach(extendContextWith);
+ // Transform the initializer expression.
+ var parent = initializerExpression.parent;
+ initializerExpression = initializerExpression.accept(this);
+ initializerExpression.parent = parent;
+ if (parent is Let) {
+ parent.body = initializerExpression;
+ } else if (parent is FieldInitializer) {
+ parent.value = initializerExpression;
+ } else {
+ throw "Found unexpected node '${node.runtimeType}, expected a 'Let' "
+ "or a 'FieldInitializer'.";
+ }
+ }
+ }
+ rewriter = null;
+ // Transform constructor body.
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;
}
+ AstRewriter makeRewriterForBody(FunctionNode function) {
+ Statement body = function.body;
+ if (body is! Block) {
+ body = new Block(<Statement>[body]);
+ function.body = function.body.parent = body;
+ }
+ return new BlockRewriter(body);
+ }
+
Expression handleLocalFunction(FunctionNode function) {
FunctionNode enclosingFunction = currentFunction;
Map<TypeParameter, DartType> enclosingTypeSubstitution = typeSubstitution;
@@ -223,13 +259,7 @@ class ClosureConverter extends Transformer {
Statement body = function.body;
assert(body != null);
- if (body is Block) {
- _currentBlock = body;
- } else {
- _currentBlock = new Block(<Statement>[body]);
- function.body = body.parent = _currentBlock;
- }
- _insertionIndex = 0;
+ rewriter = makeRewriterForBody(function);
VariableDeclaration contextVariable = new VariableDeclaration(
"#contextParameter",
@@ -275,9 +305,11 @@ class ClosureConverter extends Transformer {
});
}
- TreeNode visitFunctionExpression(FunctionExpression node) => saveContext(() {
- return handleLocalFunction(node.function);
- });
+ TreeNode visitFunctionExpression(FunctionExpression node) {
+ return saveContext(() {
+ return handleLocalFunction(node.function);
+ });
+ }
/// Add a new class to the current library that looks like this:
///
@@ -394,28 +426,21 @@ class ClosureConverter extends Transformer {
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]);
- function.body = body.parent = _currentBlock;
- }
- _insertionIndex = 0;
+ rewriter = makeRewriterForBody(function);
// Start with no context. This happens after setting up _currentBlock
// so statements can be emitted into _currentBlock if necessary.
context = new NoContext(this);
}
void resetContext() {
- _currentBlock = null;
- _insertionIndex = 0;
+ rewriter = null;
context = null;
currentMemberFunction = null;
currentMember = null;
}
bool get isEmptyContext {
- return _currentBlock == null && _insertionIndex == 0 && context == null;
+ return rewriter == null && context == null;
}
TreeNode visitLocalInitializer(LocalInitializer node) {
@@ -426,16 +451,14 @@ class ClosureConverter extends Transformer {
TreeNode visitFunctionNode(FunctionNode node) {
transformList(node.typeParameters, this, node);
-
- void extend(VariableDeclaration parameter) {
- context.extend(parameter, new VariableGet(parameter));
- }
-
// TODO: Can parameters contain initializers (e.g., for optional ones) that
// need to be closure converted?
- node.positionalParameters.where(capturedVariables.contains).forEach(extend);
- node.namedParameters.where(capturedVariables.contains).forEach(extend);
-
+ node.positionalParameters
+ .where(capturedVariables.contains)
+ .forEach(extendContextWith);
+ node.namedParameters
+ .where(capturedVariables.contains)
+ .forEach(extendContextWith);
assert(node.body != null);
node.body = node.body.accept(this);
node.body.parent = node;
@@ -444,25 +467,8 @@ class ClosureConverter extends Transformer {
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;
- }
- }
-
+ BlockRewriter blockRewriter = rewriter = rewriter.forNestedBlock(node);
+ blockRewriter.transformStatements(node, this);
return node;
});
}
@@ -556,9 +562,9 @@ class ClosureConverter extends Transformer {
statements.add(node);
node.variables.clear();
node.updates.insert(0, cloneContext());
- _currentBlock = new Block(statements);
- _insertionIndex = 0;
- return _currentBlock.accept(this);
+ Block block = new Block(statements);
+ rewriter = new BlockRewriter(block);
+ return block.accept(this);
});
}
return super.visitForStatement(node);
« no previous file with comments | « pkg/kernel/lib/transformations/closure/context.dart ('k') | pkg/kernel/lib/transformations/closure/rewriter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698