| Index: runtime/vm/parser.cc
|
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
|
| index f9664bd666ce8766eeb4873f386e798b52c06f37..a5b49ee3fc1e49a5e6d4e1ffd5c96b14da3e81aa 100644
|
| --- a/runtime/vm/parser.cc
|
| +++ b/runtime/vm/parser.cc
|
| @@ -6817,6 +6817,8 @@ void Parser::OpenAsyncTryBlock() {
|
| // This is the outermost try-catch in the function.
|
| ASSERT(try_stack_ == NULL);
|
| PushTry(current_block_);
|
| + // Validate that we always get try index of 0.
|
| + ASSERT(try_stack_->try_index() == CatchClauseNode::kImplicitAsyncTryIndex);
|
|
|
| SetupSavedTryContext(context_var);
|
| }
|
| @@ -7086,6 +7088,7 @@ void Parser::AddAsyncGeneratorVariables() {
|
| // var :async_then_callback;
|
| // var :async_catch_error_callback;
|
| // var :async_stack_trace;
|
| + // var :controller_stream;
|
| // These variables are used to store the async generator closure containing
|
| // the body of the async* function. They are used by the await operator.
|
| LocalVariable* controller_var =
|
| @@ -7108,6 +7111,10 @@ void Parser::AddAsyncGeneratorVariables() {
|
| LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| Symbols::AsyncStackTraceVar(), Object::dynamic_type());
|
| current_block_->scope->AddVariable(async_stack_trace);
|
| + LocalVariable* controller_stream = new (Z)
|
| + LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
| + Symbols::ControllerStream(), Object::dynamic_type());
|
| + current_block_->scope->AddVariable(controller_stream);
|
| }
|
|
|
|
|
| @@ -7177,7 +7184,8 @@ RawFunction* Parser::OpenAsyncGeneratorFunction(TokenPosition async_func_pos) {
|
| // var :async_then_callback = _asyncThenWrapperHelper(:async_op);
|
| // var :async_catch_error_callback = _asyncCatchErrorWrapperHelper(:async_op);
|
| // :controller = new _AsyncStarStreamController(:async_op);
|
| -// return :controller.stream;
|
| +// var :controller_stream = :controller.stream;
|
| +// return :controller_stream;
|
| // }
|
| SequenceNode* Parser::CloseAsyncGeneratorFunction(const Function& closure_func,
|
| SequenceNode* closure_body) {
|
| @@ -7208,6 +7216,9 @@ SequenceNode* Parser::CloseAsyncGeneratorFunction(const Function& closure_func,
|
| existing_var = closure_body->scope()->LookupVariable(
|
| Symbols::AsyncStackTraceVar(), false);
|
| ASSERT((existing_var != NULL) && existing_var->is_captured());
|
| + existing_var =
|
| + closure_body->scope()->LookupVariable(Symbols::ControllerStream(), false);
|
| + ASSERT((existing_var != NULL) && existing_var->is_captured());
|
|
|
| const Library& async_lib = Library::Handle(Library::AsyncLibrary());
|
|
|
| @@ -7316,13 +7327,28 @@ SequenceNode* Parser::CloseAsyncGeneratorFunction(const Function& closure_func,
|
| TokenPosition::kNoSource, controller_var, controller_constructor_call);
|
| current_block_->statements->Add(store_controller);
|
|
|
| + // Grab :controller.stream
|
| + InstanceGetterNode* controller_stream = new (Z) InstanceGetterNode(
|
| + TokenPosition::kNoSource,
|
| + new (Z) LoadLocalNode(TokenPosition::kNoSource, controller_var),
|
| + Symbols::Stream());
|
| +
|
| + // Store :controller.stream into :controller_stream inside the closure.
|
| + // We have to remember the stream because a new instance is generated for
|
| + // each getter invocation and in order to recreate the linkage, we need the
|
| + // awaited on instance.
|
| + LocalVariable* controller_stream_var =
|
| + current_block_->scope->LookupVariable(Symbols::ControllerStream(), false);
|
| + ASSERT(controller_stream_var != NULL);
|
| +
|
| + StoreLocalNode* store_controller_stream = new (Z) StoreLocalNode(
|
| + TokenPosition::kNoSource, controller_stream_var, controller_stream);
|
| + current_block_->statements->Add(store_controller_stream);
|
| +
|
| // return :controller.stream;
|
| ReturnNode* return_node = new (Z) ReturnNode(
|
| TokenPosition::kNoSource,
|
| - new (Z) InstanceGetterNode(
|
| - TokenPosition::kNoSource,
|
| - new (Z) LoadLocalNode(TokenPosition::kNoSource, controller_var),
|
| - Symbols::Stream()));
|
| + new (Z) LoadLocalNode(TokenPosition::kNoSource, controller_stream_var));
|
| current_block_->statements->Add(return_node);
|
| return CloseBlock();
|
| }
|
| @@ -9066,6 +9092,37 @@ AstNode* Parser::ParseAwaitForStatement(String* label_name) {
|
| ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
|
| ExpectToken(Token::kRPAREN);
|
|
|
| + // Create :stream to store the stream into temporarily.
|
| + LocalVariable* stream_var =
|
| + new (Z) LocalVariable(stream_expr_pos, stream_expr_pos,
|
| + Symbols::ColonStream(), Object::dynamic_type());
|
| + current_block_->scope->AddVariable(stream_var);
|
| +
|
| + // Store the stream expression into a variable.
|
| + StoreLocalNode* store_stream_var =
|
| + new (Z) StoreLocalNode(stream_expr_pos, stream_var, stream_expr);
|
| + current_block_->statements->Add(store_stream_var);
|
| +
|
| + // Register the awaiter on the stream by invoking `_asyncStarListenHelper`.
|
| + const Library& async_lib = Library::Handle(Library::AsyncLibrary());
|
| + const Function& async_star_listen_helper = Function::ZoneHandle(
|
| + Z,
|
| + async_lib.LookupFunctionAllowPrivate(Symbols::_AsyncStarListenHelper()));
|
| + ASSERT(!async_star_listen_helper.IsNull());
|
| + LocalVariable* async_op_var =
|
| + current_block_->scope->LookupVariable(Symbols::AsyncOperation(), false);
|
| + ASSERT(async_op_var != NULL);
|
| + ArgumentListNode* async_star_listen_helper_args =
|
| + new (Z) ArgumentListNode(stream_expr_pos);
|
| + async_star_listen_helper_args->Add(
|
| + new (Z) LoadLocalNode(stream_expr_pos, stream_var));
|
| + async_star_listen_helper_args->Add(
|
| + new (Z) LoadLocalNode(stream_expr_pos, async_op_var));
|
| + StaticCallNode* async_star_listen_helper_call = new (Z) StaticCallNode(
|
| + stream_expr_pos, async_star_listen_helper, async_star_listen_helper_args);
|
| +
|
| + current_block_->statements->Add(async_star_listen_helper_call);
|
| +
|
| // Build creation of implicit StreamIterator.
|
| // var :for-in-iter = new StreamIterator(stream_expr).
|
| const Class& stream_iterator_cls =
|
| @@ -9076,7 +9133,7 @@ AstNode* Parser::ParseAwaitForStatement(String* label_name) {
|
| stream_iterator_cls.LookupFunction(Symbols::StreamIteratorConstructor()));
|
| ASSERT(!iterator_ctor.IsNull());
|
| ArgumentListNode* ctor_args = new (Z) ArgumentListNode(stream_expr_pos);
|
| - ctor_args->Add(stream_expr);
|
| + ctor_args->Add(new (Z) LoadLocalNode(stream_expr_pos, stream_var));
|
| ConstructorCallNode* ctor_call = new (Z) ConstructorCallNode(
|
| stream_expr_pos, TypeArguments::ZoneHandle(Z), iterator_ctor, ctor_args);
|
| const AbstractType& iterator_type = Object::dynamic_type();
|
|
|