Index: pkg/kernel/lib/transformations/closure/info.dart |
diff --git a/pkg/kernel/lib/transformations/closure/info.dart b/pkg/kernel/lib/transformations/closure/info.dart |
index 2d9c2ca3c90f6f38ea3b78201741b63a3eaa7c94..b47da636cc3c54acac95d7a22522dd7726b69b29 100644 |
--- a/pkg/kernel/lib/transformations/closure/info.dart |
+++ b/pkg/kernel/lib/transformations/closure/info.dart |
@@ -9,13 +9,17 @@ import '../../ast.dart' |
Class, |
Constructor, |
Field, |
+ FieldInitializer, |
FunctionDeclaration, |
FunctionNode, |
+ LocalInitializer, |
Member, |
Name, |
Procedure, |
ProcedureKind, |
PropertyGet, |
+ RedirectingInitializer, |
+ SuperInitializer, |
ThisExpression, |
TypeParameter, |
TypeParameterType, |
@@ -100,8 +104,30 @@ class ClosureInfo extends RecursiveVisitor { |
} |
visitConstructor(Constructor node) { |
+ /// [currentFunction] should be set to [currentMemberFunction] before |
+ /// visiting the [FunctionNode] of the constructor, because initializers may |
+ /// use constructor parameters and it shouldn't be treated as capturing |
+ /// them. Consider the following code: |
+ /// |
+ /// class A { |
+ /// int x; |
+ /// A(int x) /* [x] is visible in initializers and body. */ |
+ /// : this.x = x { /* Initializer. */ |
+ /// /* Constructor body. */ |
+ /// } |
+ /// } |
+ /// |
+ /// Here the parameter shouldn't be captured into a context in the |
+ /// initializer. However, [currentFunction] is `null` if not set, and |
+ /// `function[node.variable]` in this case points to the [FunctionNode] of |
+ /// the constructor (which is not `null`). It leads to `x` being treated as |
+ /// captured, because it's seen as used outside of the function where it is |
+ /// declared. In turn, it leads to unnecessary context creation and usage. |
beginMember(node, node.function); |
- super.visitConstructor(node); |
+ saveCurrentFunction(() { |
+ currentFunction = currentMemberFunction; |
+ super.visitConstructor(node); |
+ }); |
endMember(); |
} |
@@ -158,10 +184,12 @@ class ClosureInfo extends RecursiveVisitor { |
visitFunctionNode(FunctionNode node) { |
localNames.putIfAbsent(node, computeUniqueLocalName); |
- var saved = currentFunction; |
- currentFunction = node; |
- node.visitChildren(this); |
- currentFunction = saved; |
+ |
+ saveCurrentFunction(() { |
+ currentFunction = node; |
+ node.visitChildren(this); |
+ }); |
+ |
Set<TypeParameter> capturedTypeVariables = typeVariables[node]; |
if (capturedTypeVariables != null && !isOuterMostContext) { |
// Propagate captured type variables to enclosing function. |
@@ -209,4 +237,13 @@ class ClosureInfo extends RecursiveVisitor { |
invokedGetters.add(node.name); |
super.visitPropertyGet(node); |
} |
+ |
+ saveCurrentFunction(void f()) { |
+ var saved = currentFunction; |
+ try { |
+ f(); |
+ } finally { |
+ currentFunction = saved; |
+ } |
+ } |
} |