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 |