Chromium Code Reviews| 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 |