Chromium Code Reviews| Index: lib/compiler/implementation/closure.dart |
| =================================================================== |
| --- lib/compiler/implementation/closure.dart (revision 11862) |
| +++ lib/compiler/implementation/closure.dart (working copy) |
| @@ -179,7 +179,9 @@ |
| // non-mutated variables. |
| Set<Element> mutatedVariables; |
| + FunctionElement outermostFunctionElement; |
| FunctionElement currentFunctionElement; |
| + |
| // The closureData of the currentFunctionElement. |
| ClosureClassMap closureData; |
| @@ -250,16 +252,11 @@ |
| } |
| void useLocal(Element element) { |
| - // TODO(floitsch): replace this with a general solution. |
| - Element functionElement = currentFunctionElement; |
| - if (functionElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { |
| - ConstructorBodyElement body = functionElement; |
| - functionElement = body.constructor; |
| - } |
| // If the element is not declared in the current function and the element |
| // is not the closure itself we need to mark the element as free variable. |
| - if (element.enclosingElement != functionElement && |
| - element != functionElement) { |
| + if (insideClosure && |
|
floitsch
2012/09/05 13:50:34
As discussed: explain that this is not just an opt
ngeoffray
2012/09/05 15:36:11
Done.
|
| + element.enclosingElement != currentFunctionElement && |
| + element != currentFunctionElement) { |
| assert(closureData.freeVariableMapping[element] == null || |
| closureData.freeVariableMapping[element] == element); |
| closureData.freeVariableMapping[element] = element; |
| @@ -346,6 +343,9 @@ |
| } |
| visitNewExpression(NewExpression node) { |
| + TypeAnnotation annotation = node.send.getTypeAnnotation(); |
| + DartType type = elements.getType(annotation); |
| + |
| bool hasTypeVariable(DartType type) { |
| if (type is TypeVariableType) { |
| return true; |
| @@ -359,14 +359,25 @@ |
| } |
| return false; |
| } |
| - TypeAnnotation annotation = node.send.getTypeAnnotation(); |
| - DartType type = elements.getType(annotation); |
| - if (hasTypeVariable(type)) { |
| - // Factories do not use [this] to get the type variables. |
| - if (closureData.thisElement !== null) { |
| - useLocal(closureData.thisElement); |
| + |
| + void analyzeTypeVariables(DartType type) { |
| + if (type is TypeVariableType) { |
| + useLocal(type.element); |
| + } else if (type is InterfaceType) { |
| + InterfaceType ifcType = type; |
| + for (DartType argument in ifcType.arguments) { |
| + analyzeTypeVariables(argument); |
| + } |
| } |
| } |
| + |
| + if (outermostFunctionElement.isInstanceMember() |
| + || outermostFunctionElement.isGenerativeConstructor()) { |
| + if (hasTypeVariable(type)) useLocal(closureData.thisElement); |
| + } else if (outermostFunctionElement.isFactoryConstructor()) { |
| + analyzeTypeVariables(type); |
| + } |
| + |
| node.visitChildren(this); |
| } |
| @@ -464,38 +475,31 @@ |
| visitFunctionExpression(FunctionExpression node) { |
| Element element = elements[node]; |
| - if (element.kind === ElementKind.PARAMETER) { |
| + if (element.isParameter()) { |
| // TODO(ahe): This is a hack. This method should *not* call |
| // visitChildren. |
| return node.name.accept(this); |
| } |
| - bool isClosure = (closureData !== null); |
| - if (isClosure) closures.add(node); |
| - |
| bool oldInsideClosure = insideClosure; |
| FunctionElement oldFunctionElement = currentFunctionElement; |
| ClosureClassMap oldClosureData = closureData; |
| - insideClosure = isClosure; |
| - currentFunctionElement = elements[node]; |
| + insideClosure = outermostFunctionElement != null; |
| + currentFunctionElement = element; |
| if (insideClosure) { |
| + closures.add(node); |
| closureData = globalizeClosure(node, element); |
| } else { |
| + outermostFunctionElement = element; |
| 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) { |
| + if (element.isInstanceMember() || element.isGenerativeConstructor()) { |
| // TODO(floitsch): currently all variables are considered to be |
|
floitsch
2012/09/05 13:50:34
Remove the TODO.
ngeoffray
2012/09/05 15:36:11
Done.
|
| // 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 ThisElement(thisEnclosingElement); |
| + thisElement = new ThisElement(element); |
| } |
| closureData = new ClosureClassMap(null, null, null, thisElement); |
| } |
| @@ -513,6 +517,15 @@ |
| if (insideClosure) { |
| declareLocal(element); |
| } |
| + |
| + if (currentFunctionElement.isFactoryConstructor()) { |
| + // Declare the type parameters in the scope. Generative |
| + // constructors just use 'this'. |
| + ClassElement cls = currentFunctionElement.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 |