Skip to content

Commit ec00386

Browse files
committed
Auto merge of #157309 - cjgillot:coroutine-hir-desugar, r=<try>
Desugar async blocks in HIR instead of MIR
2 parents 48f976c + d17eeb1 commit ec00386

209 files changed

Lines changed: 3915 additions & 4009 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 86 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ use rustc_ast::*;
77
use rustc_ast_pretty::pprust::expr_to_string;
88
use rustc_data_structures::stack::ensure_sufficient_stack;
99
use rustc_errors::msg;
10-
use rustc_hir as hir;
1110
use rustc_hir::def::{DefKind, Res};
12-
use rustc_hir::{HirId, Target, find_attr};
11+
use rustc_hir::{self as hir, HirId, LangItem, Target, find_attr};
1312
use rustc_middle::span_bug;
1413
use rustc_middle::ty::TyCtxt;
1514
use rustc_session::errors::report_lit_error;
@@ -359,9 +358,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
359358
GenBlockKind::Gen => hir::CoroutineDesugaring::Gen,
360359
GenBlockKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen,
361360
};
362-
self.make_desugared_coroutine_expr(
361+
return self.make_desugared_coroutine_expr(
363362
*capture_clause,
364363
e.id,
364+
expr_hir_id,
365365
None,
366366
*decl_span,
367367
e.span,
@@ -375,7 +375,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
375375
expr
376376
})
377377
},
378-
)
378+
);
379379
}
380380
ExprKind::Block(blk, opt_label) => {
381381
// Different from loops, label of block resolves to block id rather than
@@ -813,26 +813,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
813813
&mut self,
814814
capture_clause: CaptureBy,
815815
closure_node_id: NodeId,
816+
closure_hir_id: HirId,
816817
return_ty: Option<hir::FnRetTy<'hir>>,
817818
fn_decl_span: Span,
818819
span: Span,
819820
desugaring_kind: hir::CoroutineDesugaring,
820821
coroutine_source: hir::CoroutineSource,
821822
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
822-
) -> hir::ExprKind<'hir> {
823+
) -> hir::Expr<'hir> {
823824
let closure_def_id = self.local_def_id(closure_node_id);
824825
let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source);
825826

827+
let span = self.lower_span(span);
828+
let unstable_span = self.mark_span_with_reason(
829+
DesugaringKind::Async,
830+
span,
831+
Some(Arc::clone(&self.allow_gen_future)),
832+
);
833+
826834
// The `async` desugaring takes a resume argument and maintains a `task_context`,
827835
// whereas a generator does not.
828836
let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind {
829837
hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => {
830838
// Resume argument type: `ResumeTy`
831-
let unstable_span = self.mark_span_with_reason(
832-
DesugaringKind::Async,
833-
self.lower_span(span),
834-
Some(Arc::clone(&self.allow_gen_future)),
835-
);
836839
let resume_ty =
837840
self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None);
838841
let input_ty = hir::Ty {
@@ -848,21 +851,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
848851
Ident::with_dummy_span(sym::_task_context),
849852
hir::BindingMode::MUT,
850853
);
851-
let param = hir::Param {
852-
hir_id: self.next_id(),
853-
pat,
854-
ty_span: self.lower_span(span),
855-
span: self.lower_span(span),
856-
};
854+
let param = hir::Param { hir_id: self.next_id(), pat, ty_span: span, span };
857855
let params = arena_vec![self; param];
858856

859857
(inputs, params, Some(task_context_hid))
860858
}
861859
hir::CoroutineDesugaring::Gen => (&[], &[], None),
862860
};
863861

864-
let output =
865-
return_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
862+
let output = return_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(span));
866863

867864
let fn_decl = self.arena.alloc(hir::FnDecl {
868865
inputs,
@@ -884,7 +881,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
884881
});
885882

