@@ -263,7 +263,7 @@ impl LoweringContext<'_> {
263263 } )
264264 } )
265265 }
266- ExprKind :: Await ( ref expr) => self . lower_await ( e. span , expr) ,
266+ ExprKind :: Await ( ref expr) => self . lower_expr_await ( e. span , expr) ,
267267 ExprKind :: Closure (
268268 capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span
269269 ) => if let IsAsync :: Async { closure_id, .. } = asyncness {
@@ -375,6 +375,165 @@ impl LoweringContext<'_> {
375375 }
376376 }
377377
378+ /// Desugar `<expr>.await` into:
379+ /// ```rust
380+ /// {
381+ /// let mut pinned = <expr>;
382+ /// loop {
383+ /// match ::std::future::poll_with_tls_context(unsafe {
384+ /// ::std::pin::Pin::new_unchecked(&mut pinned)
385+ /// }) {
386+ /// ::std::task::Poll::Ready(result) => break result,
387+ /// ::std::task::Poll::Pending => {},
388+ /// }
389+ /// yield ();
390+ /// }
391+ /// }
392+ /// ```
393+ fn lower_expr_await ( & mut self , await_span : Span , expr : & Expr ) -> hir:: ExprKind {
394+ match self . generator_kind {
395+ Some ( hir:: GeneratorKind :: Async ) => { } ,
396+ Some ( hir:: GeneratorKind :: Gen ) |
397+ None => {
398+ let mut err = struct_span_err ! (
399+ self . sess,
400+ await_span,
401+ E0728 ,
402+ "`await` is only allowed inside `async` functions and blocks"
403+ ) ;
404+ err. span_label ( await_span, "only allowed inside `async` functions and blocks" ) ;
405+ if let Some ( item_sp) = self . current_item {
406+ err. span_label ( item_sp, "this is not `async`" ) ;
407+ }
408+ err. emit ( ) ;
409+ }
410+ }
411+ let span = self . mark_span_with_reason (
412+ DesugaringKind :: Await ,
413+ await_span,
414+ None ,
415+ ) ;
416+ let gen_future_span = self . mark_span_with_reason (
417+ DesugaringKind :: Await ,
418+ await_span,
419+ self . allow_gen_future . clone ( ) ,
420+ ) ;
421+
422+ // let mut pinned = <expr>;
423+ let expr = P ( self . lower_expr ( expr) ) ;
424+ let pinned_ident = Ident :: with_empty_ctxt ( sym:: pinned) ;
425+ let ( pinned_pat, pinned_pat_hid) = self . pat_ident_binding_mode (
426+ span,
427+ pinned_ident,
428+ hir:: BindingAnnotation :: Mutable ,
429+ ) ;
430+ let pinned_let = self . stmt_let_pat (
431+ ThinVec :: new ( ) ,
432+ span,
433+ Some ( expr) ,
434+ pinned_pat,
435+ hir:: LocalSource :: AwaitDesugar ,
436+ ) ;
437+
438+ // ::std::future::poll_with_tls_context(unsafe {
439+ // ::std::pin::Pin::new_unchecked(&mut pinned)
440+ // })`
441+ let poll_expr = {
442+ let pinned = P ( self . expr_ident ( span, pinned_ident, pinned_pat_hid) ) ;
443+ let ref_mut_pinned = self . expr_mut_addr_of ( span, pinned) ;
444+ let pin_ty_id = self . next_id ( ) ;
445+ let new_unchecked_expr_kind = self . expr_call_std_assoc_fn (
446+ pin_ty_id,
447+ span,
448+ & [ sym:: pin, sym:: Pin ] ,
449+ "new_unchecked" ,
450+ hir_vec ! [ ref_mut_pinned] ,
451+ ) ;
452+ let new_unchecked = P ( self . expr ( span, new_unchecked_expr_kind, ThinVec :: new ( ) ) ) ;
453+ let unsafe_expr = self . expr_unsafe ( new_unchecked) ;
454+ P ( self . expr_call_std_path (
455+ gen_future_span,
456+ & [ sym:: future, sym:: poll_with_tls_context] ,
457+ hir_vec ! [ unsafe_expr] ,
458+ ) )
459+ } ;
460+
461+ // `::std::task::Poll::Ready(result) => break result`
462+ let loop_node_id = self . sess . next_node_id ( ) ;
463+ let loop_hir_id = self . lower_node_id ( loop_node_id) ;
464+ let ready_arm = {
465+ let x_ident = Ident :: with_empty_ctxt ( sym:: result) ;
466+ let ( x_pat, x_pat_hid) = self . pat_ident ( span, x_ident) ;
467+ let x_expr = P ( self . expr_ident ( span, x_ident, x_pat_hid) ) ;
468+ let ready_pat = self . pat_std_enum (
469+ span,
470+ & [ sym:: task, sym:: Poll , sym:: Ready ] ,
471+ hir_vec ! [ x_pat] ,
472+ ) ;
473+ let break_x = self . with_loop_scope ( loop_node_id, |this| {
474+ let expr_break = hir:: ExprKind :: Break (
475+ this. lower_loop_destination ( None ) ,
476+ Some ( x_expr) ,
477+ ) ;
478+ P ( this. expr ( await_span, expr_break, ThinVec :: new ( ) ) )
479+ } ) ;
480+ self . arm ( hir_vec ! [ ready_pat] , break_x)
481+ } ;
482+
483+ // `::std::task::Poll::Pending => {}`
484+ let pending_arm = {
485+ let pending_pat = self . pat_std_enum (
486+ span,
487+ & [ sym:: task, sym:: Poll , sym:: Pending ] ,
488+ hir_vec ! [ ] ,
489+ ) ;
490+ let empty_block = P ( self . expr_block_empty ( span) ) ;
491+ self . arm ( hir_vec ! [ pending_pat] , empty_block)
492+ } ;
493+
494+ let match_stmt = {
495+ let match_expr = self . expr_match (
496+ span,
497+ poll_expr,
498+ hir_vec ! [ ready_arm, pending_arm] ,
499+ hir:: MatchSource :: AwaitDesugar ,
500+ ) ;
501+ self . stmt_expr ( span, match_expr)
502+ } ;
503+
504+ let yield_stmt = {
505+ let unit = self . expr_unit ( span) ;
506+ let yield_expr = self . expr (
507+ span,
508+ hir:: ExprKind :: Yield ( P ( unit) , hir:: YieldSource :: Await ) ,
509+ ThinVec :: new ( ) ,
510+ ) ;
511+ self . stmt_expr ( span, yield_expr)
512+ } ;
513+
514+ let loop_block = P ( self . block_all (
515+ span,
516+ hir_vec ! [ match_stmt, yield_stmt] ,
517+ None ,
518+ ) ) ;
519+
520+ let loop_expr = P ( hir:: Expr {
521+ hir_id : loop_hir_id,
522+ node : hir:: ExprKind :: Loop (
523+ loop_block,
524+ None ,
525+ hir:: LoopSource :: Loop ,
526+ ) ,
527+ span,
528+ attrs : ThinVec :: new ( ) ,
529+ } ) ;
530+
531+ hir:: ExprKind :: Block (
532+ P ( self . block_all ( span, hir_vec ! [ pinned_let] , Some ( loop_expr) ) ) ,
533+ None ,
534+ )
535+ }
536+
378537 fn lower_expr_closure (
379538 & mut self ,
380539 capture_clause : CaptureBy ,
0 commit comments