Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Side by Side Diff: pkg/kernel/lib/transformations/closure/converter.dart

Issue 2989563002: Preserve type variables in closure conversion. (Closed)
Patch Set: Update binary.md. Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698