886883
// `static |<_task_context?>| -> <return_ty> { <body> }`:
887-
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
884+
let coroutine_closure = hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
888885
def_id: closure_def_id,
889886
binder: hir::ClosureBinder::Default,
890887
capture_clause: self.lower_capture_clause(capture_clause),
@@ -896,7 +893,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
896893
kind: hir::ClosureKind::Coroutine(coroutine_kind),
897894
constness: hir::Constness::NotConst,
898895
explicit_captures: &[],
899-
}))
896+
}));
897+
let coroutine_closure = hir::Expr { hir_id: closure_hir_id, kind: coroutine_closure, span };
898+
899+
let from_coroutine = match desugaring_kind {
900+
hir::CoroutineDesugaring::Async => LangItem::FutureFromCoroutine,
901+
hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIteratorFromCoroutine,
902+
hir::CoroutineDesugaring::Gen => LangItem::IterFromCoroutine,
903+
};
904+
self.expr_call_lang_item_fn_mut(
905+
unstable_span,
906+
from_coroutine,
907+
arena_vec![self; coroutine_closure],
908+
)
900909
}
901910

902911
/// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
@@ -949,19 +958,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
949958
/// }
950959
/// ```
951960
fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
961+
let full_span = expr.span.to(await_kw_span);
952962
let expr = self.arena.alloc(self.lower_expr_mut(expr));
953-
self.make_lowered_await(await_kw_span, expr, FutureKind::Future)
963+
self.make_lowered_await(await_kw_span, full_span, expr, FutureKind::Future)
954964
}
955965

956966
/// Takes an expr that has already been lowered and generates a desugared await loop around it
957967
fn make_lowered_await(
958968
&mut self,
959969
await_kw_span: Span,
970+
// Pass the span separately, as `expr.span` may be a desugaring.
971+
full_span: Span,
960972
expr: &'hir hir::Expr<'hir>,
961973
await_kind: FutureKind,
962974
) -> hir::ExprKind<'hir> {
963-
let full_span = expr.span.to(await_kw_span);
964-
965975
let is_async_gen = match self.coroutine_kind {
966976
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false,
967977
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
@@ -972,19 +982,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
972982
// is not accidentally orphaned.
973983
let stmt_id = self.next_id();
974984
let expr_err = self.expr(
975-
expr.span,
985+
full_span,
976986
hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {
977987
await_kw_span,
978988
item_span: self.current_item,
979989
})),
980990
);
981991
return hir::ExprKind::Block(
982992
self.block_all(
983-
expr.span,
993+
full_span,
984994
arena_vec![self; hir::Stmt {
985995
hir_id: stmt_id,
986996
kind: hir::StmtKind::Semi(expr),
987-
span: expr.span,
997+
span: full_span,
988998
}],
989999
Some(self.arena.alloc(expr_err)),
9901000
),
@@ -1643,18 +1653,54 @@ impl<'hir> LoweringContext<'_, 'hir> {
16431653
.emit();
16441654
}
16451655

