OLD | NEW |
---|---|
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
6 | 6 |
7 import '../closure.dart'; | 7 import '../closure.dart'; |
8 import 'closure.dart'; | 8 import 'closure.dart'; |
9 | 9 |
10 /// This builder walks the code to determine what variables are captured/free at | 10 /// This builder walks the code to determine what variables are captured/free at |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
171 // parameters, and type parameters are declared in the class, not | 171 // parameters, and type parameters are declared in the class, not |
172 // the factory. | 172 // the factory. |
173 _currentScopeInfo.freeVariables.add(variable); | 173 _currentScopeInfo.freeVariables.add(variable); |
174 } | 174 } |
175 if (_inTry) { | 175 if (_inTry) { |
176 _currentScopeInfo.localsUsedInTryOrSync.add(variable); | 176 _currentScopeInfo.localsUsedInTryOrSync.add(variable); |
177 } | 177 } |
178 } | 178 } |
179 | 179 |
180 @override | 180 @override |
181 void visitThisExpression(ir.ThisExpression thisExpression) { | |
182 if (_hasThisLocal) _registerNeedsThis(); | |
183 } | |
184 | |
185 @override | |
186 void visitTypeParameter(ir.TypeParameter typeParameter) { | |
187 ir.TreeNode context = _executableContext; | |
188 if (_isInsideClosure && context is ir.Procedure && context.isFactory) { | |
189 // This is a closure in a factory constructor. Since there is no | |
190 // [:this:], we have to mark the type arguments as free variables to | |
191 // capture them in the closure. | |
192 // TODO(efortuna): Implement for in the case of RTI. | |
193 // useTypeVariableAsLocal(typeParameter.bound); | |
194 } | |
195 | |
196 if (_executableContext is ir.Member && | |
197 _executableContext is! ir.Field && | |
198 _hasThisLocal) { | |
199 // In checked mode, using a type variable in a type annotation may lead | |
200 // to a runtime type check that needs to access the type argument and | |
201 // therefore the closure needs a this-element, if it is not in a field | |
202 // initializer; field initializers are evaluated in a context where | |
203 // the type arguments are available in locals. | |
204 _registerNeedsThis(); | |
205 } | |
206 } | |
207 | |
208 /// Add `this` as a variable that needs to be accessed (and thus may become a | |
209 /// free/captured variable. | |
210 void _registerNeedsThis() { | |
211 if (_isInsideClosure) { | |
212 _currentScopeInfo.freeVariables.add(const ThisVariable()); | |
Johnni Winther
2017/08/31 07:24:38
Add a `needsThis` property on [KernelScopeInfo] in
Emily Fortuna
2017/08/31 17:40:52
Done.
| |
213 } | |
214 } | |
215 | |
216 @override | |
181 void visitForStatement(ir.ForStatement node) { | 217 void visitForStatement(ir.ForStatement node) { |
182 List<ir.VariableDeclaration> boxedLoopVariables = | 218 List<ir.VariableDeclaration> boxedLoopVariables = |
183 <ir.VariableDeclaration>[]; | 219 <ir.VariableDeclaration>[]; |
184 enterNewScope(node, () { | 220 enterNewScope(node, () { |
185 // First visit initialized variables and update steps so we can easily | 221 // First visit initialized variables and update steps so we can easily |
186 // check if a loop variable was captured in one of these subexpressions. | 222 // check if a loop variable was captured in one of these subexpressions. |
187 node.variables | 223 node.variables |
188 .forEach((ir.VariableDeclaration variable) => variable.accept(this)); | 224 .forEach((ir.VariableDeclaration variable) => variable.accept(this)); |
189 node.updates | 225 node.updates |
190 .forEach((ir.Expression expression) => expression.accept(this)); | 226 .forEach((ir.Expression expression) => expression.accept(this)); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
296 @override | 332 @override |
297 void visitFunctionExpression(ir.FunctionExpression functionExpression) { | 333 void visitFunctionExpression(ir.FunctionExpression functionExpression) { |
298 visitInvokable(functionExpression); | 334 visitInvokable(functionExpression); |
299 } | 335 } |
300 | 336 |
301 @override | 337 @override |
302 void visitFunctionDeclaration(ir.FunctionDeclaration functionDeclaration) { | 338 void visitFunctionDeclaration(ir.FunctionDeclaration functionDeclaration) { |
303 visitInvokable(functionDeclaration); | 339 visitInvokable(functionDeclaration); |
304 } | 340 } |
305 } | 341 } |
342 | |
343 /// A fake sentinel "ir" node place holder representing the usage of `this` | |
344 /// inside closures that occur inside members. | |
345 class ThisVariable implements ir.VariableDeclaration { | |
346 const ThisVariable(); | |
347 | |
348 bool get isConst => true; | |
349 set isConst(bool constVal) => | |
350 throw new UnsupportedError("ThisVariable.setIsConst"); | |
351 bool get isFinal => true; | |
352 set isFinal(bool finalValue) => | |
353 throw new UnsupportedError("ThisVariable.setIsFinal"); | |
354 bool get isCovariant => false; | |
355 set isCovariant(bool covariant) => | |
356 throw new UnsupportedError("ThisVariable.setIsCovariant"); | |
357 bool get isFieldFormal => false; | |
358 set isFieldFormal(bool formal) => | |
359 throw new UnsupportedError("ThisVariable.setIsFieldFormal"); | |
360 String get name => 'this'; | |
361 set name(String name) => throw new UnsupportedError("ThisVariable.setName"); | |
362 set type(ir.DartType type) => throw new UnsupportedError("ThisVariable.type"); | |
363 int get fileOffset => throw new UnsupportedError("ThisVariable.fileOffset"); | |
364 set fileOffset(int offset) => | |
365 throw new UnsupportedError("ThisVariable.setFileOffset"); | |
366 | |
367 int get binaryOffsetNoTag => | |
368 throw new UnsupportedError("ThisVariable.binaryOffsetNoTag"); | |
369 set binaryOffsetNoTag(int offset) => | |
370 throw new UnsupportedError("ThisVariable.binaryOffsetNoTag"); | |
371 | |
372 int get fileEqualsOffset => | |
373 throw new UnsupportedError("ThisVariable.fileEqualsOffset"); | |
374 set fileEqualsOffset(int offset) => | |
375 throw new UnsupportedError("ThisVariable.setFileEqualsOffset"); | |
376 | |
377 int get flags => throw new UnsupportedError("ThisVariable.flags"); | |
378 set flags(int flags) => throw new UnsupportedError("ThisVariable.flags"); | |
379 | |
380 ir.DartType get type => | |
381 throw new UnsupportedError("Sentinel this does not have a type."); | |
382 | |
383 ir.TreeNode get parent => | |
384 throw new UnsupportedError("Sentinel this does not have a parent."); | |
385 | |
386 set parent(ir.TreeNode parent) => | |
387 throw new UnsupportedError("Sentinel this does not have a parent."); | |
388 | |
389 ir.Expression get initializer => null; | |
390 set initializer(ir.Expression expression) => | |
391 throw new UnsupportedError("ThisVariable.setInitializer"); | |
392 | |
393 accept(ir.StatementVisitor v) => throw new UnsupportedError( | |
394 "ThisVariable should not be walked in AST traversal"); | |
395 accept1(ir.StatementVisitor1 v, arg) => throw new UnsupportedError( | |
396 "ThisVariable should not be walked in AST traversal"); | |
397 | |
398 visitChildren(ir.Visitor v) { | |
399 throw new UnsupportedError( | |
400 "ThisVariable should not be walked in AST traversal"); | |
401 } | |
402 | |
403 transformChildren(ir.Transformer v) { | |
404 throw new UnsupportedError( | |
405 "ThisVariable should not be walked in AST traversal"); | |
406 } | |
407 | |
408 void replaceChild(ir.TreeNode child, ir.TreeNode replacement) => | |
409 throw new UnsupportedError("ThisVariable.replaceChild"); | |
410 | |
411 void replaceWith(ir.TreeNode replacement) => | |
412 throw new UnsupportedError("ThisVariable.replaceWith"); | |
413 | |
414 void remove() => throw new UnsupportedError("ThisVariable.remove"); | |
415 | |
416 ir.Program get enclosingProgram => | |
417 throw new UnsupportedError("ThisVariable.enclosingProgram"); | |
418 | |
419 ir.Location get location => | |
420 throw new UnsupportedError("ThisVariable.location"); | |
421 | |
422 String toString() => 'thisVariable'; | |
423 } | |
OLD | NEW |