| 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 |