1646-
let is_async_gen = match self.coroutine_kind {
1647-
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false,
1648-
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
1649-
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
1650-
// Lower to a block `{ EXPR; <error> }` so that the awaited expr
1651-
// is not accidentally orphaned.
1656+
let Some(coroutine_kind) = self.coroutine_kind else {
1657+
let suggestion = self.current_item.map(|s| s.shrink_to_lo());
1658+
self.dcx().emit_err(YieldInClosure { span, suggestion });
1659+
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable));
1660+
return hir::ExprKind::Yield(yielded, hir::YieldSource::Yield);
1661+
};
1662+
1663+
match coroutine_kind {
1664+
// Raw and Gen coroutines, nothing to do.
1665+
hir::CoroutineKind::Coroutine(_)
1666+
| hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => {
1667+
hir::ExprKind::Yield(yielded, hir::YieldSource::Yield)
1668+
}
1669+
// `yield $expr` is transformed into `task_context = yield async_gen_ready($expr)`.
1670+
// This ensures that we store our resumed `ResumeContext` correctly, and also that
1671+
// the apparent value of the `yield` expression is `()`.
1672+
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => {
1673+
let desugar_span = self.mark_span_with_reason(
1674+
DesugaringKind::Async,
1675+
span,
1676+
Some(Arc::clone(&self.allow_async_gen)),
1677+
);
1678+
let wrapped_yielded = self.expr_call_lang_item_fn(
1679+
desugar_span,
1680+
hir::LangItem::AsyncGenReady,
1681+
std::slice::from_ref(yielded),
1682+
);
1683+
let yield_expr = self.arena.alloc(
1684+
self.expr(span, hir::ExprKind::Yield(wrapped_yielded, hir::YieldSource::Yield)),
1685+
);
1686+
1687+
let Some(task_context_hid) = self.task_context else {
1688+
unreachable!("use of `await` outside of an async context.");
1689+
};
1690+
let task_context_ident = Ident::with_dummy_span(sym::_task_context);
1691+
let lhs = self.expr_ident(desugar_span, task_context_ident, task_context_hid);
1692+
1693+
hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span))
1694+
}
1695+
// Lower to a block `{ EXPR; <error> }` so that the awaited expr
1696+
// is not accidentally orphaned.
1697+
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => {
16521698
let stmt_id = self.next_id();
16531699
let expr_err = self.expr(
16541700
yielded.span,
16551701
hir::ExprKind::Err(self.dcx().emit_err(AsyncCoroutinesNotSupported { span })),
16561702
);
1657-
return hir::ExprKind::Block(
1703+
hir::ExprKind::Block(
16581704
self.block_all(
16591705
yielded.span,
16601706
arena_vec![self; hir::Stmt {
@@ -1665,45 +1711,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
16651711
Some(self.arena.alloc(expr_err)),
16661712
),
16671713
None,
1668-
);
1669-
}
1670-
Some(hir::CoroutineKind::Coroutine(_)) => false,
1671-
None => {
1672-
let suggestion = self.current_item.map(|s| s.shrink_to_lo());
1673-
self.dcx().emit_err(YieldInClosure { span, suggestion });
1674-
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable));
1675-
1676-
false
1714+
)
16771715
}
1678-
};
1679-
1680-
if is_async_gen {
1681-
// `yield $expr` is transformed into `task_context = yield async_gen_ready($expr)`.
1682-
// This ensures that we store our resumed `ResumeContext` correctly, and also that
1683-
// the apparent value of the `yield` expression is `()`.
1684-
let desugar_span = self.mark_span_with_reason(
1685-
DesugaringKind::Async,
1686-
span,
1687-
Some(Arc::clone(&self.allow_async_gen)),
1688-
);
1689-
let wrapped_yielded = self.expr_call_lang_item_fn(
1690-
desugar_span,
1691-
hir::LangItem::AsyncGenReady,
1692-
std::slice::from_ref(yielded),
1693-
);
1694-
let yield_expr = self.arena.alloc(
1695-
self.expr(span, hir::ExprKind::Yield(wrapped_yielded, hir::YieldSource::Yield)),
1696-
);
1697-
1698-
let Some(task_context_hid) = self.task_context else {
1699-
unreachable!("use of `await` outside of an async context.");
1700-
};
1701-
let task_context_ident = Ident::with_dummy_span(sym::_task_context);
1702-
let lhs = self.expr_ident(desugar_span, task_context_ident, task_context_hid);
1703-
1704-
hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span))
1705-
} else {
1706-
hir::ExprKind::Yield(yielded, hir::YieldSource::Yield)
17071716
}
17081717
}
17091718

@@ -1798,7 +1807,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
17981807
));
17991808
// `unsafe { ... }`
18001809
let iter = self.arena.alloc(self.expr_unsafe(head_span, iter));
1801-
let kind = self.make_lowered_await(head_span, iter, FutureKind::AsyncIterator);
1810+
let kind = self.make_lowered_await(
1811+
head_span,
1812+
head_span,
1813+
iter,
1814+
FutureKind::AsyncIterator,
1815+
);
18021816
self.arena.alloc(hir::Expr { hir_id: self.next_id(), kind, span: head_span })
18031817
}
18041818
};

