| Index: frog/leg/ssa/closure.dart
|
| diff --git a/frog/leg/ssa/closure.dart b/frog/leg/ssa/closure.dart
|
| index f8b6143d5019e017d1157caa41c86c5e1a8357c9..d0b8f95d44b459c8ff1b91b48dd5c624efe84925 100644
|
| --- a/frog/leg/ssa/closure.dart
|
| +++ b/frog/leg/ssa/closure.dart
|
| @@ -27,6 +27,9 @@ class ClosureData {
|
| final ClassElement globalizedClosureElement;
|
| // The callElement will be null for methods that are not local closures.
|
| final FunctionElement callElement;
|
| + // The [thisElement] makes handling 'this' easier by treating it like any
|
| + // other argument. It is only set for instance-members.
|
| + final Element thisElement;
|
|
|
| // Maps free locals, arguments and function elements to their captured
|
| // copies.
|
| @@ -46,7 +49,7 @@ class ClosureData {
|
|
|
| final Set<Element> usedVariablesInTry;
|
|
|
| - ClosureData(this.globalizedClosureElement, this.callElement)
|
| + ClosureData(this.globalizedClosureElement, this.callElement, this.thisElement)
|
| : this.freeVariableMapping = new Map<Element, Element>(),
|
| this.capturedFieldMapping = new Map<Element, Element>(),
|
| this.capturingScopes = new Map<Node, ClosureScope>(),
|
| @@ -187,10 +190,8 @@ class ClosureTranslator extends AbstractVisitor {
|
| }
|
|
|
| visitIdentifier(Identifier node) {
|
| - // TODO(floitsch): handle 'this'.
|
| - if (node.isThis() && insideClosure) {
|
| - compiler.unimplemented("ClosureAnalyzer.visitIdentifier this-capture",
|
| - node: node);
|
| + if (node.isThis()) {
|
| + useLocal(closureData.thisElement);
|
| }
|
| node.visitChildren(this);
|
| }
|
| @@ -199,10 +200,9 @@ class ClosureTranslator extends AbstractVisitor {
|
| Element element = elements[node];
|
| if (Elements.isLocal(element)) {
|
| useLocal(element);
|
| - } else if (element === null && node.receiver === null) {
|
| - if (insideClosure) {
|
| - compiler.unimplemented("ClosureTranslator.visitSend this-capture");
|
| - }
|
| + } else if (node.receiver === null &&
|
| + Elements.isInstanceSend(node, elements)) {
|
| + useLocal(closureData.thisElement);
|
| }
|
| node.visitChildren(this);
|
| }
|
| @@ -263,10 +263,14 @@ class ClosureTranslator extends AbstractVisitor {
|
| ClassElement objectClass =
|
| compiler.coreLibrary.find(const SourceString('Object'));
|
| globalizedElement.supertype = new SimpleType(Types.OBJECT, objectClass);
|
| - return new ClosureData(globalizedElement, callElement);
|
| + // The nested function's 'this' is the same as the one for the outer
|
| + // function. It could be [null] if we are inside a static method.
|
| + Element thisElement = closureData.thisElement;
|
| + return new ClosureData(globalizedElement, callElement, thisElement);
|
| }
|
|
|
| visitFunctionExpression(FunctionExpression node) {
|
| + FunctionElement element = elements[node];
|
| bool isClosure = (closureData !== null);
|
|
|
| if (isClosure) closures.add(node);
|
| @@ -279,14 +283,38 @@ class ClosureTranslator extends AbstractVisitor {
|
|
|
| insideClosure = isClosure;
|
| currentFunctionElement = elements[node];
|
| - closureData = insideClosure ?
|
| - globalizeClosure(node) :
|
| - new ClosureData(null, null);
|
| + if (insideClosure) {
|
| + closureData = globalizeClosure(node);
|
| + } else {
|
| + Element thisElement = null;
|
| + // TODO(floitsch): we should not need to look for generative constructors.
|
| + // At the moment we store only one ClosureData for both the factory and
|
| + // the body.
|
| + if (element.isInstanceMember() ||
|
| + element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
|
| + // TODO(floitsch): currently all variables are considered to be
|
| + // declared in the GENERATIVE_CONSTRUCTOR. Including the 'this'.
|
| + Element thisEnclosingElement = element;
|
| + if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) {
|
| + ConstructorBodyElement body = element;
|
| + thisEnclosingElement = body.constructor;
|
| + }
|
| + thisElement = new Element(const SourceString("this"),
|
| + ElementKind.PARAMETER,
|
| + thisEnclosingElement);
|
| + }
|
| + closureData = new ClosureData(null, null, thisElement);
|
| + }
|
| scopeVariables = new List<Element>();
|
|
|
| // TODO(floitsch): a named function is visible from inside itself. Add
|
| // the element to the block.
|
|
|
| + // We have to declare the implicit 'this' parameter.
|
| + if (!insideClosure && closureData.thisElement !== null) {
|
| + declareLocal(closureData.thisElement);
|
| + }
|
| +
|
| node.visitChildren(this);
|
|
|
| attachCapturedScopeVariables(node);
|
|
|