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

Side by Side Diff: lib/transformations/continuation.dart

Issue 2476513003: Fix a bug with await in finally. (Closed)
Patch Set: Created 4 years, 1 month 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.continuation; 5 library kernel.transformations.continuation;
6 6
7 import 'dart:math' as math; 7 import 'dart:math' as math;
8 8
9 import '../ast.dart'; 9 import '../ast.dart';
10 import '../visitor.dart'; 10 import '../visitor.dart';
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 } 174 }
175 175
176 abstract class AsyncRewriterBase extends ContinuationRewriterBase { 176 abstract class AsyncRewriterBase extends ContinuationRewriterBase {
177 final VariableDeclaration nestedClosureVariable = 177 final VariableDeclaration nestedClosureVariable =
178 new VariableDeclaration(":async_op"); 178 new VariableDeclaration(":async_op");
179 final VariableDeclaration thenContinuationVariable = 179 final VariableDeclaration thenContinuationVariable =
180 new VariableDeclaration(":async_op_then"); 180 new VariableDeclaration(":async_op_then");
181 final VariableDeclaration catchErrorContinuationVariable = 181 final VariableDeclaration catchErrorContinuationVariable =
182 new VariableDeclaration(":async_op_error"); 182 new VariableDeclaration(":async_op_error");
183 183
184 LabeledStatement labeledBody;
185
184 ExpressionLifter expressionRewriter; 186 ExpressionLifter expressionRewriter;
185 187
186 AsyncRewriterBase(helper, enclosingFunction) 188 AsyncRewriterBase(helper, enclosingFunction)
187 // Body is wrapped in the try-catch so initial currentTryDepth is 1. 189 // Body is wrapped in the try-catch so initial currentTryDepth is 1.
188 : super(helper, enclosingFunction, currentTryDepth: 1) {} 190 : super(helper, enclosingFunction, currentTryDepth: 1) {}
189 191
190 void setupAsyncContinuations(List<Statement> statements) { 192 void setupAsyncContinuations(List<Statement> statements) {
191 expressionRewriter = new ExpressionLifter(this); 193 expressionRewriter = new ExpressionLifter(this);
192 194
193 // var :async_op_then; 195 // var :async_op_then;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 final boundCatchErrorClosure = new StaticInvocation( 234 final boundCatchErrorClosure = new StaticInvocation(
233 helper.asyncErrorWrapper, 235 helper.asyncErrorWrapper,
234 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)])); 236 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)]));
235 final catchErrorClosureVariableAssign = new ExpressionStatement( 237 final catchErrorClosureVariableAssign = new ExpressionStatement(
236 new VariableSet( 238 new VariableSet(
237 catchErrorContinuationVariable, boundCatchErrorClosure)); 239 catchErrorContinuationVariable, boundCatchErrorClosure));
238 statements.add(catchErrorClosureVariableAssign); 240 statements.add(catchErrorClosureVariableAssign);
239 } 241 }
240 242
241 Statement buildWrappedBody() { 243 Statement buildWrappedBody() {
242 // No explicit return at the end of the body => we will add one! 244 labeledBody = new LabeledStatement(null);
243 var body = addReturnStatementIfNecessary(enclosingFunction.body); 245 labeledBody.body = visitDelimited(enclosingFunction.body)
244 var userBody = visitDelimited(body); 246 ..parent = labeledBody;
245 247
246 var exceptionVariable = new VariableDeclaration(":exception"); 248 var exceptionVariable = new VariableDeclaration(":exception");
247 var stackTraceVariable = new VariableDeclaration(":stack_trace"); 249 var stackTraceVariable = new VariableDeclaration(":stack_trace");
248 250
249 var completeErrorStatement = 251 return new TryCatch(buildReturn(labeledBody), <Catch>[
250 buildCatchBody(exceptionVariable, stackTraceVariable); 252 new Catch(
251 253 exceptionVariable,
252 var catchBody = new Block(<Statement>[completeErrorStatement]); 254 new Block(<Statement>[
253 var catches = <Catch>[ 255 buildCatchBody(exceptionVariable, stackTraceVariable)
254 new Catch(exceptionVariable, catchBody, stackTrace: stackTraceVariable) 256 ]),
255 ]; 257 stackTrace: stackTraceVariable)
256 return new TryCatch(userBody, catches); 258 ]);
257 }
258
259 Statement addReturnStatementIfNecessary(Statement body) {
260 if (body is Block) {
261 Block block = body;
262 if (block.statements.isEmpty ||
263 block.statements.last is! ReturnStatement) {
264 var returnStatement = new ReturnStatement();
265 block.statements.add(returnStatement);
266 returnStatement.parent = block;
267 }
268 } else if (body is! ReturnStatement) {
269 var returnStatement = new ReturnStatement();
270 body = new Block(<Statement>[body, returnStatement]);
271 }
272 return body;
273 } 259 }
274 260
275 Statement buildCatchBody( 261 Statement buildCatchBody(
276 Statement exceptionVariable, Statement stackTraceVariable); 262 Statement exceptionVariable, Statement stackTraceVariable);
277 263
264 Statement buildReturn(Statement body);
265
278 List<Statement> statements = <Statement>[]; 266 List<Statement> statements = <Statement>[];
279 267
280 TreeNode visitInvalidStatement(InvalidStatement stmt) { 268 TreeNode visitInvalidStatement(InvalidStatement stmt) {
281 statements.add(stmt); 269 statements.add(stmt);
282 return null; 270 return null;
283 } 271 }
284 272
285 TreeNode visitExpressionStatement(ExpressionStatement stmt) { 273 TreeNode visitExpressionStatement(ExpressionStatement stmt) {
286 stmt.expression = expressionRewriter.rewrite(stmt.expression, statements) 274 stmt.expression = expressionRewriter.rewrite(stmt.expression, statements)
287 ..parent = stmt; 275 ..parent = stmt;
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 stmt.condition = expressionRewriter.rewrite(stmt.condition, statements) 585 stmt.condition = expressionRewriter.rewrite(stmt.condition, statements)
598 ..parent = stmt; 586 ..parent = stmt;
599 stmt.then = visitDelimited(stmt.then)..parent = stmt; 587 stmt.then = visitDelimited(stmt.then)..parent = stmt;
600 if (stmt.otherwise != null) { 588 if (stmt.otherwise != null) {
601 stmt.otherwise = visitDelimited(stmt.otherwise)..parent = stmt; 589 stmt.otherwise = visitDelimited(stmt.otherwise)..parent = stmt;
602 } 590 }
603 statements.add(stmt); 591 statements.add(stmt);
604 return null; 592 return null;
605 } 593 }
606 594
607 TreeNode visitReturnStatement(ReturnStatement stmt) {
608 if (stmt.expression != null) {
609 stmt.expression = expressionRewriter.rewrite(stmt.expression, statements)
610 ..parent = stmt;
611 }
612 statements.add(stmt);
613 return null;
614 }
615
616 TreeNode visitTryCatch(TryCatch stmt) { 595 TreeNode visitTryCatch(TryCatch stmt) {
617 ++currentTryDepth; 596 ++currentTryDepth;
618 stmt.body = visitDelimited(stmt.body)..parent = stmt; 597 stmt.body = visitDelimited(stmt.body)..parent = stmt;
619 --currentTryDepth; 598 --currentTryDepth;
620 599
621 ++currentCatchDepth; 600 ++currentCatchDepth;
622 for (var clause in stmt.catches) { 601 for (var clause in stmt.catches) {
623 clause.body = visitDelimited(clause.body)..parent = clause; 602 clause.body = visitDelimited(clause.body)..parent = clause;
624 } 603 }
625 --currentCatchDepth; 604 --currentCatchDepth;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 AsyncStarFunctionRewriter(helper, enclosingFunction) 646 AsyncStarFunctionRewriter(helper, enclosingFunction)
668 : super(helper, enclosingFunction); 647 : super(helper, enclosingFunction);
669 648
670 FunctionNode rewrite() { 649 FunctionNode rewrite() {
671 var statements = <Statement>[]; 650 var statements = <Statement>[];
672 651
673 // var :controller; 652 // var :controller;
674 controllerVariable = new VariableDeclaration(":controller"); 653 controllerVariable = new VariableDeclaration(":controller");
675 statements.add(controllerVariable); 654 statements.add(controllerVariable);
676 655
677 super.setupAsyncContinuations(statements); 656 setupAsyncContinuations(statements);
678 657
679 // :controller = new _AsyncController(:async_op); 658 // :controller = new _AsyncController(:async_op);
680 var arguments = 659 var arguments =
681 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)]); 660 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)]);
682 var buildController = new ConstructorInvocation( 661 var buildController = new ConstructorInvocation(
683 helper.streamControllerConstructor, arguments); 662 helper.streamControllerConstructor, arguments);
684 var setController = new ExpressionStatement( 663 var setController = new ExpressionStatement(
685 new VariableSet(controllerVariable, buildController)); 664 new VariableSet(controllerVariable, buildController));
686 statements.add(setController); 665 statements.add(setController);
687 666
(...skipping 12 matching lines...) Expand all
700 Statement buildCatchBody(exceptionVariable, stackTraceVariable) { 679 Statement buildCatchBody(exceptionVariable, stackTraceVariable) {
701 return new ExpressionStatement(new MethodInvocation( 680 return new ExpressionStatement(new MethodInvocation(
702 new VariableGet(controllerVariable), 681 new VariableGet(controllerVariable),
703 new Name("completeError", helper.asyncLibrary), 682 new Name("completeError", helper.asyncLibrary),
704 new Arguments(<Expression>[ 683 new Arguments(<Expression>[
705 new VariableGet(exceptionVariable), 684 new VariableGet(exceptionVariable),
706 new VariableGet(stackTraceVariable) 685 new VariableGet(stackTraceVariable)
707 ]))); 686 ])));
708 } 687 }
709 688
689 Statement buildReturn(Statement body) {
690 // Async* functions cannot return a value. The returns from the function
691 // have been translated into breaks from the labeled body.
692 return new Block(<Statement>[
693 body,
694 new ExpressionStatement(new MethodInvocation(
695 new VariableGet(controllerVariable),
696 new Name("close", helper.asyncLibrary),
697 new Arguments(<Expression>[]))),
698 new ReturnStatement()
699 ]);
700 }
701
710 TreeNode visitYieldStatement(YieldStatement stmt) { 702 TreeNode visitYieldStatement(YieldStatement stmt) {
711 Expression expr = expressionRewriter.rewrite(stmt.expression, statements); 703 Expression expr = expressionRewriter.rewrite(stmt.expression, statements);
712 704
713 var addExpression = new MethodInvocation( 705 var addExpression = new MethodInvocation(
714 new VariableGet(controllerVariable), 706 new VariableGet(controllerVariable),
715 new Name(stmt.isYieldStar ? 'addStream' : 'add', helper.asyncLibrary), 707 new Name(stmt.isYieldStar ? 'addStream' : 'add', helper.asyncLibrary),
716 new Arguments(<Expression>[expr])); 708 new Arguments(<Expression>[expr]));
717 709
718 statements.add(new IfStatement(addExpression, 710 statements.add(new IfStatement(addExpression,
719 new ReturnStatement(new NullLiteral()), createContinuationPoint())); 711 new ReturnStatement(new NullLiteral()), createContinuationPoint()));
720 return null; 712 return null;
721 } 713 }
722 714
723 TreeNode visitReturnStatement(ReturnStatement node) { 715 TreeNode visitReturnStatement(ReturnStatement node) {
724 // async* functions cannot have normal [ReturnStatement]s in them. 716 // Async* functions cannot return a value.
725 assert(node.expression == null || node.expression is NullLiteral); 717 assert(node.expression == null || node.expression is NullLiteral);
726 718 statements.add(new BreakStatement(labeledBody));
asgerf 2016/11/03 09:32:39 Maybe copy over the breakpoint location from the r
Kevin Millikin (Google) 2016/11/03 09:43:53 Thanks, done.
727 statements.add(new ExpressionStatement(new MethodInvocation(
728 new VariableGet(controllerVariable),
729 new Name("close", helper.asyncLibrary),
730 new Arguments(<Expression>[]))));
731 statements.add(new ReturnStatement());
732 return null; 719 return null;
733 } 720 }
734 } 721 }
735 722
736 class AsyncFunctionRewriter extends AsyncRewriterBase { 723 class AsyncFunctionRewriter extends AsyncRewriterBase {
737 VariableDeclaration completerVariable; 724 VariableDeclaration completerVariable;
725 VariableDeclaration returnVariable;
738 726
739 AsyncFunctionRewriter(helper, enclosingFunction) 727 AsyncFunctionRewriter(helper, enclosingFunction)
740 : super(helper, enclosingFunction); 728 : super(helper, enclosingFunction);
741 729
742 FunctionNode rewrite() { 730 FunctionNode rewrite() {
743 var statements = <Statement>[]; 731 var statements = <Statement>[];
744 732
745 // var :completer = new Completer.sync(); 733 // var :completer = new Completer.sync();
746 completerVariable = new VariableDeclaration(":completer", 734 completerVariable = new VariableDeclaration(":completer",
747 initializer: new StaticInvocation( 735 initializer: new StaticInvocation(
748 helper.completerConstructor, new Arguments([])), 736 helper.completerConstructor, new Arguments([])),
749 isFinal: true); 737 isFinal: true);
750 statements.add(completerVariable); 738 statements.add(completerVariable);
751 739
752 super.setupAsyncContinuations(statements); 740 returnVariable = new VariableDeclaration(":return_value");
741 statements.add(returnVariable);
742
743 setupAsyncContinuations(statements);
753 744
754 // new Future.microtask(:async_op); 745 // new Future.microtask(:async_op);
755 var newMicrotaskStatement = new ExpressionStatement(new StaticInvocation( 746 var newMicrotaskStatement = new ExpressionStatement(new StaticInvocation(
756 helper.futureMicrotaskConstructor, 747 helper.futureMicrotaskConstructor,
757 new Arguments([new VariableGet(nestedClosureVariable)]))); 748 new Arguments([new VariableGet(nestedClosureVariable)])));
758 statements.add(newMicrotaskStatement); 749 statements.add(newMicrotaskStatement);
759 750
760 // return :completer.future; 751 // return :completer.future;
761 var completerGet = new VariableGet(completerVariable); 752 var completerGet = new VariableGet(completerVariable);
762 var returnStatement = new ReturnStatement( 753 var returnStatement = new ReturnStatement(
763 new PropertyGet(completerGet, new Name('future', helper.asyncLibrary))); 754 new PropertyGet(completerGet, new Name('future', helper.asyncLibrary)));
764 statements.add(returnStatement); 755 statements.add(returnStatement);
765 756
766 enclosingFunction.body = new Block(statements); 757 enclosingFunction.body = new Block(statements);
767 enclosingFunction.body.parent = enclosingFunction; 758 enclosingFunction.body.parent = enclosingFunction;
768 enclosingFunction.asyncMarker = AsyncMarker.Sync; 759 enclosingFunction.asyncMarker = AsyncMarker.Sync;
769 return enclosingFunction; 760 return enclosingFunction;
770 } 761 }
771 762
772 Statement buildCatchBody(exceptionVariable, stackTraceVariable) { 763 Statement buildCatchBody(exceptionVariable, stackTraceVariable) {
773 return new ExpressionStatement(new MethodInvocation( 764 return new ExpressionStatement(new MethodInvocation(
774 new VariableGet(completerVariable), 765 new VariableGet(completerVariable),
775 new Name("completeError", helper.asyncLibrary), 766 new Name("completeError", helper.asyncLibrary),
776 new Arguments([ 767 new Arguments([
777 new VariableGet(exceptionVariable), 768 new VariableGet(exceptionVariable),
778 new VariableGet(stackTraceVariable) 769 new VariableGet(stackTraceVariable)
779 ]))); 770 ])));
780 } 771 }
781 772
773 Statement buildReturn(Statement body) {
774 // Returns from the body have all been translated into assignments to the
775 // return value variable followed by a break from the labeled body.
776 return new Block(<Statement>[
777 body,
778 new ExpressionStatement(new MethodInvocation(
779 new VariableGet(completerVariable),
780 new Name("complete", helper.asyncLibrary),
781 new Arguments([new VariableGet(returnVariable)]))),
782 new ReturnStatement()
783 ]);
784 }
785
782 visitReturnStatement(ReturnStatement node) { 786 visitReturnStatement(ReturnStatement node) {
783 var expr; 787 var expr = node.expression == null
784 if (node.expression == null) { 788 ? new NullLiteral()
785 expr = new NullLiteral(); 789 : expressionRewriter.rewrite(node.expression, statements);
786 } else { 790 statements
787 expr = expressionRewriter.rewrite(node.expression, statements); 791 .add(new ExpressionStatement(new VariableSet(returnVariable, expr)));
788 } 792 statements.add(new BreakStatement(labeledBody));
789
790 statements.add(new ExpressionStatement(new MethodInvocation(
791 new VariableGet(completerVariable),
792 new Name("complete", helper.asyncLibrary),
793 new Arguments([expr]))));
794 statements.add(new ReturnStatement(new NullLiteral()));
795 return null; 793 return null;
796 } 794 }
797 } 795 }
798 796
799 class HelperNodes { 797 class HelperNodes {
800 final Library asyncLibrary; 798 final Library asyncLibrary;
801 final Library coreLibrary; 799 final Library coreLibrary;
802 final Procedure printProcedure; 800 final Procedure printProcedure;
803 final Procedure completerConstructor; 801 final Procedure completerConstructor;
804 final Procedure futureMicrotaskConstructor; 802 final Procedure futureMicrotaskConstructor;
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
889 findFactoryConstructor(completerClass, 'sync'), 887 findFactoryConstructor(completerClass, 'sync'),
890 findConstructor(syncIterableClass, ''), 888 findConstructor(syncIterableClass, ''),
891 findConstructor(streamIteratorClass, ''), 889 findConstructor(streamIteratorClass, ''),
892 findFactoryConstructor(futureClass, 'microtask'), 890 findFactoryConstructor(futureClass, 'microtask'),
893 findConstructor(streamControllerClass, ''), 891 findConstructor(streamControllerClass, ''),
894 findProcedure(asyncLibrary, '_asyncThenWrapperHelper'), 892 findProcedure(asyncLibrary, '_asyncThenWrapperHelper'),
895 findProcedure(asyncLibrary, '_asyncErrorWrapperHelper'), 893 findProcedure(asyncLibrary, '_asyncErrorWrapperHelper'),
896 findProcedure(asyncLibrary, '_awaitHelper')); 894 findProcedure(asyncLibrary, '_awaitHelper'));
897 } 895 }
898 } 896 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698