compiler/rustc_ast_lowering/src/expr/closure.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -327,18 +327,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
327327
// Transform `async |x: u8| -> X { ... }` into
328328
// `|x: u8| || -> X { ... }`.
329329
let body_id = this.lower_body(|this| {
330-
let ((parameters, expr), _) = this.with_move_expr_bindings(None, |this| {
331-
this.lower_coroutine_body_with_moved_arguments(
332-
&inner_decl,
333-
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
334-
fn_decl_span,
335-
body.span,
336-
coroutine_kind,
337-
hir::CoroutineSource::Closure,
338-
)
339-
});
330+
let ((parameters, expr, coroutine_hir_id), _) =
331+
this.with_move_expr_bindings(None, |this| {
332+
this.lower_coroutine_body_with_moved_arguments(
333+
&inner_decl,
334+
|this| {
335+
this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body))
336+
},
337+
fn_decl_span,
338+
body.span,
339+
coroutine_kind,
340+
hir::CoroutineSource::Closure,
341+
)
342+
});
340343

341-
this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id);
344+
this.maybe_forward_track_caller(body.span, closure_hir_id, coroutine_hir_id);
342345

343346
(parameters, expr)
344347
});

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,18 +1506,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
15061506
};
15071507
// FIXME(contracts): Support contracts on async fn.
15081508
self.lower_body(|this| {
1509-
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
1510-
decl,
1511-
|this| this.lower_block_expr(body),
1512-
fn_decl_span,
1513-
body.span,
1514-
coroutine_kind,
1515-
hir::CoroutineSource::Fn,
1516-
);
1509+
let (parameters, expr, coroutine_hir_id) = this
1510+
.lower_coroutine_body_with_moved_arguments(
1511+
decl,
1512+
|this| this.lower_block_expr(body),
1513+
fn_decl_span,
1514+
body.span,
1515+
coroutine_kind,
1516+
hir::CoroutineSource::Fn,
1517+
);
15171518

15181519
// FIXME(async_fn_track_caller): Can this be moved above?
1519-
let hir_id = expr.hir_id;
1520-
this.maybe_forward_track_caller(body.span, fn_id, hir_id);
1520+
this.maybe_forward_track_caller(body.span, fn_id, coroutine_hir_id);
15211521

15221522
(parameters, expr)
15231523
})
@@ -1535,7 +1535,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
15351535
body_span: Span,
15361536
coroutine_kind: CoroutineKind,
15371537
coroutine_source: hir::CoroutineSource,
1538-
) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) {
1538+
) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>, HirId) {
15391539
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
15401540
let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
15411541

@@ -1699,6 +1699,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
16991699
CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
17001700
};
17011701
let closure_id = coroutine_kind.closure_id();
1702+
let closure_hir_id = self.lower_node_id(closure_id);
17021703

17031704
let coroutine_expr = self.make_desugared_coroutine_expr(
17041705
// The default capture mode here is by-ref. Later on during upvar analysis,
@@ -1707,6 +1708,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
17071708
// all async closures would default to `FnOnce` as their calling mode.
17081709
CaptureBy::Ref,
17091710
closure_id,
1711+
closure_hir_id,
17101712
None,
17111713
fn_decl_span,
17121714
body_span,
@@ -1715,13 +1717,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
17151717
mkbody,
17161718
);
17171719

1718-
let expr = hir::Expr {
1719-
hir_id: self.lower_node_id(closure_id),
1720-
kind: coroutine_expr,
1721-
span: self.lower_span(body_span),
1722-
};
1723-
1724-
(self.arena.alloc_from_iter(parameters), expr)
1720+
(self.arena.alloc_from_iter(parameters), coroutine_expr, closure_hir_id)
17251721
}
17261722

17271723
fn lower_method_sig(

0 commit comments

Comments
 (0)