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

Unified Diff: lib/compiler/implementation/closure.dart

Issue 10913133: Allow closures inside lazy initializers. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add another test. Created 8 years, 2 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: lib/compiler/implementation/closure.dart
diff --git a/lib/compiler/implementation/closure.dart b/lib/compiler/implementation/closure.dart
index ec82f30c8e5bb368e9dd6977e0729e7631ab230a..b856080fffeb0a6c9070a1e2c2b70421ed9b046d 100644
--- a/lib/compiler/implementation/closure.dart
+++ b/lib/compiler/implementation/closure.dart
@@ -18,7 +18,8 @@ class ClosureTask extends CompilerTask {
String get name => "Closure Simplifier";
- ClosureClassMap computeClosureToClassMapping(FunctionExpression node,
+ ClosureClassMap computeClosureToClassMapping(Element element,
+ Expression node,
TreeElements elements) {
return measure(() {
ClosureClassMap cached = closureMappingCache[node];
@@ -26,9 +27,16 @@ class ClosureTask extends CompilerTask {
ClosureTranslator translator =
new ClosureTranslator(compiler, elements, closureMappingCache);
+
// The translator will store the computed closure-mappings inside the
- // cache. One for given method and one for each nested closure.
- translator.translate(node);
+ // cache. One for given node and one for each nested closure.
+ if (node is FunctionExpression) {
+ translator.translateFunction(element, node);
+ } else {
+ // Must be the lazy initializer of a static.
+ assert(node is SendSet);
+ translator.translateLazyInitializer(element, node);
+ }
assert(closureMappingCache[node] != null);
return closureMappingCache[node];
});
@@ -113,7 +121,7 @@ class ClosureScope {
class ClosureClassMap {
// The closure's element before any translation. Will be null for methods.
- final FunctionElement closureElement;
+ final Element closureElement;
// The closureClassElement will be null for methods that are not local
// closures.
final ClassElement closureClassElement;
@@ -170,7 +178,7 @@ class ClosureTranslator extends Visitor {
// will update this mapping.
Map<Element, Element> capturedVariableMapping;
// List of encountered closures.
- List<FunctionExpression> closures;
+ List<Expression> closures;
// The variables that have been declared in the current scope.
List<Element> scopeVariables;
@@ -179,8 +187,8 @@ class ClosureTranslator extends Visitor {
// non-mutated variables.
Set<Element> mutatedVariables;
- FunctionElement outermostFunctionElement;
- FunctionElement currentFunctionElement;
+ Element outermostElement;
+ Element currentElement;
// The closureData of the currentFunctionElement.
ClosureClassMap closureData;
@@ -189,11 +197,12 @@ class ClosureTranslator extends Visitor {
ClosureTranslator(this.compiler, this.elements, this.closureMappingCache)
: capturedVariableMapping = new Map<Element, Element>(),
- closures = <FunctionExpression>[],
+ closures = <Expression>[],
mutatedVariables = new Set<Element>();
- void translate(Node node) {
- visit(node);
+ void translateFunction(Element element, FunctionExpression node) {
+ assert(elements[node] == element);
+ visit(node); // [visitFunctionExpression] will call [visitInvokable].
// When variables need to be boxed their [capturedVariableMapping] is
// updated, but we delay updating the similar freeVariableMapping in the
// closure datas that capture these variables.
@@ -201,12 +210,19 @@ class ClosureTranslator extends Visitor {
updateClosures();
}
+ void translateLazyInitializer(Element element, SendSet node) {
+ assert(node.assignmentOperator.source == const SourceString("="));
+ Expression initialValue = node.argumentsNode.nodes.head;
+ visitInvokable(element, node, () { visit(initialValue); });
+ updateClosures();
+ }
+
// This function runs through all of the existing closures and updates their
// free variables to the boxed value. It also adds the field-elements to the
// class representing the closure. At the same time it fills the
// [capturedFieldMapping].
void updateClosures() {
- for (FunctionExpression closure in closures) {
+ for (Expression closure in closures) {
// The captured variables that need to be stored in a field of the closure
// class.
Set<Element> fieldCaptures = new Set<Element>();
@@ -260,8 +276,8 @@ class ClosureTranslator extends Visitor {
// parameters, and type parameters are declared in the class, not
// the factory.
if (insideClosure &&
- element.enclosingElement != currentFunctionElement &&
- element != currentFunctionElement) {
+ element.enclosingElement != currentElement &&
+ element != currentElement) {
assert(closureData.freeVariableMapping[element] == null ||
closureData.freeVariableMapping[element] == element);
closureData.freeVariableMapping[element] = element;
@@ -373,12 +389,12 @@ class ClosureTranslator extends Visitor {
}
}
}
- if (outermostFunctionElement.isMember() &&
- compiler.world.needsRti(outermostFunctionElement.getEnclosingClass())) {
- if (outermostFunctionElement.isInstanceMember()
- || outermostFunctionElement.isGenerativeConstructor()) {
+ if (outermostElement.isMember() &&
+ compiler.world.needsRti(outermostElement.getEnclosingClass())) {
+ if (outermostElement.isInstanceMember()
+ || outermostElement.isGenerativeConstructor()) {
if (hasTypeVariable(type)) useLocal(closureData.thisElement);
- } else if (outermostFunctionElement.isFactoryConstructor()) {
+ } else if (outermostElement.isFactoryConstructor()) {
analyzeTypeVariables(type);
}
}
@@ -402,7 +418,7 @@ class ClosureTranslator extends Visitor {
// TODO(floitsch): construct better box names.
SourceString boxName =
new SourceString("box_${closureFieldCounter++}");
- box = new BoxElement(boxName, currentFunctionElement);
+ box = new BoxElement(boxName, currentElement);
}
// TODO(floitsch): construct better boxed names.
String elementName = element.name.slowToString();
@@ -509,25 +525,18 @@ class ClosureTranslator extends Visitor {
callElement, thisElement);
}
- visitFunctionExpression(FunctionExpression node) {
- Element element = elements[node];
- if (element.isParameter()) {
- // TODO(ahe): This is a hack. This method should *not* call
- // visitChildren.
- return node.name.accept(this);
- }
-
+ void visitInvokable(Element element, Expression node, void visitChildren()) {
bool oldInsideClosure = insideClosure;
- FunctionElement oldFunctionElement = currentFunctionElement;
+ Element oldFunctionElement = currentElement;
ClosureClassMap oldClosureData = closureData;
- insideClosure = outermostFunctionElement != null;
- currentFunctionElement = element;
+ insideClosure = outermostElement != null;
+ currentElement = element;
if (insideClosure) {
closures.add(node);
closureData = globalizeClosure(node, element);
} else {
- outermostFunctionElement = element;
+ outermostElement = element;
Element thisElement = null;
if (element.isInstanceMember() || element.isGenerativeConstructor()) {
thisElement = new ThisElement(element);
@@ -549,23 +558,17 @@ class ClosureTranslator extends Visitor {
declareLocal(element);
}
- if (currentFunctionElement.isFactoryConstructor()
- && compiler.world.needsRti(currentFunctionElement.enclosingElement)) {
+ if (currentElement.isFactoryConstructor()
+ && compiler.world.needsRti(currentElement.enclosingElement)) {
// Declare the type parameters in the scope. Generative
// constructors just use 'this'.
- ClassElement cls = currentFunctionElement.enclosingElement;
+ ClassElement cls = currentElement.enclosingElement;
cls.typeVariables.forEach((TypeVariableType typeVariable) {
declareLocal(typeVariable.element);
});
}
- // TODO(ahe): This is problematic. The backend should not repeat
- // the work of the resolver. It is the resolver's job to create
- // parameters, etc. Other phases should only visit statements.
- // TODO(floitsch): we avoid visiting the initializers on purpose so that
- // we get an error-message later in the builder.
- if (node.parameters !== null) node.parameters.accept(this);
- if (node.body !== null) node.body.accept(this);
+ visitChildren();
});
@@ -575,7 +578,7 @@ class ClosureTranslator extends Visitor {
// Restore old values.
insideClosure = oldInsideClosure;
closureData = oldClosureData;
- currentFunctionElement = oldFunctionElement;
+ currentElement = oldFunctionElement;
// Mark all free variables as captured and use them in the outer function.
List<Element> freeVariables =
@@ -591,6 +594,26 @@ class ClosureTranslator extends Visitor {
}
}
+ visitFunctionExpression(FunctionExpression node) {
+ Element element = elements[node];
+
+ if (element.isParameter()) {
+ // TODO(ahe): This is a hack. This method should *not* call
+ // visitChildren.
+ return node.name.accept(this);
+ }
+
+ visitInvokable(element, node, () {
+ // TODO(ahe): This is problematic. The backend should not repeat
+ // the work of the resolver. It is the resolver's job to create
+ // parameters, etc. Other phases should only visit statements.
+ // TODO(floitsch): we avoid visiting the initializers on purpose so that
+ // we get an error-message later in the builder.
+ if (node.parameters !== null) node.parameters.accept(this);
+ if (node.body !== null) node.body.accept(this);
+ });
+ }
+
visitFunctionDeclaration(FunctionDeclaration node) {
node.visitChildren(this);
declareLocal(elements[node]);
« no previous file with comments | « no previous file | lib/compiler/implementation/resolver.dart » ('j') | lib/compiler/implementation/ssa/builder.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698