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

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: don't use the redirecting technique unless necessary. 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 final Map<VariableDeclaration, int /*capture flags -- see info.dart*/ >
Dmitry Stefantsov 2017/07/31 15:05:35 Please, add put this comment on its own line above
sjindel 2017/07/31 15:32:16 Done.
74 capturedVariables;
73 final Map<FunctionNode, Set<TypeParameter>> capturedTypeVariables; 75 final Map<FunctionNode, Set<TypeParameter>> capturedTypeVariables;
74 final Map<FunctionNode, VariableDeclaration> thisAccess; 76 final Map<FunctionNode, VariableDeclaration> thisAccess;
75 final Map<FunctionNode, String> localNames; 77 final Map<FunctionNode, String> localNames;
76 78
77 /// Records place-holders for cloning contexts. See [visitForStatement]. 79 /// Records place-holders for cloning contexts. See [visitForStatement].
78 final Set<InvalidExpression> contextClonePlaceHolders = 80 final Set<InvalidExpression> contextClonePlaceHolders =
79 new Set<InvalidExpression>(); 81 new Set<InvalidExpression>();
80 82
81 final CloneVisitor cloner = new CloneWithoutBody(); 83 final CloneVisitor cloner = new CloneWithoutBody();
82 84
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 TreeNode visitClass(Class node) { 176 TreeNode visitClass(Class node) {
175 assert(newClassMembers.isEmpty); 177 assert(newClassMembers.isEmpty);
176 currentClass = node; 178 currentClass = node;
177 node = super.visitClass(node); 179 node = super.visitClass(node);
178 newClassMembers.forEach(node.addMember); 180 newClassMembers.forEach(node.addMember);
179 newClassMembers.clear(); 181 newClassMembers.clear();
180 currentClass = null; 182 currentClass = null;
181 return node; 183 return node;
182 } 184 }
183 185
184 void extendContextWith(VariableDeclaration parameter) { 186 extendContextConditionally(bool inInitializer) =>
Dmitry Stefantsov 2017/07/31 15:05:35 As Karl pointed out, the arrow notation is usually
Dmitry Stefantsov 2017/07/31 15:05:35 I would suggest to make [inInitializer] a named pa
sjindel 2017/07/31 15:32:16 Done.
sjindel 2017/07/31 15:32:16 Done.
185 context.extend(parameter, new VariableGet(parameter)); 187 (VariableDeclaration parameter) {
186 } 188 var captured = capturedVariables[parameter];
Dmitry Stefantsov 2017/07/31 15:05:35 Also I think that the name [captured] is a bit mis
Dmitry Stefantsov 2017/07/31 15:05:35 I think using type annotation `int` here helps wit
sjindel 2017/07/31 15:32:16 Done.
sjindel 2017/07/31 15:32:16 Done.
189
190 // When moving variables into the context while scanning initializers,
191 // we need to add the variable if it's captured in an initializer,
192 // whether or not it's used/captured in the body. However, in the body,
193 // we only need to add the variable into the context if it's *not*
194 // captured in an initializer.
195 if (captured != null && inInitializer
196 ? (captured & ClosureInfo.INSIDE_INITIALIZER) > 0
197 : captured == ClosureInfo.OUTSIDE_INITIALIZER) {
198 context.extend(parameter, new VariableGet(parameter));
199 }
200 return captured ?? 0;
201 };
187 202
188 TreeNode visitConstructor(Constructor node) { 203 TreeNode visitConstructor(Constructor node) {
189 assert(isEmptyContext); 204 assert(isEmptyContext);
190 currentMember = node; 205 currentMember = node;
191 206
207 // If we created a context for the initializers, we need to re-use that
208 // context in the body of the function. Unfortunately, the context is
209 // declared in a local initializer and local initializers aren't visible
210 // in the body of the constructor. To work around this issue, we move the
211 // body into a new constructor and make this constructor redirect to that
212 // one, passing the context as an argument to the new constructor.
213 var movingCtor = false;
214
192 // Transform initializers. 215 // Transform initializers.
193 if (node.initializers.length > 0) { 216 if (node.initializers.length > 0) {
194 var initRewriter = new InitializerListRewriter(node); 217 var initRewriter = new InitializerListRewriter(node);
195 rewriter = initRewriter; 218 rewriter = initRewriter;
196 context = new NoContext(this); 219 context = new NoContext(this);
197 220
221 int capturedBoth =
222 ClosureInfo.OUTSIDE_INITIALIZER | ClosureInfo.INSIDE_INITIALIZER;
223
198 // TODO(karlklose): add a fine-grained analysis of captured parameters. 224 // TODO(karlklose): add a fine-grained analysis of captured parameters.
199 node.function.positionalParameters 225 movingCtor = node.function.positionalParameters
200 .where(capturedVariables.contains) 226 .map(extendContextConditionally(true))
201 .forEach(extendContextWith); 227 .any((flags) => flags == capturedBoth) ||
202 node.function.namedParameters 228 node.function.namedParameters
203 .where(capturedVariables.contains) 229 .map(extendContextConditionally(true))
204 .forEach(extendContextWith); 230 .any((flags) => flags == capturedBoth);
205 231
206 transformList(node.initializers, this, node); 232 transformList(node.initializers, this, node);
207 node.initializers.insertAll(0, initRewriter.prefix); 233 node.initializers.insertAll(0, initRewriter.prefix);
208 context = rewriter = null; 234 rewriter = null;
209 } 235 }
210 236
211 // Transform constructor body. 237 // Transform constructor body.
212 FunctionNode function = node.function; 238 FunctionNode function = node.function;
213 if (function.body != null && function.body is! EmptyStatement) { 239 if (function.body != null && function.body is! EmptyStatement) {
214 setupContextForFunctionBody(function); 240 setupContextForFunctionBody(function);
241 if (!movingCtor) context = new NoContext(this);
215 VariableDeclaration self = thisAccess[currentMemberFunction]; 242 VariableDeclaration self = thisAccess[currentMemberFunction];
216 if (self != null) { 243 if (self != null) {
217 context.extend(self, new ThisExpression()); 244 context.extend(self, new ThisExpression());
218 } 245 }
219 node.function.accept(this); 246 node.function.accept(this);
220 resetContext(); 247
248 if (movingCtor) {
249 var contextDecl = (context as LocalContext).self;
250 var newCtorName = new Name("${node.name.name}#redir");
251 var newCtor = new Constructor(node.function, name: newCtorName);
252 newClassMembers.add(newCtor);
253
254 LocalInitializer contextDeclInit = null;
255 for (var init in node.initializers) {
Dmitry Stefantsov 2017/07/31 15:05:35 This version is definitely better. I was thinking
sjindel 2017/07/31 15:32:16 True, but I feel that this approach keeps the logi
Dmitry Stefantsov 2017/08/01 09:36:13 But it's not completely isolated. I think that su
256 if (init is LocalInitializer && init.variable == contextDecl) {
257 contextDeclInit = init;
258 } else {
259 newCtor.initializers.add(init);
260 }
261 }
262
263 node.initializers = node.initializers.take(1).toList();
264
265 var cv = new CloneVisitor();
266 var oldCtorParams = function.positionalParameters
267 .map(cv.visitVariableDeclaration)
268 .toList();
269 var oldCtorNamedParams =
270 function.namedParameters.map(cv.visitVariableDeclaration).toList();
271
272 function.positionalParameters.addAll(function.namedParameters);
273 function.namedParameters = [];
274
275 var args = <Expression>[];
276 assert(function.typeParameters.length == 0);
277 args.addAll(oldCtorParams.map((decl) => new VariableGet(decl)));
278 args.addAll(oldCtorNamedParams.map((decl) => new VariableGet(decl)));
279
280 node.function = new FunctionNode(new EmptyStatement(),
281 typeParameters: [],
282 positionalParameters: oldCtorParams,
283 namedParameters: oldCtorNamedParams,
284 requiredParameterCount: function.requiredParameterCount,
285 returnType: function.returnType,
286 asyncMarker: function.asyncMarker,
287 dartAsyncMarker: function.dartAsyncMarker);
288 node.function.parent = node;
289
290 var oldCtorDecl = cv.visitVariableDeclaration(contextDecl);
291 contextDecl.initializer = null;
292 function.positionalParameters.add(contextDecl);
293 function.requiredParameterCount++;
294
295 contextDeclInit.variable = oldCtorDecl;
296 oldCtorDecl.parent = contextDeclInit;
297
298 args.add(new VariableGet(oldCtorDecl));
299 var redirInit =
300 new RedirectingInitializer(newCtor, new Arguments(args));
301 node.initializers.add(redirInit);
302 }
221 } 303 }
304 resetContext();
222 return node; 305 return node;
223 } 306 }
224 307
225 AstRewriter makeRewriterForBody(FunctionNode function) { 308 AstRewriter makeRewriterForBody(FunctionNode function) {
226 Statement body = function.body; 309 Statement body = function.body;
227 if (body is! Block) { 310 if (body is! Block) {
228 body = new Block(<Statement>[body]); 311 body = new Block(<Statement>[body]);
229 function.body = function.body.parent = body; 312 function.body = function.body.parent = body;
230 } 313 }
231 return new BlockRewriter(body); 314 return new BlockRewriter(body);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 350
268 Expression result = addClosure(function, contextVariable, parent.expression, 351 Expression result = addClosure(function, contextVariable, parent.expression,
269 typeSubstitution, enclosingTypeSubstitution); 352 typeSubstitution, enclosingTypeSubstitution);
270 currentFunction = enclosingFunction; 353 currentFunction = enclosingFunction;
271 typeSubstitution = enclosingTypeSubstitution; 354 typeSubstitution = enclosingTypeSubstitution;
272 return result; 355 return result;
273 } 356 }
274 357
275 TreeNode visitFunctionDeclaration(FunctionDeclaration node) { 358 TreeNode visitFunctionDeclaration(FunctionDeclaration node) {
276 /// Is this closure itself captured by a closure? 359 /// Is this closure itself captured by a closure?
277 bool isCaptured = capturedVariables.contains(node.variable); 360 bool isCaptured = capturedVariables.containsKey(node.variable);
278 if (isCaptured) { 361 if (isCaptured) {
279 context.extend(node.variable, new InvalidExpression()); 362 context.extend(node.variable, new InvalidExpression());
280 } 363 }
281 Context parent = context; 364 Context parent = context;
282 return saveContext(() { 365 return saveContext(() {
283 Expression expression = handleLocalFunction(node.function); 366 Expression expression = handleLocalFunction(node.function);
284 367
285 if (isCaptured) { 368 if (isCaptured) {
286 parent.update(node.variable, expression); 369 parent.update(node.variable, expression);
287 return null; 370 return null;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 } 445 }
363 446
364 TreeNode visitProcedure(Procedure node) { 447 TreeNode visitProcedure(Procedure node) {
365 assert(isEmptyContext); 448 assert(isEmptyContext);
366 449
367 currentMember = node; 450 currentMember = node;
368 451
369 FunctionNode function = node.function; 452 FunctionNode function = node.function;
370 if (function.body != null) { 453 if (function.body != null) {
371 setupContextForFunctionBody(function); 454 setupContextForFunctionBody(function);
455 // Start with no context. This happens after setting up _currentBlock
456 // so statements can be emitted into _currentBlock if necessary.
457 context = new NoContext(this);
Dmitry Stefantsov 2017/07/31 15:05:35 Why was [context] initialization moved here?
sjindel 2017/07/31 15:32:16 It didn't really make sense to do it in the functi
Dmitry Stefantsov 2017/08/01 09:36:13 If we had a special kind of rewriter for the case
458
372 VariableDeclaration self = thisAccess[currentMemberFunction]; 459 VariableDeclaration self = thisAccess[currentMemberFunction];
373 if (self != null) { 460 if (self != null) {
374 context.extend(self, new ThisExpression()); 461 context.extend(self, new ThisExpression());
375 } 462 }
376 node.transformChildren(this); 463 node.transformChildren(this);
377 resetContext(); 464 resetContext();
378 } 465 }
379 466
380 return node; 467 return node;
381 } 468 }
382 469
383 void setupContextForFunctionBody(FunctionNode function) { 470 void setupContextForFunctionBody(FunctionNode function) {
Dmitry Stefantsov 2017/07/31 15:05:35 Now this function name is misleading, after actual
sjindel 2017/07/31 15:32:16 Done.
384 Statement body = function.body; 471 Statement body = function.body;
385 assert(body != null); 472 assert(body != null);
386 currentMemberFunction = function; 473 currentMemberFunction = function;
387 // Ensure that the body is a block which becomes the current block. 474 // Ensure that the body is a block which becomes the current block.
388 rewriter = makeRewriterForBody(function); 475 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 } 476 }
393 477
394 void resetContext() { 478 void resetContext() {
395 rewriter = null; 479 rewriter = null;
396 context = null; 480 context = null;
397 currentMemberFunction = null; 481 currentMemberFunction = null;
398 currentMember = null; 482 currentMember = null;
399 } 483 }
400 484
401 bool get isEmptyContext { 485 bool get isEmptyContext {
402 return rewriter == null && context == null; 486 return rewriter == null && context == null;
403 } 487 }
404 488
405 TreeNode visitLocalInitializer(LocalInitializer node) { 489 TreeNode visitLocalInitializer(LocalInitializer node) {
406 assert(!capturedVariables.contains(node.variable)); 490 assert(!capturedVariables.containsKey(node.variable));
407 node.transformChildren(this); 491 node.transformChildren(this);
408 return node; 492 return node;
409 } 493 }
410 494
411 TreeNode visitFunctionNode(FunctionNode node) { 495 TreeNode visitFunctionNode(FunctionNode node) {
412 transformList(node.typeParameters, this, node); 496 transformList(node.typeParameters, this, node);
413 // TODO: Can parameters contain initializers (e.g., for optional ones) that 497 // Initializers for optional parameters must be compile-time constants,
414 // need to be closure converted? 498 // which excludes closures.
415 node.positionalParameters 499 node.positionalParameters.forEach(extendContextConditionally(false));
416 .where(capturedVariables.contains) 500 node.namedParameters.forEach(extendContextConditionally(false));
417 .forEach(extendContextWith);
418 node.namedParameters
419 .where(capturedVariables.contains)
420 .forEach(extendContextWith);
421 assert(node.body != null); 501 assert(node.body != null);
422 node.body = node.body.accept(this); 502 node.body = node.body.accept(this);
423 node.body.parent = node; 503 node.body.parent = node;
424 return node; 504 return node;
425 } 505 }
426 506
427 TreeNode visitBlock(Block node) { 507 TreeNode visitBlock(Block node) {
428 return saveContext(() { 508 return saveContext(() {
429 BlockRewriter blockRewriter = rewriter = rewriter.forNestedBlock(node); 509 BlockRewriter blockRewriter = rewriter = rewriter.forNestedBlock(node);
430 blockRewriter.transformStatements(this); 510 blockRewriter.transformStatements(this);
431 return node; 511 return node;
432 }); 512 });
433 } 513 }
434 514
435 TreeNode visitVariableDeclaration(VariableDeclaration node) { 515 TreeNode visitVariableDeclaration(VariableDeclaration node) {
436 node.transformChildren(this); 516 node.transformChildren(this);
437 517
438 if (!capturedVariables.contains(node)) return node; 518 if (!capturedVariables.containsKey(node)) return node;
439 if (node.initializer == null && node.parent is FunctionNode) { 519 if (node.initializer == null && node.parent is FunctionNode) {
440 // If the variable is a function parameter and doesn't have an 520 // 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. 521 // initializer, just use this variable name to put it into the context.
442 context.extend(node, new VariableGet(node)); 522 context.extend(node, new VariableGet(node));
443 } else { 523 } else {
444 context.extend(node, node.initializer ?? new NullLiteral()); 524 context.extend(node, node.initializer ?? new NullLiteral());
445 } 525 }
446 526
447 if (node.parent == currentFunction) { 527 if (node.parent == currentFunction) {
448 return node; 528 return node;
449 } else { 529 } else {
450 assert(node.parent is Block); 530 assert(node.parent is Block);
451 // When returning null, the parent block will remove 531 // When returning null, the parent block will remove
452 // this node from its list of statements. 532 // this node from its list of statements.
453 return null; 533 return null;
454 } 534 }
455 } 535 }
456 536
457 TreeNode visitVariableGet(VariableGet node) { 537 TreeNode visitVariableGet(VariableGet node) {
458 return capturedVariables.contains(node.variable) 538 return capturedVariables.containsKey(node.variable)
459 ? context.lookup(node.variable) 539 ? context.lookup(node.variable)
460 : node; 540 : node;
461 } 541 }
462 542
463 TreeNode visitVariableSet(VariableSet node) { 543 TreeNode visitVariableSet(VariableSet node) {
464 node.transformChildren(this); 544 node.transformChildren(this);
465 545
466 return capturedVariables.contains(node.variable) 546 return capturedVariables.containsKey(node.variable)
467 ? context.assign(node.variable, node.value, 547 ? context.assign(node.variable, node.value,
468 voidContext: isInVoidContext(node)) 548 voidContext: isInVoidContext(node))
469 : node; 549 : node;
470 } 550 }
471 551
472 bool isInVoidContext(Expression node) { 552 bool isInVoidContext(Expression node) {
473 TreeNode parent = node.parent; 553 TreeNode parent = node.parent;
474 return parent is ExpressionStatement || 554 return parent is ExpressionStatement ||
475 parent is ForStatement && parent.condition != node; 555 parent is ForStatement && parent.condition != node;
476 } 556 }
(...skipping 15 matching lines...) Expand all
492 InvalidExpression placeHolder = new InvalidExpression(); 572 InvalidExpression placeHolder = new InvalidExpression();
493 contextClonePlaceHolders.add(placeHolder); 573 contextClonePlaceHolders.add(placeHolder);
494 return placeHolder; 574 return placeHolder;
495 } 575 }
496 576
497 TreeNode visitInvalidExpression(InvalidExpression node) { 577 TreeNode visitInvalidExpression(InvalidExpression node) {
498 return contextClonePlaceHolders.remove(node) ? context.clone() : node; 578 return contextClonePlaceHolders.remove(node) ? context.clone() : node;
499 } 579 }
500 580
501 TreeNode visitForStatement(ForStatement node) { 581 TreeNode visitForStatement(ForStatement node) {
502 if (node.variables.any(capturedVariables.contains)) { 582 if (node.variables.any(capturedVariables.containsKey)) {
503 // In Dart, loop variables are new variables on each iteration of the 583 // 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 584 // 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 585 // closure, which is the situation we're in here. So we transform the
506 // loop. 586 // loop.
507 // 587 //
508 // Consider the following example, where `x` is `node.variables.first`, 588 // Consider the following example, where `x` is `node.variables.first`,
509 // and `#t1` is a temporary variable: 589 // and `#t1` is a temporary variable:
510 // 590 //
511 // for (var x = 0; x < 10; x++) body; 591 // for (var x = 0; x < 10; x++) body;
512 // 592 //
(...skipping 16 matching lines...) Expand all
529 node.updates.insert(0, cloneContext()); 609 node.updates.insert(0, cloneContext());
530 Block block = new Block(statements); 610 Block block = new Block(statements);
531 rewriter = new BlockRewriter(block); 611 rewriter = new BlockRewriter(block);
532 return block.accept(this); 612 return block.accept(this);
533 }); 613 });
534 } 614 }
535 return super.visitForStatement(node); 615 return super.visitForStatement(node);
536 } 616 }
537 617
538 TreeNode visitForInStatement(ForInStatement node) { 618 TreeNode visitForInStatement(ForInStatement node) {
539 if (capturedVariables.contains(node.variable)) { 619 if (capturedVariables.containsKey(node.variable)) {
540 // In Dart, loop variables are new variables on each iteration of the 620 // 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 621 // 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` 622 // closure, so we need to transform the for-in loop when `node.variable`
543 // is captured. 623 // is captured.
544 // 624 //
545 // Consider the following example, where `x` is `node.variable`, and 625 // Consider the following example, where `x` is `node.variable`, and
546 // `#t1` is a temporary variable: 626 // `#t1` is a temporary variable:
547 // 627 //
548 // for (var x in expr) body; 628 // for (var x in expr) body;
549 // 629 //
(...skipping 16 matching lines...) Expand all
566 646
567 TreeNode visitThisExpression(ThisExpression node) { 647 TreeNode visitThisExpression(ThisExpression node) {
568 return isOuterMostContext 648 return isOuterMostContext
569 ? node 649 ? node
570 : context.lookup(thisAccess[currentMemberFunction]); 650 : context.lookup(thisAccess[currentMemberFunction]);
571 } 651 }
572 652
573 TreeNode visitCatch(Catch node) { 653 TreeNode visitCatch(Catch node) {
574 VariableDeclaration exception = node.exception; 654 VariableDeclaration exception = node.exception;
575 VariableDeclaration stackTrace = node.stackTrace; 655 VariableDeclaration stackTrace = node.stackTrace;
576 if (stackTrace != null && capturedVariables.contains(stackTrace)) { 656 if (stackTrace != null && capturedVariables.containsKey(stackTrace)) {
577 Block block = node.body = ensureBlock(node.body); 657 Block block = node.body = ensureBlock(node.body);
578 block.parent = node; 658 block.parent = node;
579 node.stackTrace = new VariableDeclaration(null); 659 node.stackTrace = new VariableDeclaration(null);
580 node.stackTrace.parent = node; 660 node.stackTrace.parent = node;
581 stackTrace.initializer = new VariableGet(node.stackTrace); 661 stackTrace.initializer = new VariableGet(node.stackTrace);
582 block.statements.insert(0, stackTrace); 662 block.statements.insert(0, stackTrace);
583 stackTrace.parent = block; 663 stackTrace.parent = block;
584 } 664 }
585 if (exception != null && capturedVariables.contains(exception)) { 665 if (exception != null && capturedVariables.containsKey(exception)) {
586 Block block = node.body = ensureBlock(node.body); 666 Block block = node.body = ensureBlock(node.body);
587 block.parent = node; 667 block.parent = node;
588 node.exception = new VariableDeclaration(null); 668 node.exception = new VariableDeclaration(null);
589 node.exception.parent = node; 669 node.exception.parent = node;
590 exception.initializer = new VariableGet(node.exception); 670 exception.initializer = new VariableGet(node.exception);
591 block.statements.insert(0, exception); 671 block.statements.insert(0, exception);
592 exception.parent = block; 672 exception.parent = block;
593 } 673 }
594 return super.visitCatch(node); 674 return super.visitCatch(node);
595 } 675 }
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 copy.function.body.parent = copy.function; 775 copy.function.body.parent = copy.function;
696 return copy; 776 return copy;
697 } 777 }
698 778
699 void addGetterForwarder(Name name, Procedure getter) { 779 void addGetterForwarder(Name name, Procedure getter) {
700 assert(getter.isGetter); 780 assert(getter.isGetter);
701 newClassMembers 781 newClassMembers
702 .add(copyWithBody(getter, forwardToThisProperty(getter))..name = name); 782 .add(copyWithBody(getter, forwardToThisProperty(getter))..name = name);
703 } 783 }
704 } 784 }
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