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

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

Issue 2991853002: Fix duplicate context creation when closures appear in initializers. (Closed)
Patch Set: Review comments. 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,
(...skipping 10 matching lines...) Expand all
21 ForStatement, 21 ForStatement,
22 FunctionDeclaration, 22 FunctionDeclaration,
23 FunctionExpression, 23 FunctionExpression,
24 FunctionNode, 24 FunctionNode,
25 FunctionType, 25 FunctionType,
26 InterfaceType, 26 InterfaceType,
27 InvalidExpression, 27 InvalidExpression,
28 InvocationExpression, 28 InvocationExpression,
29 Library, 29 Library,
30 LocalInitializer, 30 LocalInitializer,
31 RedirectingInitializer,
31 Member, 32 Member,
32 MethodInvocation, 33 MethodInvocation,
33 Name, 34 Name,
34 NamedExpression, 35 NamedExpression,
35 NamedType, 36 NamedType,
36 NullLiteral, 37 NullLiteral,
37 Procedure, 38 Procedure,
38 ProcedureKind, 39 ProcedureKind,
39 PropertyGet, 40 PropertyGet,
40 ReturnStatement, 41 ReturnStatement,
(...skipping 13 matching lines...) Expand all
54 import '../../frontend/accessors.dart' show VariableAccessor; 55 import '../../frontend/accessors.dart' show VariableAccessor;
55 56
56 import '../../clone.dart' show CloneVisitor; 57 import '../../clone.dart' show CloneVisitor;
57 58
58 import '../../core_types.dart' show CoreTypes; 59 import '../../core_types.dart' show CoreTypes;
59 60
60 import '../../type_algebra.dart' show substitute; 61 import '../../type_algebra.dart' show substitute;
61 62
62 import 'clone_without_body.dart' show CloneWithoutBody; 63 import 'clone_without_body.dart' show CloneWithoutBody;
63 64
64 import 'context.dart' show Context, NoContext; 65 import 'context.dart' show Context, NoContext, LocalContext;
65 66
66 import 'info.dart' show ClosureInfo; 67 import 'info.dart' show ClosureInfo;
67 68
68 import 'rewriter.dart' show AstRewriter, BlockRewriter, InitializerListRewriter; 69 import 'rewriter.dart' show AstRewriter, BlockRewriter, InitializerListRewriter;
69 70
70 class ClosureConverter extends Transformer { 71 class ClosureConverter extends Transformer {
71 final CoreTypes coreTypes; 72 final CoreTypes coreTypes;
72 final Set<VariableDeclaration> capturedVariables; 73
74 // This map pairs variables that are captured with flags indicating whether
75 // they are captured inside or outside an initializer.
Dmitry Stefantsov 2017/08/01 09:36:13 Please, add a reference to the field in [ClosureIn
sjindel 2017/08/01 14:58:25 Done.
76 final Map<VariableDeclaration, int> capturedVariables;
77
73 final Map<FunctionNode, Set<TypeParameter>> capturedTypeVariables; 78 final Map<FunctionNode, Set<TypeParameter>> capturedTypeVariables;
74 final Map<FunctionNode, VariableDeclaration> thisAccess; 79 final Map<FunctionNode, VariableDeclaration> thisAccess;
75 final Map<FunctionNode, String> localNames; 80 final Map<FunctionNode, String> localNames;
76 81
77 /// Records place-holders for cloning contexts. See [visitForStatement]. 82 /// Records place-holders for cloning contexts. See [visitForStatement].
78 final Set<InvalidExpression> contextClonePlaceHolders = 83 final Set<InvalidExpression> contextClonePlaceHolders =
79 new Set<InvalidExpression>(); 84 new Set<InvalidExpression>();
80 85
81 final CloneVisitor cloner = new CloneWithoutBody(); 86 final CloneVisitor cloner = new CloneWithoutBody();
82 87
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 TreeNode visitClass(Class node) { 179 TreeNode visitClass(Class node) {
175 assert(newClassMembers.isEmpty); 180 assert(newClassMembers.isEmpty);
176 currentClass = node; 181 currentClass = node;
177 node = super.visitClass(node); 182 node = super.visitClass(node);
178 newClassMembers.forEach(node.addMember); 183 newClassMembers.forEach(node.addMember);
179 newClassMembers.clear(); 184 newClassMembers.clear();
180 currentClass = null; 185 currentClass = null;
181 return node; 186 return node;
182 } 187 }
183 188
184 void extendContextWith(VariableDeclaration parameter) { 189 extendContextConditionally({bool inInitializer}) {
185 context.extend(parameter, new VariableGet(parameter)); 190 return (VariableDeclaration parameter) {
191 int flags = capturedVariables[parameter];
192
193 // When moving variables into the context while scanning initializers,
194 // we need to add the variable if it's captured in an initializer,
195 // whether or not it's used/captured in the body. However, in the body,
196 // we only need to add the variable into the context if it's *not*
197 // captured in an initializer.
198 if (flags != null && inInitializer
199 ? (flags & ClosureInfo.INSIDE_INITIALIZER) > 0
200 : flags == ClosureInfo.OUTSIDE_INITIALIZER) {
Dmitry Stefantsov 2017/08/01 09:36:13 How about breaking this condition into many, for e
201 context.extend(parameter, new VariableGet(parameter));
202 }
203 return flags ?? 0;
204 };
186 } 205 }
187 206
188 TreeNode visitConstructor(Constructor node) { 207 TreeNode visitConstructor(Constructor node) {
189 assert(isEmptyContext); 208 assert(isEmptyContext);
190 currentMember = node; 209 currentMember = node;
191 210
211 // If we created a context for the initializers, we need to re-use that
212 // context in the body of the function. Unfortunately, the context is
213 // declared in a local initializer and local initializers aren't visible
214 // in the body of the constructor. To work around this issue, we move the
215 // body into a new constructor and make this constructor redirect to that
216 // one, passing the context as an argument to the new constructor.
217 var movingCtor = false;
218
192 // Transform initializers. 219 // Transform initializers.
193 if (node.initializers.length > 0) { 220 if (node.initializers.length > 0) {
194 var initRewriter = new InitializerListRewriter(node); 221 var initRewriter = new InitializerListRewriter(node);
195 rewriter = initRewriter; 222 rewriter = initRewriter;
196 context = new NoContext(this); 223 context = new NoContext(this);
197 224
225 int capturedBoth =
Dmitry Stefantsov 2017/08/01 09:36:13 I think using `final` modifier makes sense for thi
sjindel 2017/08/01 14:58:25 Done.
226 ClosureInfo.OUTSIDE_INITIALIZER | ClosureInfo.INSIDE_INITIALIZER;
227
198 // TODO(karlklose): add a fine-grained analysis of captured parameters. 228 // TODO(karlklose): add a fine-grained analysis of captured parameters.
199 node.function.positionalParameters 229 movingCtor = node.function.positionalParameters
200 .where(capturedVariables.contains) 230 .map(extendContextConditionally(inInitializer: true))
201 .forEach(extendContextWith); 231 .any((flags) => flags == capturedBoth) ||
202 node.function.namedParameters 232 node.function.namedParameters
203 .where(capturedVariables.contains) 233 .map(extendContextConditionally(inInitializer: true))
204 .forEach(extendContextWith); 234 .any((flags) => flags == capturedBoth);
205 235
206 transformList(node.initializers, this, node); 236 transformList(node.initializers, this, node);
207 node.initializers.insertAll(0, initRewriter.prefix); 237 node.initializers.insertAll(0, initRewriter.prefix);
208 context = rewriter = null; 238 rewriter = null;
209 } 239 }
210 240
211 // Transform constructor body. 241 // Transform constructor body.
212 FunctionNode function = node.function; 242 FunctionNode function = node.function;
213 if (function.body != null && function.body is! EmptyStatement) { 243 if (function.body != null && function.body is! EmptyStatement) {
214 setupContextForFunctionBody(function); 244 setupRewriterForFunctionBody(function);
245 if (!movingCtor) context = new NoContext(this);
215 VariableDeclaration self = thisAccess[currentMemberFunction]; 246 VariableDeclaration self = thisAccess[currentMemberFunction];
216 if (self != null) { 247 if (self != null) {
217 context.extend(self, new ThisExpression()); 248 context.extend(self, new ThisExpression());
218 } 249 }
219 node.function.accept(this); 250 node.function.accept(this);
220 resetContext(); 251
252 if (movingCtor) {
253 var contextDecl = (context as LocalContext).self;
254 var newCtorName = new Name("${node.name.name}#redir");
255 var newCtor = new Constructor(node.function, name: newCtorName);
256 newClassMembers.add(newCtor);
257
258 LocalInitializer contextDeclInit = null;
259 for (var init in node.initializers) {
260 if (init is LocalInitializer && init.variable == contextDecl) {
261 contextDeclInit = init;
262 } else {
263 newCtor.initializers.add(init);
264 }
265 }
266
267 node.initializers = node.initializers.take(1).toList();
Dmitry Stefantsov 2017/08/01 09:36:13 Here we still treat the first initializer as speci
sjindel 2017/08/01 14:58:25 Done.
268
269 var cv = new CloneVisitor();
270 var oldCtorParams = function.positionalParameters
271 .map(cv.visitVariableDeclaration)
272 .toList();
273 var oldCtorNamedParams =
274 function.namedParameters.map(cv.visitVariableDeclaration).toList();
275
276 function.positionalParameters.addAll(function.namedParameters);
277 function.namedParameters = [];
278
279 var args = <Expression>[];
280 assert(function.typeParameters.length == 0);
Dmitry Stefantsov 2017/08/01 09:36:13 If we are now sure that the [FunctionNode] of the
sjindel 2017/08/01 14:58:25 Done.
281 args.addAll(oldCtorParams.map((decl) => new VariableGet(decl)));
282 args.addAll(oldCtorNamedParams.map((decl) => new VariableGet(decl)));
283
284 node.function = new FunctionNode(new EmptyStatement(),
285 typeParameters: [],
286 positionalParameters: oldCtorParams,
287 namedParameters: oldCtorNamedParams,
288 requiredParameterCount: function.requiredParameterCount,
289 returnType: function.returnType,
290 asyncMarker: function.asyncMarker,
291 dartAsyncMarker: function.dartAsyncMarker);
292 node.function.parent = node;
293
294 var oldCtorDecl = cv.visitVariableDeclaration(contextDecl);
295 contextDecl.initializer = null;
296 function.positionalParameters.add(contextDecl);
297 function.requiredParameterCount++;
298
299 contextDeclInit.variable = oldCtorDecl;
300 oldCtorDecl.parent = contextDeclInit;
301
302 args.add(new VariableGet(oldCtorDecl));
303 var redirInit =
304 new RedirectingInitializer(newCtor, new Arguments(args));
305 node.initializers.add(redirInit);
306 }
221 } 307 }
308 resetContext();
222 return node; 309 return node;
223 } 310 }
224 311
225 AstRewriter makeRewriterForBody(FunctionNode function) { 312 AstRewriter makeRewriterForBody(FunctionNode function) {
226 Statement body = function.body; 313 Statement body = function.body;
227 if (body is! Block) { 314 if (body is! Block) {
228 body = new Block(<Statement>[body]); 315 body = new Block(<Statement>[body]);
229 function.body = function.body.parent = body; 316 function.body = function.body.parent = body;
230 } 317 }
231 return new BlockRewriter(body); 318 return new BlockRewriter(body);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 354
268 Expression result = addClosure(function, contextVariable, parent.expression, 355 Expression result = addClosure(function, contextVariable, parent.expression,
269 typeSubstitution, enclosingTypeSubstitution); 356 typeSubstitution, enclosingTypeSubstitution);
270 currentFunction = enclosingFunction; 357 currentFunction = enclosingFunction;
271 typeSubstitution = enclosingTypeSubstitution; 358 typeSubstitution = enclosingTypeSubstitution;
272 return result; 359 return result;
273 } 360 }
274 361
275 TreeNode visitFunctionDeclaration(FunctionDeclaration node) { 362 TreeNode visitFunctionDeclaration(FunctionDeclaration node) {
276 /// Is this closure itself captured by a closure? 363 /// Is this closure itself captured by a closure?
277 bool isCaptured = capturedVariables.contains(node.variable); 364 bool isCaptured = capturedVariables.containsKey(node.variable);
278 if (isCaptured) { 365 if (isCaptured) {
279 context.extend(node.variable, new InvalidExpression()); 366 context.extend(node.variable, new InvalidExpression());
280 } 367 }
281 Context parent = context; 368 Context parent = context;
282 return saveContext(() { 369 return saveContext(() {
283 Expression expression = handleLocalFunction(node.function); 370 Expression expression = handleLocalFunction(node.function);
284 371
285 if (isCaptured) { 372 if (isCaptured) {
286 parent.update(node.variable, expression); 373 parent.update(node.variable, expression);
287 return null; 374 return null;
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 closedTopLevelFunction, accessContext, closureType, fnTypeArgs); 448 closedTopLevelFunction, accessContext, closureType, fnTypeArgs);
362 } 449 }
363 450
364 TreeNode visitProcedure(Procedure node) { 451 TreeNode visitProcedure(Procedure node) {
365 assert(isEmptyContext); 452 assert(isEmptyContext);
366 453
367 currentMember = node; 454 currentMember = node;
368 455
369 FunctionNode function = node.function; 456 FunctionNode function = node.function;
370 if (function.body != null) { 457 if (function.body != null) {
371 setupContextForFunctionBody(function); 458 setupRewriterForFunctionBody(function);
459 // Start with no context. This happens after setting up _currentBlock
460 // so statements can be emitted into _currentBlock if necessary.
461 context = new NoContext(this);
462
372 VariableDeclaration self = thisAccess[currentMemberFunction]; 463 VariableDeclaration self = thisAccess[currentMemberFunction];
373 if (self != null) { 464 if (self != null) {
374 context.extend(self, new ThisExpression()); 465 context.extend(self, new ThisExpression());
375 } 466 }
376 node.transformChildren(this); 467 node.transformChildren(this);
377 resetContext(); 468 resetContext();
378 } 469 }
379 470
380 return node; 471 return node;
381 } 472 }
382 473
383 void setupContextForFunctionBody(FunctionNode function) { 474 void setupRewriterForFunctionBody(FunctionNode function) {
384 Statement body = function.body; 475 Statement body = function.body;
385 assert(body != null); 476 assert(body != null);
386 currentMemberFunction = function; 477 currentMemberFunction = function;
387 // Ensure that the body is a block which becomes the current block. 478 // Ensure that the body is a block which becomes the current block.
388 rewriter = makeRewriterForBody(function); 479 rewriter = makeRewriterForBody(function);
389 // Start with no context. This happens after setting up _currentBlock
390 // so statements can be emitted into _currentBlock if necessary.
391 context = new NoContext(this);
392 } 480 }
393 481
394 void resetContext() { 482 void resetContext() {
395 rewriter = null; 483 rewriter = null;
396 context = null; 484 context = null;
397 currentMemberFunction = null; 485 currentMemberFunction = null;
398 currentMember = null; 486 currentMember = null;
399 } 487 }
400 488
401 bool get isEmptyContext { 489 bool get isEmptyContext {
402 return rewriter == null && context == null; 490 return rewriter == null && context == null;
403 } 491 }
404 492
405 TreeNode visitLocalInitializer(LocalInitializer node) { 493 TreeNode visitLocalInitializer(LocalInitializer node) {
406 assert(!capturedVariables.contains(node.variable)); 494 assert(!capturedVariables.containsKey(node.variable));
407 node.transformChildren(this); 495 node.transformChildren(this);
408 return node; 496 return node;
409 } 497 }
410 498
411 TreeNode visitFunctionNode(FunctionNode node) { 499 TreeNode visitFunctionNode(FunctionNode node) {
412 transformList(node.typeParameters, this, node); 500 transformList(node.typeParameters, this, node);
413 // TODO: Can parameters contain initializers (e.g., for optional ones) that 501 // Initializers for optional parameters must be compile-time constants,
414 // need to be closure converted? 502 // which excludes closures.
Dmitry Stefantsov 2017/08/01 09:36:13 Looks like the cause for this comment was lost dur
sjindel 2017/08/01 14:58:25 Done.
415 node.positionalParameters 503 node.positionalParameters
416 .where(capturedVariables.contains) 504 .forEach(extendContextConditionally(inInitializer: false));
417 .forEach(extendContextWith);
418 node.namedParameters 505 node.namedParameters
419 .where(capturedVariables.contains) 506 .forEach(extendContextConditionally(inInitializer: false));
420 .forEach(extendContextWith);
421 assert(node.body != null); 507 assert(node.body != null);
422 node.body = node.body.accept(this); 508 node.body = node.body.accept(this);
423 node.body.parent = node; 509 node.body.parent = node;
424 return node; 510 return node;
425 } 511 }
426 512
427 TreeNode visitBlock(Block node) { 513 TreeNode visitBlock(Block node) {
428 return saveContext(() { 514 return saveContext(() {
429 BlockRewriter blockRewriter = rewriter = rewriter.forNestedBlock(node); 515 BlockRewriter blockRewriter = rewriter = rewriter.forNestedBlock(node);
430 blockRewriter.transformStatements(this); 516 blockRewriter.transformStatements(this);
431 return node; 517 return node;
432 }); 518 });
433 } 519 }
434 520
435 TreeNode visitVariableDeclaration(VariableDeclaration node) { 521 TreeNode visitVariableDeclaration(VariableDeclaration node) {
436 node.transformChildren(this); 522 node.transformChildren(this);
437 523
438 if (!capturedVariables.contains(node)) return node; 524 if (!capturedVariables.containsKey(node)) return node;
439 if (node.initializer == null && node.parent is FunctionNode) { 525 if (node.initializer == null && node.parent is FunctionNode) {
440 // If the variable is a function parameter and doesn't have an 526 // If the variable is a function parameter and doesn't have an
441 // initializer, just use this variable name to put it into the context. 527 // initializer, just use this variable name to put it into the context.
442 context.extend(node, new VariableGet(node)); 528 context.extend(node, new VariableGet(node));
443 } else { 529 } else {
444 context.extend(node, node.initializer ?? new NullLiteral()); 530 context.extend(node, node.initializer ?? new NullLiteral());
445 } 531 }
446 532
447 if (node.parent == currentFunction) { 533 if (node.parent == currentFunction) {
448 return node; 534 return node;
449 } else { 535 } else {
450 assert(node.parent is Block); 536 assert(node.parent is Block);
451 // When returning null, the parent block will remove 537 // When returning null, the parent block will remove
452 // this node from its list of statements. 538 // this node from its list of statements.
453 return null; 539 return null;
454 } 540 }
455 } 541 }
456 542
457 TreeNode visitVariableGet(VariableGet node) { 543 TreeNode visitVariableGet(VariableGet node) {
458 return capturedVariables.contains(node.variable) 544 return capturedVariables.containsKey(node.variable)
459 ? context.lookup(node.variable) 545 ? context.lookup(node.variable)
460 : node; 546 : node;
461 } 547 }
462 548
463 TreeNode visitVariableSet(VariableSet node) { 549 TreeNode visitVariableSet(VariableSet node) {
464 node.transformChildren(this); 550 node.transformChildren(this);
465 551
466 return capturedVariables.contains(node.variable) 552 return capturedVariables.containsKey(node.variable)
467 ? context.assign(node.variable, node.value, 553 ? context.assign(node.variable, node.value,
468 voidContext: isInVoidContext(node)) 554 voidContext: isInVoidContext(node))
469 : node; 555 : node;
470 } 556 }
471 557
472 bool isInVoidContext(Expression node) { 558 bool isInVoidContext(Expression node) {
473 TreeNode parent = node.parent; 559 TreeNode parent = node.parent;
474 return parent is ExpressionStatement || 560 return parent is ExpressionStatement ||
475 parent is ForStatement && parent.condition != node; 561 parent is ForStatement && parent.condition != node;
476 } 562 }
(...skipping 15 matching lines...) Expand all
492 InvalidExpression placeHolder = new InvalidExpression(); 578 InvalidExpression placeHolder = new InvalidExpression();
493 contextClonePlaceHolders.add(placeHolder); 579 contextClonePlaceHolders.add(placeHolder);
494 return placeHolder; 580 return placeHolder;
495 } 581 }
496 582
497 TreeNode visitInvalidExpression(InvalidExpression node) { 583 TreeNode visitInvalidExpression(InvalidExpression node) {
498 return contextClonePlaceHolders.remove(node) ? context.clone() : node; 584 return contextClonePlaceHolders.remove(node) ? context.clone() : node;
499 } 585 }
500 586
501 TreeNode visitForStatement(ForStatement node) { 587 TreeNode visitForStatement(ForStatement node) {
502 if (node.variables.any(capturedVariables.contains)) { 588 if (node.variables.any(capturedVariables.containsKey)) {
503 // In Dart, loop variables are new variables on each iteration of the 589 // In Dart, loop variables are new variables on each iteration of the
504 // loop. This is only observable when a loop variable is captured by a 590 // loop. This is only observable when a loop variable is captured by a
505 // closure, which is the situation we're in here. So we transform the 591 // closure, which is the situation we're in here. So we transform the
506 // loop. 592 // loop.
507 // 593 //
508 // Consider the following example, where `x` is `node.variables.first`, 594 // Consider the following example, where `x` is `node.variables.first`,
509 // and `#t1` is a temporary variable: 595 // and `#t1` is a temporary variable:
510 // 596 //
511 // for (var x = 0; x < 10; x++) body; 597 // for (var x = 0; x < 10; x++) body;
512 // 598 //
(...skipping 16 matching lines...) Expand all
529 node.updates.insert(0, cloneContext()); 615 node.updates.insert(0, cloneContext());
530 Block block = new Block(statements); 616 Block block = new Block(statements);
531 rewriter = new BlockRewriter(block); 617 rewriter = new BlockRewriter(block);
532 return block.accept(this); 618 return block.accept(this);
533 }); 619 });
534 } 620 }
535 return super.visitForStatement(node); 621 return super.visitForStatement(node);
536 } 622 }
537 623
538 TreeNode visitForInStatement(ForInStatement node) { 624 TreeNode visitForInStatement(ForInStatement node) {
539 if (capturedVariables.contains(node.variable)) { 625 if (capturedVariables.containsKey(node.variable)) {
540 // In Dart, loop variables are new variables on each iteration of the 626 // In Dart, loop variables are new variables on each iteration of the
541 // loop. This is only observable when the loop variable is captured by a 627 // loop. This is only observable when the loop variable is captured by a
542 // closure, so we need to transform the for-in loop when `node.variable` 628 // closure, so we need to transform the for-in loop when `node.variable`
543 // is captured. 629 // is captured.
544 // 630 //
545 // Consider the following example, where `x` is `node.variable`, and 631 // Consider the following example, where `x` is `node.variable`, and
546 // `#t1` is a temporary variable: 632 // `#t1` is a temporary variable:
547 // 633 //
548 // for (var x in expr) body; 634 // for (var x in expr) body;
549 // 635 //
(...skipping 16 matching lines...) Expand all
566 652
567 TreeNode visitThisExpression(ThisExpression node) { 653 TreeNode visitThisExpression(ThisExpression node) {
568 return isOuterMostContext 654 return isOuterMostContext
569 ? node 655 ? node
570 : context.lookup(thisAccess[currentMemberFunction]); 656 : context.lookup(thisAccess[currentMemberFunction]);
571 } 657 }
572 658
573 TreeNode visitCatch(Catch node) { 659 TreeNode visitCatch(Catch node) {
574 VariableDeclaration exception = node.exception; 660 VariableDeclaration exception = node.exception;
575 VariableDeclaration stackTrace = node.stackTrace; 661 VariableDeclaration stackTrace = node.stackTrace;
576 if (stackTrace != null && capturedVariables.contains(stackTrace)) { 662 if (stackTrace != null && capturedVariables.containsKey(stackTrace)) {
577 Block block = node.body = ensureBlock(node.body); 663 Block block = node.body = ensureBlock(node.body);
578 block.parent = node; 664 block.parent = node;
579 node.stackTrace = new VariableDeclaration(null); 665 node.stackTrace = new VariableDeclaration(null);
580 node.stackTrace.parent = node; 666 node.stackTrace.parent = node;
581 stackTrace.initializer = new VariableGet(node.stackTrace); 667 stackTrace.initializer = new VariableGet(node.stackTrace);
582 block.statements.insert(0, stackTrace); 668 block.statements.insert(0, stackTrace);
583 stackTrace.parent = block; 669 stackTrace.parent = block;
584 } 670 }
585 if (exception != null && capturedVariables.contains(exception)) { 671 if (exception != null && capturedVariables.containsKey(exception)) {
586 Block block = node.body = ensureBlock(node.body); 672 Block block = node.body = ensureBlock(node.body);
587 block.parent = node; 673 block.parent = node;
588 node.exception = new VariableDeclaration(null); 674 node.exception = new VariableDeclaration(null);
589 node.exception.parent = node; 675 node.exception.parent = node;
590 exception.initializer = new VariableGet(node.exception); 676 exception.initializer = new VariableGet(node.exception);
591 block.statements.insert(0, exception); 677 block.statements.insert(0, exception);
592 exception.parent = block; 678 exception.parent = block;
593 } 679 }
594 return super.visitCatch(node); 680 return super.visitCatch(node);
595 } 681 }
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 copy.function.body.parent = copy.function; 781 copy.function.body.parent = copy.function;
696 return copy; 782 return copy;
697 } 783 }
698 784
699 void addGetterForwarder(Name name, Procedure getter) { 785 void addGetterForwarder(Name name, Procedure getter) {
700 assert(getter.isGetter); 786 assert(getter.isGetter);
701 newClassMembers 787 newClassMembers
702 .add(copyWithBody(getter, forwardToThisProperty(getter))..name = name); 788 .add(copyWithBody(getter, forwardToThisProperty(getter))..name = name);
703 } 789 }
704 } 790 }
OLDNEW
« no previous file with comments | « no previous file | pkg/kernel/lib/transformations/closure/info.dart » ('j') | pkg/kernel/lib/transformations/closure/info.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698