Chromium Code Reviews| 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.converter; | 5 library kernel.transformations.closure.converter; |
| 6 | 6 |
| 7 import '../../ast.dart' | 7 import '../../ast.dart' |
| 8 show | 8 show |
| 9 Arguments, | 9 Arguments, |
| 10 Block, | 10 Block, |
| 11 Catch, | 11 Catch, |
| 12 Class, | 12 Class, |
| 13 ClosureCreation, | 13 ClosureCreation, |
| 14 Constructor, | 14 Constructor, |
| 15 DartType, | 15 DartType, |
| 16 DynamicType, | |
| 17 EmptyStatement, | 16 EmptyStatement, |
| 18 Expression, | 17 Expression, |
| 19 ExpressionStatement, | 18 ExpressionStatement, |
| 20 Field, | 19 Field, |
| 21 ForInStatement, | 20 ForInStatement, |
| 22 ForStatement, | 21 ForStatement, |
| 23 FunctionDeclaration, | 22 FunctionDeclaration, |
| 24 FunctionExpression, | 23 FunctionExpression, |
| 25 FunctionNode, | 24 FunctionNode, |
| 26 FunctionType, | 25 FunctionType, |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 253 assert(body != null); | 252 assert(body != null); |
| 254 | 253 |
| 255 rewriter = makeRewriterForBody(function); | 254 rewriter = makeRewriterForBody(function); |
| 256 | 255 |
| 257 VariableDeclaration contextVariable = | 256 VariableDeclaration contextVariable = |
| 258 new VariableDeclaration("#contextParameter", type: const VectorType()); | 257 new VariableDeclaration("#contextParameter", type: const VectorType()); |
| 259 Context parent = context; | 258 Context parent = context; |
| 260 context = context.toNestedContext( | 259 context = context.toNestedContext( |
| 261 new VariableAccessor(contextVariable, null, TreeNode.noOffset)); | 260 new VariableAccessor(contextVariable, null, TreeNode.noOffset)); |
| 262 | 261 |
| 263 Set<TypeParameter> captured = capturedTypeVariables[currentFunction]; | 262 Set<TypeParameter> captured = |
| 264 if (captured != null) { | 263 capturedTypeVariables[currentFunction] ?? new Set<TypeParameter>(); |
| 265 typeSubstitution = copyTypeVariables(captured); | 264 var newParams = <TypeParameter>[], newArgs = <TypeParameterType>[]; |
|
karlklose
2017/07/25 09:38:23
Use one variable declaration per variable.
sjindel
2017/07/25 13:11:48
Code removed.
| |
| 266 } else { | 265 typeSubstitution = copyTypeVariables(captured, newParams, newArgs); |
| 267 typeSubstitution = const <TypeParameter, DartType>{}; | 266 |
| 268 } | 267 /**** |
|
Dmitry Stefantsov
2017/07/25 09:13:34
Please, remove the code if it's no longer needed.
sjindel
2017/07/25 13:11:48
Done.
| |
| 269 | 268 |
| 270 // TODO(29181): remove replacementTypeSubstitution variable and its usages. | 269 // TODO(29181): remove replacementTypeSubstitution variable and its usages. |
| 271 // All the type variables used in this function body are replaced with | 270 // All the type variables used in this function body are replaced with |
| 272 // either dynamic or their bounds. This is to temporarily remove the type | 271 // either dynamic or their bounds. This is to temporarily remove the type |
| 273 // variables from closure conversion. They should be returned after the VM | 272 // variables from closure conversion. They should be returned after the VM |
| 274 // changes are done to support vectors and closure creation. See #29181. | 273 // changes are done to support vectors and closure creation. See #29181. |
| 275 Map<TypeParameter, DartType> replacementTypeSubstitution = | 274 Map<TypeParameter, DartType> replacementTypeSubstitution = |
| 276 <TypeParameter, DartType>{}; | 275 <TypeParameter, DartType>{}; |
| 277 for (TypeParameter parameter in typeSubstitution.keys) { | 276 for (TypeParameter parameter in typeSubstitution.keys) { |
| 278 replacementTypeSubstitution[parameter] = const DynamicType(); | 277 replacementTypeSubstitution[parameter] = const DynamicType(); |
| 279 } | 278 } |
| 280 for (TypeParameter parameter in typeSubstitution.keys) { | 279 for (TypeParameter parameter in typeSubstitution.keys) { |
| 281 if (!isObject(parameter.bound)) { | 280 if (!isObject(parameter.bound)) { |
| 282 replacementTypeSubstitution[parameter] = | 281 replacementTypeSubstitution[parameter] = |
| 283 substitute(parameter.bound, replacementTypeSubstitution); | 282 substitute(parameter.bound, replacementTypeSubstitution); |
| 284 } | 283 } |
| 285 } | 284 } |
| 286 typeSubstitution = replacementTypeSubstitution; | 285 typeSubstitution = replacementTypeSubstitution; |
| 287 function.transformChildren(this); | |
| 288 | 286 |
| 289 // TODO(29181): don't replace typeSubstitution with an empty map. | 287 // TODO(29181): don't replace typeSubstitution with an empty map. |
| 290 // Information about captured type variables is deleted from the closure | 288 // Information about captured type variables is deleted from the closure |
| 291 // class, because the type variables in this function body are already | 289 // class, because the type variables in this function body are already |
| 292 // replaced with either dynamic or their bounds. This change should be | 290 // replaced with either dynamic or their bounds. This change should be |
| 293 // undone after the VM support for vectors and closure creation is | 291 // undone after the VM support for vectors and closure creation is |
| 294 // implemented. See #29181. | 292 // implemented. See #29181. |
| 295 typeSubstitution = <TypeParameter, DartType>{}; | 293 typeSubstitution = <TypeParameter, DartType>{}; |
| 294 | |
| 295 ****/ | |
| 296 function.transformChildren(this); | |
| 297 | |
| 296 Expression result = addClosure(function, contextVariable, parent.expression, | 298 Expression result = addClosure(function, contextVariable, parent.expression, |
| 297 typeSubstitution, enclosingTypeSubstitution); | 299 typeSubstitution, enclosingTypeSubstitution, newParams, newArgs); |
| 298 currentFunction = enclosingFunction; | 300 currentFunction = enclosingFunction; |
| 299 typeSubstitution = enclosingTypeSubstitution; | 301 typeSubstitution = enclosingTypeSubstitution; |
| 300 return result; | 302 return result; |
| 301 } | 303 } |
| 302 | 304 |
| 303 TreeNode visitFunctionDeclaration(FunctionDeclaration node) { | 305 TreeNode visitFunctionDeclaration(FunctionDeclaration node) { |
| 304 /// Is this closure itself captured by a closure? | 306 /// Is this closure itself captured by a closure? |
| 305 bool isCaptured = capturedVariables.contains(node.variable); | 307 bool isCaptured = capturedVariables.contains(node.variable); |
| 306 if (isCaptured) { | 308 if (isCaptured) { |
| 307 context.extend(node.variable, new InvalidExpression()); | 309 context.extend(node.variable, new InvalidExpression()); |
| 308 } | 310 } |
| 309 Context parent = context; | 311 Context parent = context; |
| 310 return saveContext(() { | 312 return saveContext(() { |
| 311 Expression expression = handleLocalFunction(node.function); | 313 Expression expression = handleLocalFunction(node.function); |
| 312 | 314 |
| 313 if (isCaptured) { | 315 if (isCaptured) { |
| 314 parent.update(node.variable, expression); | 316 parent.update(node.variable, expression); |
| 315 return null; | 317 return null; |
| 316 } else { | 318 } else { |
| 317 node.variable.initializer = expression; | 319 node.variable.initializer = expression; |
| 318 expression.parent = node.variable; | 320 expression.parent = node.variable; |
| 319 return node.variable; | 321 return node.variable; |
| 320 } | 322 } |
| 321 }); | 323 }); |
| 322 } | 324 } |
| 323 | 325 |
| 324 TreeNode visitFunctionExpression(FunctionExpression node) { | 326 TreeNode visitFunctionExpression(FunctionExpression node) => |
|
karlklose
2017/07/25 09:38:23
I prefer using {} and a return statement instead o
sjindel
2017/07/25 13:11:48
Done.
| |
| 325 return saveContext(() { | 327 saveContext(() => handleLocalFunction(node.function)); |
| 326 return handleLocalFunction(node.function); | |
| 327 }); | |
| 328 } | |
| 329 | 328 |
| 330 /// Add a new procedure to the current library that looks like this: | 329 /// Add a new procedure to the current library that looks like this: |
| 331 /// | 330 /// |
| 332 /// static method closure#0(Vector #c, /* Parameters of [function]. */) | 331 /// static method closure#0(Vector #c, /* Parameters of [function]. */) |
| 333 /// → dynamic { | 332 /// → dynamic { |
| 334 /// | 333 /// |
| 335 /// /* Context is represented by #c. */ | 334 /// /* Context is represented by #c. */ |
| 336 /// | 335 /// |
| 337 /// /* Body of [function]. */ | 336 /// /* Body of [function]. */ |
| 338 /// | 337 /// |
| 339 /// } | 338 /// } |
| 340 /// | 339 /// |
| 341 /// Returns an invocation of the closure creation primitive that binds the | 340 /// Returns an invocation of the closure creation primitive that binds the |
| 342 /// above top-level function to a context represented as Vector. | 341 /// above top-level function to a context represented as Vector. |
| 343 Expression addClosure( | 342 Expression addClosure( |
| 344 FunctionNode function, | 343 FunctionNode function, |
| 345 VariableDeclaration contextVariable, | 344 VariableDeclaration contextVariable, |
| 346 Expression accessContext, | 345 Expression accessContext, |
| 347 Map<TypeParameter, DartType> substitution, | 346 Map<TypeParameter, DartType> substitution, |
| 348 Map<TypeParameter, DartType> enclosingTypeSubstitution) { | 347 Map<TypeParameter, DartType> enclosingTypeSubstitution, |
| 348 List<TypeParameter> newTypeParams, | |
| 349 List<TypeParameterType> newTypeArgs) { | |
| 350 function.typeParameters.insertAll(0, newTypeParams); | |
| 349 function.positionalParameters.insert(0, contextVariable); | 351 function.positionalParameters.insert(0, contextVariable); |
| 350 ++function.requiredParameterCount; | 352 ++function.requiredParameterCount; |
| 351 Procedure closedTopLevelFunction = new Procedure( | 353 Procedure closedTopLevelFunction = new Procedure( |
| 352 new Name(createNameForClosedTopLevelFunction(function)), | 354 new Name(createNameForClosedTopLevelFunction(function)), |
| 353 ProcedureKind.Method, | 355 ProcedureKind.Method, |
| 354 function, | 356 function, |
| 355 isStatic: true, | 357 isStatic: true, |
| 356 fileUri: currentFileUri); | 358 fileUri: currentFileUri); |
| 357 newLibraryMembers.add(closedTopLevelFunction); | 359 newLibraryMembers.add(closedTopLevelFunction); |
| 358 | 360 |
| 359 FunctionType closureType = new FunctionType( | 361 FunctionType closureType = new FunctionType( |
| 360 function.positionalParameters | 362 function.positionalParameters |
| 361 .skip(1) | 363 .skip(1) |
| 362 .map((VariableDeclaration decl) => decl.type) | 364 .map((VariableDeclaration decl) => decl.type) |
| 363 .toList(), | 365 .toList(), |
| 364 function.returnType, | 366 function.returnType, |
| 365 namedParameters: function.namedParameters | 367 namedParameters: function.namedParameters |
| 366 .map((VariableDeclaration decl) => | 368 .map((VariableDeclaration decl) => |
| 367 new NamedType(decl.name, decl.type)) | 369 new NamedType(decl.name, decl.type)) |
| 368 .toList(), | 370 .toList(), |
| 369 typeParameters: function.typeParameters, | 371 typeParameters: function.typeParameters, |
| 370 requiredParameterCount: function.requiredParameterCount - 1); | 372 requiredParameterCount: function.requiredParameterCount - 1); |
| 371 | 373 |
| 372 return new ClosureCreation( | 374 return new ClosureCreation( |
| 373 closedTopLevelFunction, accessContext, closureType); | 375 closedTopLevelFunction, accessContext, closureType, newTypeArgs); |
| 374 } | 376 } |
| 375 | 377 |
| 376 TreeNode visitProcedure(Procedure node) { | 378 TreeNode visitProcedure(Procedure node) { |
| 377 assert(isEmptyContext); | 379 assert(isEmptyContext); |
| 378 | 380 |
| 379 currentMember = node; | 381 currentMember = node; |
| 380 | 382 |
| 381 FunctionNode function = node.function; | 383 FunctionNode function = node.function; |
| 382 if (function.body != null) { | 384 if (function.body != null) { |
| 383 setupContextForFunctionBody(function); | 385 setupContextForFunctionBody(function); |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 657 return new FunctionNode(new ReturnStatement(invocation), | 659 return new FunctionNode(new ReturnStatement(invocation), |
| 658 typeParameters: typeParameters, | 660 typeParameters: typeParameters, |
| 659 positionalParameters: positionalParameters, | 661 positionalParameters: positionalParameters, |
| 660 namedParameters: namedParameters, | 662 namedParameters: namedParameters, |
| 661 requiredParameterCount: requiredParameterCount, | 663 requiredParameterCount: requiredParameterCount, |
| 662 returnType: substitute(function.returnType, cloner.typeSubstitution)); | 664 returnType: substitute(function.returnType, cloner.typeSubstitution)); |
| 663 } | 665 } |
| 664 | 666 |
| 665 /// Creates copies of the type variables in [original] and returns a | 667 /// Creates copies of the type variables in [original] and returns a |
| 666 /// substitution that can be passed to [substitute] to substitute all uses of | 668 /// substitution that can be passed to [substitute] to substitute all uses of |
| 667 /// [original] with their copies. | 669 /// [original] with their copies. Additionally returns a list of new type |
|
karlklose
2017/07/25 09:38:23
If you keep the "output parameters", please change
sjindel
2017/07/25 13:11:48
Removed code.
| |
| 670 /// parameters to prefix to the enclosing function's type parameters and the | |
| 671 /// arguments to be passed for those parameters. | |
| 672 /// | |
| 668 Map<TypeParameter, DartType> copyTypeVariables( | 673 Map<TypeParameter, DartType> copyTypeVariables( |
| 669 Iterable<TypeParameter> original) { | 674 Iterable<TypeParameter> original, |
| 675 List<TypeParameter> typeParams_out, | |
|
Dmitry Stefantsov
2017/07/25 09:13:34
As I understand it, we don't use underscores in va
Dmitry Stefantsov
2017/07/25 09:13:34
I think it's better to write a separate procedure
sjindel
2017/07/25 13:11:48
Done.
There needed in two places, and the issue wi
sjindel
2017/07/25 13:11:48
Done.
Dmitry Stefantsov
2017/07/26 09:12:09
Thanks for the explanation. Tuples would look nic
| |
| 676 List<TypeParameterType> typeArgs_out) { | |
| 670 if (original.isEmpty) return const <TypeParameter, DartType>{}; | 677 if (original.isEmpty) return const <TypeParameter, DartType>{}; |
| 678 | |
| 671 Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{}; | 679 Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{}; |
| 672 for (TypeParameter t in original) { | 680 for (TypeParameter t in original) { |
| 673 substitution[t] = new TypeParameterType(new TypeParameter(t.name)); | 681 typeArgs_out.add(new TypeParameterType(t)); |
| 682 var newParam = new TypeParameter(t.name); | |
| 683 typeParams_out.add(newParam); | |
| 684 substitution[t] = new TypeParameterType(newParam); | |
| 674 } | 685 } |
| 686 | |
| 675 substitution.forEach((TypeParameter t, DartType copy) { | 687 substitution.forEach((TypeParameter t, DartType copy) { |
| 676 if (copy is TypeParameterType) { | 688 if (copy is TypeParameterType) { |
| 677 copy.parameter.bound = substitute(t.bound, substitution); | 689 copy.parameter.bound = substitute(t.bound, substitution); |
| 678 } | 690 } |
| 679 }); | 691 }); |
| 680 return substitution; | 692 return substitution; |
| 681 } | 693 } |
| 682 | 694 |
| 683 String createNameForClosedTopLevelFunction(FunctionNode function) { | 695 String createNameForClosedTopLevelFunction(FunctionNode function) { |
| 684 return 'closure#${localNames[function]}'; | 696 return 'closure#${localNames[function]}'; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 702 copy.function.body.parent = copy.function; | 714 copy.function.body.parent = copy.function; |
| 703 return copy; | 715 return copy; |
| 704 } | 716 } |
| 705 | 717 |
| 706 void addGetterForwarder(Name name, Procedure getter) { | 718 void addGetterForwarder(Name name, Procedure getter) { |
| 707 assert(getter.isGetter); | 719 assert(getter.isGetter); |
| 708 newClassMembers | 720 newClassMembers |
| 709 .add(copyWithBody(getter, forwardToThisProperty(getter))..name = name); | 721 .add(copyWithBody(getter, forwardToThisProperty(getter))..name = name); |
| 710 } | 722 } |
| 711 } | 723 } |
| OLD | NEW |