OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library kernel.transformations.closure.info; | 5 library kernel.transformations.closure.info; |
6 | 6 |
7 import '../../ast.dart' | 7 import '../../ast.dart' |
8 show | 8 show |
9 Class, | 9 Class, |
10 Constructor, | 10 Constructor, |
11 Field, | 11 Field, |
| 12 FieldInitializer, |
12 FunctionDeclaration, | 13 FunctionDeclaration, |
13 FunctionNode, | 14 FunctionNode, |
| 15 LocalInitializer, |
14 Member, | 16 Member, |
15 Name, | 17 Name, |
16 Procedure, | 18 Procedure, |
17 ProcedureKind, | 19 ProcedureKind, |
18 PropertyGet, | 20 PropertyGet, |
| 21 RedirectingInitializer, |
| 22 SuperInitializer, |
19 ThisExpression, | 23 ThisExpression, |
20 TypeParameter, | 24 TypeParameter, |
21 TypeParameterType, | 25 TypeParameterType, |
22 VariableDeclaration, | 26 VariableDeclaration, |
23 VariableGet, | 27 VariableGet, |
24 VariableSet; | 28 VariableSet; |
25 | 29 |
26 import '../../visitor.dart' show RecursiveVisitor; | 30 import '../../visitor.dart' show RecursiveVisitor; |
27 | 31 |
28 class ClosureInfo extends RecursiveVisitor { | 32 class ClosureInfo extends RecursiveVisitor { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 currentMemberFunction = null; | 97 currentMemberFunction = null; |
94 } | 98 } |
95 | 99 |
96 visitClass(Class node) { | 100 visitClass(Class node) { |
97 currentClass = node; | 101 currentClass = node; |
98 super.visitClass(node); | 102 super.visitClass(node); |
99 currentClass = null; | 103 currentClass = null; |
100 } | 104 } |
101 | 105 |
102 visitConstructor(Constructor node) { | 106 visitConstructor(Constructor node) { |
| 107 /// [currentFunction] should be set to [currentMemberFunction] before |
| 108 /// visiting the [FunctionNode] of the constructor, because initializers may |
| 109 /// use constructor parameters and it shouldn't be treated as capturing |
| 110 /// them. Consider the following code: |
| 111 /// |
| 112 /// class A { |
| 113 /// int x; |
| 114 /// A(int x) /* [x] is visible in initializers and body. */ |
| 115 /// : this.x = x { /* Initializer. */ |
| 116 /// /* Constructor body. */ |
| 117 /// } |
| 118 /// } |
| 119 /// |
| 120 /// Here the parameter shouldn't be captured into a context in the |
| 121 /// initializer. However, [currentFunction] is `null` if not set, and |
| 122 /// `function[node.variable]` in this case points to the [FunctionNode] of |
| 123 /// the constructor (which is not `null`). It leads to `x` being treated as |
| 124 /// captured, because it's seen as used outside of the function where it is |
| 125 /// declared. In turn, it leads to unnecessary context creation and usage. |
103 beginMember(node, node.function); | 126 beginMember(node, node.function); |
104 super.visitConstructor(node); | 127 saveCurrentFunction(() { |
| 128 currentFunction = currentMemberFunction; |
| 129 super.visitConstructor(node); |
| 130 }); |
105 endMember(); | 131 endMember(); |
106 } | 132 } |
107 | 133 |
108 visitProcedure(Procedure node) { | 134 visitProcedure(Procedure node) { |
109 beginMember(node, node.function); | 135 beginMember(node, node.function); |
110 if (node.isInstanceMember && node.kind == ProcedureKind.Method) { | 136 if (node.isInstanceMember && node.kind == ProcedureKind.Method) { |
111 // Ignore the `length` method of [File] subclasses for now, as they | 137 // Ignore the `length` method of [File] subclasses for now, as they |
112 // will force us to rename the `length` getter (kernel issue #43). | 138 // will force us to rename the `length` getter (kernel issue #43). |
113 // TODO(ahe): remove this condition. | 139 // TODO(ahe): remove this condition. |
114 Class parent = node.parent; | 140 Class parent = node.parent; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 } | 177 } |
152 | 178 |
153 visitFunctionDeclaration(FunctionDeclaration node) { | 179 visitFunctionDeclaration(FunctionDeclaration node) { |
154 assert(!localNames.containsKey(node)); | 180 assert(!localNames.containsKey(node)); |
155 localNames[node.function] = computeUniqueLocalName(node.variable.name); | 181 localNames[node.function] = computeUniqueLocalName(node.variable.name); |
156 return super.visitFunctionDeclaration(node); | 182 return super.visitFunctionDeclaration(node); |
157 } | 183 } |
158 | 184 |
159 visitFunctionNode(FunctionNode node) { | 185 visitFunctionNode(FunctionNode node) { |
160 localNames.putIfAbsent(node, computeUniqueLocalName); | 186 localNames.putIfAbsent(node, computeUniqueLocalName); |
161 var saved = currentFunction; | 187 |
162 currentFunction = node; | 188 saveCurrentFunction(() { |
163 node.visitChildren(this); | 189 currentFunction = node; |
164 currentFunction = saved; | 190 node.visitChildren(this); |
| 191 }); |
| 192 |
165 Set<TypeParameter> capturedTypeVariables = typeVariables[node]; | 193 Set<TypeParameter> capturedTypeVariables = typeVariables[node]; |
166 if (capturedTypeVariables != null && !isOuterMostContext) { | 194 if (capturedTypeVariables != null && !isOuterMostContext) { |
167 // Propagate captured type variables to enclosing function. | 195 // Propagate captured type variables to enclosing function. |
168 typeVariables | 196 typeVariables |
169 .putIfAbsent(currentFunction, () => new Set<TypeParameter>()) | 197 .putIfAbsent(currentFunction, () => new Set<TypeParameter>()) |
170 .addAll(capturedTypeVariables); | 198 .addAll(capturedTypeVariables); |
171 } | 199 } |
172 } | 200 } |
173 | 201 |
174 visitVariableDeclaration(VariableDeclaration node) { | 202 visitVariableDeclaration(VariableDeclaration node) { |
(...skipping 27 matching lines...) Expand all Loading... |
202 if (!isOuterMostContext) { | 230 if (!isOuterMostContext) { |
203 thisAccess.putIfAbsent( | 231 thisAccess.putIfAbsent( |
204 currentMemberFunction, () => new VariableDeclaration("#self")); | 232 currentMemberFunction, () => new VariableDeclaration("#self")); |
205 } | 233 } |
206 } | 234 } |
207 | 235 |
208 visitPropertyGet(PropertyGet node) { | 236 visitPropertyGet(PropertyGet node) { |
209 invokedGetters.add(node.name); | 237 invokedGetters.add(node.name); |
210 super.visitPropertyGet(node); | 238 super.visitPropertyGet(node); |
211 } | 239 } |
| 240 |
| 241 saveCurrentFunction(void f()) { |
| 242 var saved = currentFunction; |
| 243 try { |
| 244 f(); |
| 245 } finally { |
| 246 currentFunction = saved; |
| 247 } |
| 248 } |
212 } | 249 } |
OLD | NEW |