| Index: lib/compiler/implementation/closure.dart
|
| diff --git a/lib/compiler/implementation/closure.dart b/lib/compiler/implementation/closure.dart
|
| index ec82f30c8e5bb368e9dd6977e0729e7631ab230a..1c52f51aa70f2c1babd04d9ebc237a0f456e5c9c 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,14 @@ 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) {
|
| + // For constructors the [element] and the [:elements[node]:] may differ.
|
| + // The [:elements[node]:] always points to the generative-constructor
|
| + // element, whereas the [element] might be the constructor-body 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 +212,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 +278,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 +391,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 +420,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 +527,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 +560,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 +580,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 +596,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]);
|
|
|