rustc_ast_lowering/
expr.rs

1use std::assert_matches::assert_matches;
2use std::ops::ControlFlow;
3use std::sync::Arc;
4
5use rustc_ast::ptr::P as AstP;
6use rustc_ast::*;
7use rustc_ast_pretty::pprust::expr_to_string;
8use rustc_data_structures::stack::ensure_sufficient_stack;
9use rustc_hir as hir;
10use rustc_hir::HirId;
11use rustc_hir::def::{DefKind, Res};
12use rustc_middle::span_bug;
13use rustc_middle::ty::TyCtxt;
14use rustc_session::errors::report_lit_error;
15use rustc_span::source_map::{Spanned, respan};
16use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
17use thin_vec::{ThinVec, thin_vec};
18use visit::{Visitor, walk_expr};
19
20use super::errors::{
21    AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, ClosureCannotBeStatic,
22    CoroutineTooManyParameters, FunctionalRecordUpdateDestructuringAssignment,
23    InclusiveRangeWithNoEnd, MatchArmWithNoBody, NeverPatternWithBody, NeverPatternWithGuard,
24    UnderscoreExprLhsAssign,
25};
26use super::{
27    GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
28};
29use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
30use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, fluent_generated};
31
32struct WillCreateDefIdsVisitor {}
33
34impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor {
35    type Result = ControlFlow<Span>;
36
37    fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
38        ControlFlow::Break(c.value.span)
39    }
40
41    fn visit_item(&mut self, item: &'v Item) -> Self::Result {
42        ControlFlow::Break(item.span)
43    }
44
45    fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result {
46        match ex.kind {
47            ExprKind::Gen(..) | ExprKind::ConstBlock(..) | ExprKind::Closure(..) => {
48                ControlFlow::Break(ex.span)
49            }
50            _ => walk_expr(self, ex),
51        }
52    }
53}
54
55impl<'hir> LoweringContext<'_, 'hir> {
56    fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
57        self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
58    }
59
60    pub(super) fn lower_expr(&mut self, e: &Expr) -> &'hir hir::Expr<'hir> {
61        self.arena.alloc(self.lower_expr_mut(e))
62    }
63
64    pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
65        ensure_sufficient_stack(|| {
66            match &e.kind {
67                // Parenthesis expression does not have a HirId and is handled specially.
68                ExprKind::Paren(ex) => {
69                    let mut ex = self.lower_expr_mut(ex);
70                    // Include parens in span, but only if it is a super-span.
71                    if e.span.contains(ex.span) {
72                        ex.span = self.lower_span(e.span);
73                    }
74                    // Merge attributes into the inner expression.
75                    if !e.attrs.is_empty() {
76                        let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]);
77                        self.attrs.insert(
78                            ex.hir_id.local_id,
79                            &*self.arena.alloc_from_iter(
80                                self.lower_attrs_vec(&e.attrs, e.span)
81                                    .into_iter()
82                                    .chain(old_attrs.iter().cloned()),
83                            ),
84                        );
85                    }
86                    return ex;
87                }
88                // Desugar `ExprForLoop`
89                // from: `[opt_ident]: for await? <pat> in <iter> <body>`
90                //
91                // This also needs special handling because the HirId of the returned `hir::Expr` will not
92                // correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.
93                ExprKind::ForLoop { pat, iter, body, label, kind } => {
94                    return self.lower_expr_for(e, pat, iter, body, *label, *kind);
95                }
96                _ => (),
97            }
98
99            let expr_hir_id = self.lower_node_id(e.id);
100            self.lower_attrs(expr_hir_id, &e.attrs, e.span);
101
102            let kind = match &e.kind {
103                ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
104                ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)),
105                ExprKind::Repeat(expr, count) => {
106                    let expr = self.lower_expr(expr);
107                    let count = self.lower_array_length_to_const_arg(count);
108                    hir::ExprKind::Repeat(expr, count)
109                }
110                ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
111                ExprKind::Call(f, args) => {
112                    if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
113                        self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)
114                    } else {
115                        let f = self.lower_expr(f);
116                        hir::ExprKind::Call(f, self.lower_exprs(args))
117                    }
118                }
119                ExprKind::MethodCall(box MethodCall { seg, receiver, args, span }) => {
120                    let hir_seg = self.arena.alloc(self.lower_path_segment(
121                        e.span,
122                        seg,
123                        ParamMode::Optional,
124                        GenericArgsMode::Err,
125                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
126                        // Method calls can't have bound modifiers
127                        None,
128                    ));
129                    let receiver = self.lower_expr(receiver);
130                    let args =
131                        self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x)));
132                    hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(*span))
133                }
134                ExprKind::Binary(binop, lhs, rhs) => {
135                    let binop = self.lower_binop(*binop);
136                    let lhs = self.lower_expr(lhs);
137                    let rhs = self.lower_expr(rhs);
138                    hir::ExprKind::Binary(binop, lhs, rhs)
139                }
140                ExprKind::Unary(op, ohs) => {
141                    let op = self.lower_unop(*op);
142                    let ohs = self.lower_expr(ohs);
143                    hir::ExprKind::Unary(op, ohs)
144                }
145                ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)),
146                ExprKind::IncludedBytes(bytes) => {
147                    let lit = self.arena.alloc(respan(
148                        self.lower_span(e.span),
149                        LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked),
150                    ));
151                    hir::ExprKind::Lit(lit)
152                }
153                ExprKind::Cast(expr, ty) => {
154                    let expr = self.lower_expr(expr);
155                    let ty =
156                        self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
157                    hir::ExprKind::Cast(expr, ty)
158                }
159                ExprKind::Type(expr, ty) => {
160                    let expr = self.lower_expr(expr);
161                    let ty =
162                        self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
163                    hir::ExprKind::Type(expr, ty)
164                }
165                ExprKind::AddrOf(k, m, ohs) => {
166                    let ohs = self.lower_expr(ohs);
167                    hir::ExprKind::AddrOf(*k, *m, ohs)
168                }
169                ExprKind::Let(pat, scrutinee, span, recovered) => {
170                    hir::ExprKind::Let(self.arena.alloc(hir::LetExpr {
171                        span: self.lower_span(*span),
172                        pat: self.lower_pat(pat),
173                        ty: None,
174                        init: self.lower_expr(scrutinee),
175                        recovered: *recovered,
176                    }))
177                }
178                ExprKind::If(cond, then, else_opt) => {
179                    self.lower_expr_if(cond, then, else_opt.as_deref())
180                }
181                ExprKind::While(cond, body, opt_label) => {
182                    self.with_loop_scope(expr_hir_id, |this| {
183                        let span =
184                            this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None);
185                        let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id);
186                        this.lower_expr_while_in_loop_scope(span, cond, body, opt_label)
187                    })
188                }
189                ExprKind::Loop(body, opt_label, span) => {
190                    self.with_loop_scope(expr_hir_id, |this| {
191                        let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id);
192                        hir::ExprKind::Loop(
193                            this.lower_block(body, false),
194                            opt_label,
195                            hir::LoopSource::Loop,
196                            this.lower_span(*span),
197                        )
198                    })
199                }
200                ExprKind::TryBlock(body) => self.lower_expr_try_block(body),
201                ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match(
202                    self.lower_expr(expr),
203                    self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
204                    match kind {
205                        MatchKind::Prefix => hir::MatchSource::Normal,
206                        MatchKind::Postfix => hir::MatchSource::Postfix,
207                    },
208                ),
209                ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
210                ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr),
211                ExprKind::Closure(box Closure {
212                    binder,
213                    capture_clause,
214                    constness,
215                    coroutine_kind,
216                    movability,
217                    fn_decl,
218                    body,
219                    fn_decl_span,
220                    fn_arg_span,
221                }) => match coroutine_kind {
222                    Some(coroutine_kind) => self.lower_expr_coroutine_closure(
223                        binder,
224                        *capture_clause,
225                        e.id,
226                        expr_hir_id,
227                        *coroutine_kind,
228                        fn_decl,
229                        body,
230                        *fn_decl_span,
231                        *fn_arg_span,
232                    ),
233                    None => self.lower_expr_closure(
234                        binder,
235                        *capture_clause,
236                        e.id,
237                        expr_hir_id,
238                        *constness,
239                        *movability,
240                        fn_decl,
241                        body,
242                        *fn_decl_span,
243                        *fn_arg_span,
244                    ),
245                },
246                ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => {
247                    let desugaring_kind = match genblock_kind {
248                        GenBlockKind::Async => hir::CoroutineDesugaring::Async,
249                        GenBlockKind::Gen => hir::CoroutineDesugaring::Gen,
250                        GenBlockKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen,
251                    };
252                    self.make_desugared_coroutine_expr(
253                        *capture_clause,
254                        e.id,
255                        None,
256                        *decl_span,
257                        e.span,
258                        desugaring_kind,
259                        hir::CoroutineSource::Block,
260                        |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
261                    )
262                }
263                ExprKind::Block(blk, opt_label) => {
264                    // Different from loops, label of block resolves to block id rather than
265                    // expr node id.
266                    let block_hir_id = self.lower_node_id(blk.id);
267                    let opt_label = self.lower_label(*opt_label, blk.id, block_hir_id);
268                    let hir_block = self.arena.alloc(self.lower_block_noalloc(
269                        block_hir_id,
270                        blk,
271                        opt_label.is_some(),
272                    ));
273                    hir::ExprKind::Block(hir_block, opt_label)
274                }
275                ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span),
276                ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp(
277                    self.lower_binop(*op),
278                    self.lower_expr(el),
279                    self.lower_expr(er),
280                ),
281                ExprKind::Field(el, ident) => {
282                    hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident))
283                }
284                ExprKind::Index(el, er, brackets_span) => {
285                    hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er), *brackets_span)
286                }
287                ExprKind::Range(e1, e2, lims) => {
288                    self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims)
289                }
290                ExprKind::Underscore => {
291                    let guar = self.dcx().emit_err(UnderscoreExprLhsAssign { span: e.span });
292                    hir::ExprKind::Err(guar)
293                }
294                ExprKind::Path(qself, path) => {
295                    let qpath = self.lower_qpath(
296                        e.id,
297                        qself,
298                        path,
299                        ParamMode::Optional,
300                        AllowReturnTypeNotation::No,
301                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
302                        None,
303                    );
304                    hir::ExprKind::Path(qpath)
305                }
306                ExprKind::Break(opt_label, opt_expr) => {
307                    let opt_expr = opt_expr.as_ref().map(|x| self.lower_expr(x));
308                    hir::ExprKind::Break(self.lower_jump_destination(e.id, *opt_label), opt_expr)
309                }
310                ExprKind::Continue(opt_label) => {
311                    hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label))
312                }
313                ExprKind::Ret(e) => {
314                    let expr = e.as_ref().map(|x| self.lower_expr(x));
315                    self.checked_return(expr)
316                }
317                ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
318                ExprKind::Become(sub_expr) => {
319                    let sub_expr = self.lower_expr(sub_expr);
320                    hir::ExprKind::Become(sub_expr)
321                }
322                ExprKind::InlineAsm(asm) => {
323                    hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
324                }
325                ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),
326                ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(
327                    self.lower_ty(
328                        container,
329                        ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
330                    ),
331                    self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))),
332                ),
333                ExprKind::Struct(se) => {
334                    let rest = match &se.rest {
335                        StructRest::Base(e) => hir::StructTailExpr::Base(self.lower_expr(e)),
336                        StructRest::Rest(sp) => hir::StructTailExpr::DefaultFields(*sp),
337                        StructRest::None => hir::StructTailExpr::None,
338                    };
339                    hir::ExprKind::Struct(
340                        self.arena.alloc(self.lower_qpath(
341                            e.id,
342                            &se.qself,
343                            &se.path,
344                            ParamMode::Optional,
345                            AllowReturnTypeNotation::No,
346                            ImplTraitContext::Disallowed(ImplTraitPosition::Path),
347                            None,
348                        )),
349                        self.arena
350                            .alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
351                        rest,
352                    )
353                }
354                ExprKind::Yield(kind) => self.lower_expr_yield(e.span, kind.expr().map(|x| &**x)),
355                ExprKind::Err(guar) => hir::ExprKind::Err(*guar),
356
357                ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(
358                    *kind,
359                    self.lower_expr(expr),
360                    ty.as_ref().map(|ty| {
361                        self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
362                    }),
363                ),
364
365                ExprKind::Dummy => {
366                    span_bug!(e.span, "lowered ExprKind::Dummy")
367                }
368
369                ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
370
371                ExprKind::Paren(_) | ExprKind::ForLoop { .. } => {
372                    unreachable!("already handled")
373                }
374
375                ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
376            };
377
378            hir::Expr { hir_id: expr_hir_id, kind, span: self.lower_span(e.span) }
379        })
380    }
381
382    /// Create an `ExprKind::Ret` that is optionally wrapped by a call to check
383    /// a contract ensures clause, if it exists.
384    fn checked_return(&mut self, opt_expr: Option<&'hir hir::Expr<'hir>>) -> hir::ExprKind<'hir> {
385        let checked_ret =
386            if let Some((check_span, check_ident, check_hir_id)) = self.contract_ensures {
387                let expr = opt_expr.unwrap_or_else(|| self.expr_unit(check_span));
388                Some(self.inject_ensures_check(expr, check_span, check_ident, check_hir_id))
389            } else {
390                opt_expr
391            };
392        hir::ExprKind::Ret(checked_ret)
393    }
394
395    /// Wraps an expression with a call to the ensures check before it gets returned.
396    pub(crate) fn inject_ensures_check(
397        &mut self,
398        expr: &'hir hir::Expr<'hir>,
399        span: Span,
400        check_ident: Ident,
401        check_hir_id: HirId,
402    ) -> &'hir hir::Expr<'hir> {
403        let checker_fn = self.expr_ident(span, check_ident, check_hir_id);
404        let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None);
405        self.expr_call(span, checker_fn, std::slice::from_ref(expr))
406    }
407
408    pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
409        self.with_new_scopes(c.value.span, |this| {
410            let def_id = this.local_def_id(c.id);
411            hir::ConstBlock {
412                def_id,
413                hir_id: this.lower_node_id(c.id),
414                body: this.lower_const_body(c.value.span, Some(&c.value)),
415            }
416        })
417    }
418
419    pub(crate) fn lower_lit(
420        &mut self,
421        token_lit: &token::Lit,
422        span: Span,
423    ) -> &'hir Spanned<LitKind> {
424        let lit_kind = match LitKind::from_token_lit(*token_lit) {
425            Ok(lit_kind) => lit_kind,
426            Err(err) => {
427                let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span);
428                LitKind::Err(guar)
429            }
430        };
431        self.arena.alloc(respan(self.lower_span(span), lit_kind))
432    }
433
434    fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
435        match u {
436            UnOp::Deref => hir::UnOp::Deref,
437            UnOp::Not => hir::UnOp::Not,
438            UnOp::Neg => hir::UnOp::Neg,
439        }
440    }
441
442    fn lower_binop(&mut self, b: BinOp) -> BinOp {
443        Spanned { node: b.node, span: self.lower_span(b.span) }
444    }
445
446    fn lower_legacy_const_generics(
447        &mut self,
448        mut f: Expr,
449        args: ThinVec<AstP<Expr>>,
450        legacy_args_idx: &[usize],
451    ) -> hir::ExprKind<'hir> {
452        let ExprKind::Path(None, path) = &mut f.kind else {
453            unreachable!();
454        };
455
456        let mut error = None;
457        let mut invalid_expr_error = |tcx: TyCtxt<'_>, span| {
458            // Avoid emitting the error multiple times.
459            if error.is_none() {
460                let mut const_args = vec![];
461                let mut other_args = vec![];
462                for (idx, arg) in args.iter().enumerate() {
463                    if legacy_args_idx.contains(&idx) {
464                        const_args.push(format!("{{ {} }}", expr_to_string(arg)));
465                    } else {
466                        other_args.push(expr_to_string(arg));
467                    }
468                }
469                let suggestion = UseConstGenericArg {
470                    end_of_fn: f.span.shrink_to_hi(),
471                    const_args: const_args.join(", "),
472                    other_args: other_args.join(", "),
473                    call_args: args[0].span.to(args.last().unwrap().span),
474                };
475                error = Some(tcx.dcx().emit_err(InvalidLegacyConstGenericArg { span, suggestion }));
476            }
477            error.unwrap()
478        };
479
480        // Split the arguments into const generics and normal arguments
481        let mut real_args = vec![];
482        let mut generic_args = ThinVec::new();
483        for (idx, arg) in args.iter().cloned().enumerate() {
484            if legacy_args_idx.contains(&idx) {
485                let parent_def_id = self.current_hir_id_owner.def_id;
486                let node_id = self.next_node_id();
487                self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, f.span);
488                let mut visitor = WillCreateDefIdsVisitor {};
489                let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
490                    AstP(Expr {
491                        id: self.next_node_id(),
492                        kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),
493                        span: f.span,
494                        attrs: [].into(),
495                        tokens: None,
496                    })
497                } else {
498                    arg
499                };
500
501                let anon_const = AnonConst { id: node_id, value: const_value };
502                generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
503            } else {
504                real_args.push(arg);
505            }
506        }
507
508        // Add generic args to the last element of the path.
509        let last_segment = path.segments.last_mut().unwrap();
510        assert!(last_segment.args.is_none());
511        last_segment.args = Some(AstP(GenericArgs::AngleBracketed(AngleBracketedArgs {
512            span: DUMMY_SP,
513            args: generic_args,
514        })));
515
516        // Now lower everything as normal.
517        let f = self.lower_expr(&f);
518        hir::ExprKind::Call(f, self.lower_exprs(&real_args))
519    }
520
521    fn lower_expr_if(
522        &mut self,
523        cond: &Expr,
524        then: &Block,
525        else_opt: Option<&Expr>,
526    ) -> hir::ExprKind<'hir> {
527        let lowered_cond = self.lower_cond(cond);
528        let then_expr = self.lower_block_expr(then);
529        if let Some(rslt) = else_opt {
530            hir::ExprKind::If(
531                lowered_cond,
532                self.arena.alloc(then_expr),
533                Some(self.lower_expr(rslt)),
534            )
535        } else {
536            hir::ExprKind::If(lowered_cond, self.arena.alloc(then_expr), None)
537        }
538    }
539
540    // Lowers a condition (i.e. `cond` in `if cond` or `while cond`), wrapping it in a terminating scope
541    // so that temporaries created in the condition don't live beyond it.
542    fn lower_cond(&mut self, cond: &Expr) -> &'hir hir::Expr<'hir> {
543        fn has_let_expr(expr: &Expr) -> bool {
544            match &expr.kind {
545                ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
546                ExprKind::Let(..) => true,
547                _ => false,
548            }
549        }
550
551        // We have to take special care for `let` exprs in the condition, e.g. in
552        // `if let pat = val` or `if foo && let pat = val`, as we _do_ want `val` to live beyond the
553        // condition in this case.
554        //
555        // In order to maintain the drop behavior for the non `let` parts of the condition,
556        // we still wrap them in terminating scopes, e.g. `if foo && let pat = val` essentially
557        // gets transformed into `if { let _t = foo; _t } && let pat = val`
558        match &cond.kind {
559            ExprKind::Binary(op @ Spanned { node: ast::BinOpKind::And, .. }, lhs, rhs)
560                if has_let_expr(cond) =>
561            {
562                let op = self.lower_binop(*op);
563                let lhs = self.lower_cond(lhs);
564                let rhs = self.lower_cond(rhs);
565
566                self.arena.alloc(self.expr(cond.span, hir::ExprKind::Binary(op, lhs, rhs)))
567            }
568            ExprKind::Let(..) => self.lower_expr(cond),
569            _ => {
570                let cond = self.lower_expr(cond);
571                let reason = DesugaringKind::CondTemporary;
572                let span_block = self.mark_span_with_reason(reason, cond.span, None);
573                self.expr_drop_temps(span_block, cond)
574            }
575        }
576    }
577
578    // We desugar: `'label: while $cond $body` into:
579    //
580    // ```
581    // 'label: loop {
582    //   if { let _t = $cond; _t } {
583    //     $body
584    //   }
585    //   else {
586    //     break;
587    //   }
588    // }
589    // ```
590    //
591    // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
592    // to preserve drop semantics since `while $cond { ... }` does not
593    // let temporaries live outside of `cond`.
594    fn lower_expr_while_in_loop_scope(
595        &mut self,
596        span: Span,
597        cond: &Expr,
598        body: &Block,
599        opt_label: Option<Label>,
600    ) -> hir::ExprKind<'hir> {
601        let lowered_cond = self.with_loop_condition_scope(|t| t.lower_cond(cond));
602        let then = self.lower_block_expr(body);
603        let expr_break = self.expr_break(span);
604        let stmt_break = self.stmt_expr(span, expr_break);
605        let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);
606        let else_expr = self.arena.alloc(self.expr_block(else_blk));
607        let if_kind = hir::ExprKind::If(lowered_cond, self.arena.alloc(then), Some(else_expr));
608        let if_expr = self.expr(span, if_kind);
609        let block = self.block_expr(self.arena.alloc(if_expr));
610        let span = self.lower_span(span.with_hi(cond.span.hi()));
611        hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span)
612    }
613
614    /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
615    /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }`
616    /// and save the block id to use it as a break target for desugaring of the `?` operator.
617    fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> {
618        let body_hir_id = self.lower_node_id(body.id);
619        self.with_catch_scope(body_hir_id, |this| {
620            let mut block = this.lower_block_noalloc(body_hir_id, body, true);
621
622            // Final expression of the block (if present) or `()` with span at the end of block
623            let (try_span, tail_expr) = if let Some(expr) = block.expr.take() {
624                (
625                    this.mark_span_with_reason(
626                        DesugaringKind::TryBlock,
627                        expr.span,
628                        Some(Arc::clone(&this.allow_try_trait)),
629                    ),
630                    expr,
631                )
632            } else {
633                let try_span = this.mark_span_with_reason(
634                    DesugaringKind::TryBlock,
635                    this.tcx.sess.source_map().end_point(body.span),
636                    Some(Arc::clone(&this.allow_try_trait)),
637                );
638
639                (try_span, this.expr_unit(try_span))
640            };
641
642            let ok_wrapped_span =
643                this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);
644
645            // `::std::ops::Try::from_output($tail_expr)`
646            block.expr = Some(this.wrap_in_try_constructor(
647                hir::LangItem::TryTraitFromOutput,
648                try_span,
649                tail_expr,
650                ok_wrapped_span,
651            ));
652
653            hir::ExprKind::Block(this.arena.alloc(block), None)
654        })
655    }
656
657    fn wrap_in_try_constructor(
658        &mut self,
659        lang_item: hir::LangItem,
660        method_span: Span,
661        expr: &'hir hir::Expr<'hir>,
662        overall_span: Span,
663    ) -> &'hir hir::Expr<'hir> {
664        let constructor = self.arena.alloc(self.expr_lang_item_path(method_span, lang_item));
665        self.expr_call(overall_span, constructor, std::slice::from_ref(expr))
666    }
667
668    fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
669        let pat = self.lower_pat(&arm.pat);
670        let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond));
671        let hir_id = self.next_id();
672        let span = self.lower_span(arm.span);
673        self.lower_attrs(hir_id, &arm.attrs, arm.span);
674        let is_never_pattern = pat.is_never_pattern();
675        // We need to lower the body even if it's unneeded for never pattern in match,
676        // ensure that we can get HirId for DefId if need (issue #137708).
677        let body = arm.body.as_ref().map(|x| self.lower_expr(x));
678        let body = if let Some(body) = body
679            && !is_never_pattern
680        {
681            body
682        } else {
683            // Either `body.is_none()` or `is_never_pattern` here.
684            if !is_never_pattern {
685                if self.tcx.features().never_patterns() {
686                    // If the feature is off we already emitted the error after parsing.
687                    let suggestion = span.shrink_to_hi();
688                    self.dcx().emit_err(MatchArmWithNoBody { span, suggestion });
689                }
690            } else if let Some(body) = &arm.body {
691                self.dcx().emit_err(NeverPatternWithBody { span: body.span });
692            } else if let Some(g) = &arm.guard {
693                self.dcx().emit_err(NeverPatternWithGuard { span: g.span });
694            }
695
696            // We add a fake `loop {}` arm body so that it typecks to `!`. The mir lowering of never
697            // patterns ensures this loop is not reachable.
698            let block = self.arena.alloc(hir::Block {
699                stmts: &[],
700                expr: None,
701                hir_id: self.next_id(),
702                rules: hir::BlockCheckMode::DefaultBlock,
703                span,
704                targeted_by_break: false,
705            });
706            self.arena.alloc(hir::Expr {
707                hir_id: self.next_id(),
708                kind: hir::ExprKind::Loop(block, None, hir::LoopSource::Loop, span),
709                span,
710            })
711        };
712        hir::Arm { hir_id, pat, guard, body, span }
713    }
714
715    /// Lower/desugar a coroutine construct.
716    ///
717    /// In particular, this creates the correct async resume argument and `_task_context`.
718    ///
719    /// This results in:
720    ///
721    /// ```text
722    /// static move? |<_task_context?>| -> <return_ty> {
723    ///     <body>
724    /// }
725    /// ```
726    pub(super) fn make_desugared_coroutine_expr(
727        &mut self,
728        capture_clause: CaptureBy,
729        closure_node_id: NodeId,
730        return_ty: Option<hir::FnRetTy<'hir>>,
731        fn_decl_span: Span,
732        span: Span,
733        desugaring_kind: hir::CoroutineDesugaring,
734        coroutine_source: hir::CoroutineSource,
735        body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
736    ) -> hir::ExprKind<'hir> {
737        let closure_def_id = self.local_def_id(closure_node_id);
738        let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source);
739
740        // The `async` desugaring takes a resume argument and maintains a `task_context`,
741        // whereas a generator does not.
742        let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind {
743            hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => {
744                // Resume argument type: `ResumeTy`
745                let unstable_span = self.mark_span_with_reason(
746                    DesugaringKind::Async,
747                    self.lower_span(span),
748                    Some(Arc::clone(&self.allow_gen_future)),
749                );
750                let resume_ty =
751                    self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None);
752                let input_ty = hir::Ty {
753                    hir_id: self.next_id(),
754                    kind: hir::TyKind::Path(resume_ty),
755                    span: unstable_span,
756                };
757                let inputs = arena_vec![self; input_ty];
758
759                // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
760                let (pat, task_context_hid) = self.pat_ident_binding_mode(
761                    span,
762                    Ident::with_dummy_span(sym::_task_context),
763                    hir::BindingMode::MUT,
764                );
765                let param = hir::Param {
766                    hir_id: self.next_id(),
767                    pat,
768                    ty_span: self.lower_span(span),
769                    span: self.lower_span(span),
770                };
771                let params = arena_vec![self; param];
772
773                (inputs, params, Some(task_context_hid))
774            }
775            hir::CoroutineDesugaring::Gen => (&[], &[], None),
776        };
777
778        let output =
779            return_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
780
781        let fn_decl = self.arena.alloc(hir::FnDecl {
782            inputs,
783            output,
784            c_variadic: false,
785            implicit_self: hir::ImplicitSelfKind::None,
786            lifetime_elision_allowed: false,
787        });
788
789        let body = self.lower_body(move |this| {
790            this.coroutine_kind = Some(coroutine_kind);
791
792            let old_ctx = this.task_context;
793            if task_context.is_some() {
794                this.task_context = task_context;
795            }
796            let res = body(this);
797            this.task_context = old_ctx;
798
799            (params, res)
800        });
801
802        // `static |<_task_context?>| -> <return_ty> { <body> }`:
803        hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
804            def_id: closure_def_id,
805            binder: hir::ClosureBinder::Default,
806            capture_clause,
807            bound_generic_params: &[],
808            fn_decl,
809            body,
810            fn_decl_span: self.lower_span(fn_decl_span),
811            fn_arg_span: None,
812            kind: hir::ClosureKind::Coroutine(coroutine_kind),
813            constness: hir::Constness::NotConst,
814        }))
815    }
816
817    /// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
818    /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.
819    pub(super) fn maybe_forward_track_caller(
820        &mut self,
821        span: Span,
822        outer_hir_id: HirId,
823        inner_hir_id: HirId,
824    ) {
825        if self.tcx.features().async_fn_track_caller()
826            && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
827            && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
828        {
829            let unstable_span = self.mark_span_with_reason(
830                DesugaringKind::Async,
831                span,
832                Some(Arc::clone(&self.allow_gen_future)),
833            );
834            self.lower_attrs(
835                inner_hir_id,
836                &[Attribute {
837                    kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(
838                        sym::track_caller,
839                        span,
840                    )))),
841                    id: self.tcx.sess.psess.attr_id_generator.mk_attr_id(),
842                    style: AttrStyle::Outer,
843                    span: unstable_span,
844                }],
845                span,
846            );
847        }
848    }
849
850    /// Desugar `<expr>.await` into:
851    /// ```ignore (pseudo-rust)
852    /// match ::std::future::IntoFuture::into_future(<expr>) {
853    ///     mut __awaitee => loop {
854    ///         match unsafe { ::std::future::Future::poll(
855    ///             <::std::pin::Pin>::new_unchecked(&mut __awaitee),
856    ///             ::std::future::get_context(task_context),
857    ///         ) } {
858    ///             ::std::task::Poll::Ready(result) => break result,
859    ///             ::std::task::Poll::Pending => {}
860    ///         }
861    ///         task_context = yield ();
862    ///     }
863    /// }
864    /// ```
865    fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
866        let expr = self.arena.alloc(self.lower_expr_mut(expr));
867        self.make_lowered_await(await_kw_span, expr, FutureKind::Future)
868    }
869
870    /// Takes an expr that has already been lowered and generates a desugared await loop around it
871    fn make_lowered_await(
872        &mut self,
873        await_kw_span: Span,
874        expr: &'hir hir::Expr<'hir>,
875        await_kind: FutureKind,
876    ) -> hir::ExprKind<'hir> {
877        let full_span = expr.span.to(await_kw_span);
878
879        let is_async_gen = match self.coroutine_kind {
880            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false,
881            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
882            Some(hir::CoroutineKind::Coroutine(_))
883            | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _))
884            | None => {
885                // Lower to a block `{ EXPR; <error> }` so that the awaited expr
886                // is not accidentally orphaned.
887                let stmt_id = self.next_id();
888                let expr_err = self.expr(
889                    expr.span,
890                    hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {
891                        await_kw_span,
892                        item_span: self.current_item,
893                    })),
894                );
895                return hir::ExprKind::Block(
896                    self.block_all(
897                        expr.span,
898                        arena_vec![self; hir::Stmt {
899                            hir_id: stmt_id,
900                            kind: hir::StmtKind::Semi(expr),
901                            span: expr.span,
902                        }],
903                        Some(self.arena.alloc(expr_err)),
904                    ),
905                    None,
906                );
907            }
908        };
909
910        let features = match await_kind {
911            FutureKind::Future => None,
912            FutureKind::AsyncIterator => Some(Arc::clone(&self.allow_for_await)),
913        };
914        let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features);
915        let gen_future_span = self.mark_span_with_reason(
916            DesugaringKind::Await,
917            full_span,
918            Some(Arc::clone(&self.allow_gen_future)),
919        );
920        let expr_hir_id = expr.hir_id;
921
922        // Note that the name of this binding must not be changed to something else because
923        // debuggers and debugger extensions expect it to be called `__awaitee`. They use
924        // this name to identify what is being awaited by a suspended async functions.
925        let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);
926        let (awaitee_pat, awaitee_pat_hid) =
927            self.pat_ident_binding_mode(gen_future_span, awaitee_ident, hir::BindingMode::MUT);
928
929        let task_context_ident = Ident::with_dummy_span(sym::_task_context);
930
931        // unsafe {
932        //     ::std::future::Future::poll(
933        //         ::std::pin::Pin::new_unchecked(&mut __awaitee),
934        //         ::std::future::get_context(task_context),
935        //     )
936        // }
937        let poll_expr = {
938            let awaitee = self.expr_ident(span, awaitee_ident, awaitee_pat_hid);
939            let ref_mut_awaitee = self.expr_mut_addr_of(span, awaitee);
940
941            let Some(task_context_hid) = self.task_context else {
942                unreachable!("use of `await` outside of an async context.");
943            };
944
945            let task_context = self.expr_ident_mut(span, task_context_ident, task_context_hid);
946
947            let new_unchecked = self.expr_call_lang_item_fn_mut(
948                span,
949                hir::LangItem::PinNewUnchecked,
950                arena_vec![self; ref_mut_awaitee],
951            );
952            let get_context = self.expr_call_lang_item_fn_mut(
953                gen_future_span,
954                hir::LangItem::GetContext,
955                arena_vec![self; task_context],
956            );
957            let call = match await_kind {
958                FutureKind::Future => self.expr_call_lang_item_fn(
959                    span,
960                    hir::LangItem::FuturePoll,
961                    arena_vec![self; new_unchecked, get_context],
962                ),
963                FutureKind::AsyncIterator => self.expr_call_lang_item_fn(
964                    span,
965                    hir::LangItem::AsyncIteratorPollNext,
966                    arena_vec![self; new_unchecked, get_context],
967                ),
968            };
969            self.arena.alloc(self.expr_unsafe(call))
970        };
971
972        // `::std::task::Poll::Ready(result) => break result`
973        let loop_node_id = self.next_node_id();
974        let loop_hir_id = self.lower_node_id(loop_node_id);
975        let ready_arm = {
976            let x_ident = Ident::with_dummy_span(sym::result);
977            let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident);
978            let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);
979            let ready_field = self.single_pat_field(gen_future_span, x_pat);
980            let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);
981            let break_x = self.with_loop_scope(loop_hir_id, move |this| {
982                let expr_break =
983                    hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
984                this.arena.alloc(this.expr(gen_future_span, expr_break))
985            });
986            self.arm(ready_pat, break_x)
987        };
988
989        // `::std::task::Poll::Pending => {}`
990        let pending_arm = {
991            let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);
992            let empty_block = self.expr_block_empty(span);
993            self.arm(pending_pat, empty_block)
994        };
995
996        let inner_match_stmt = {
997            let match_expr = self.expr_match(
998                span,
999                poll_expr,
1000                arena_vec![self; ready_arm, pending_arm],
1001                hir::MatchSource::AwaitDesugar,
1002            );
1003            self.stmt_expr(span, match_expr)
1004        };
1005
1006        // Depending on `async` of `async gen`:
1007        // async     - task_context = yield ();
1008        // async gen - task_context = yield ASYNC_GEN_PENDING;
1009        let yield_stmt = {
1010            let yielded = if is_async_gen {
1011                self.arena.alloc(self.expr_lang_item_path(span, hir::LangItem::AsyncGenPending))
1012            } else {
1013                self.expr_unit(span)
1014            };
1015
1016            let yield_expr = self.expr(
1017                span,
1018                hir::ExprKind::Yield(yielded, hir::YieldSource::Await { expr: Some(expr_hir_id) }),
1019            );
1020            let yield_expr = self.arena.alloc(yield_expr);
1021
1022            let Some(task_context_hid) = self.task_context else {
1023                unreachable!("use of `await` outside of an async context.");
1024            };
1025
1026            let lhs = self.expr_ident(span, task_context_ident, task_context_hid);
1027            let assign =
1028                self.expr(span, hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span)));
1029            self.stmt_expr(span, assign)
1030        };
1031
1032        let loop_block = self.block_all(span, arena_vec![self; inner_match_stmt, yield_stmt], None);
1033
1034        // loop { .. }
1035        let loop_expr = self.arena.alloc(hir::Expr {
1036            hir_id: loop_hir_id,
1037            kind: hir::ExprKind::Loop(
1038                loop_block,
1039                None,
1040                hir::LoopSource::Loop,
1041                self.lower_span(span),
1042            ),
1043            span: self.lower_span(span),
1044        });
1045
1046        // mut __awaitee => loop { ... }
1047        let awaitee_arm = self.arm(awaitee_pat, loop_expr);
1048
1049        // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
1050        let into_future_expr = match await_kind {
1051            FutureKind::Future => self.expr_call_lang_item_fn(
1052                span,
1053                hir::LangItem::IntoFutureIntoFuture,
1054                arena_vec![self; *expr],
1055            ),
1056            // Not needed for `for await` because we expect to have already called
1057            // `IntoAsyncIterator::into_async_iter` on it.
1058            FutureKind::AsyncIterator => expr,
1059        };
1060
1061        // match <into_future_expr> {
1062        //     mut __awaitee => loop { .. }
1063        // }
1064        hir::ExprKind::Match(
1065            into_future_expr,
1066            arena_vec![self; awaitee_arm],
1067            hir::MatchSource::AwaitDesugar,
1068        )
1069    }
1070
1071    fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
1072        hir::ExprKind::Use(self.lower_expr(expr), use_kw_span)
1073    }
1074
1075    fn lower_expr_closure(
1076        &mut self,
1077        binder: &ClosureBinder,
1078        capture_clause: CaptureBy,
1079        closure_id: NodeId,
1080        closure_hir_id: hir::HirId,
1081        constness: Const,
1082        movability: Movability,
1083        decl: &FnDecl,
1084        body: &Expr,
1085        fn_decl_span: Span,
1086        fn_arg_span: Span,
1087    ) -> hir::ExprKind<'hir> {
1088        let closure_def_id = self.local_def_id(closure_id);
1089        let (binder_clause, generic_params) = self.lower_closure_binder(binder);
1090
1091        let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
1092            let mut coroutine_kind = if this
1093                .attrs
1094                .get(&closure_hir_id.local_id)
1095                .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine)))
1096            {
1097                Some(hir::CoroutineKind::Coroutine(Movability::Movable))
1098            } else {
1099                None
1100            };
1101            // FIXME(contracts): Support contracts on closures?
1102            let body_id = this.lower_fn_body(decl, None, |this| {
1103                this.coroutine_kind = coroutine_kind;
1104                let e = this.lower_expr_mut(body);
1105                coroutine_kind = this.coroutine_kind;
1106                e
1107            });
1108            let coroutine_option =
1109                this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
1110            (body_id, coroutine_option)
1111        });
1112
1113        let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
1114        // Lower outside new scope to preserve `is_in_loop_condition`.
1115        let fn_decl = self.lower_fn_decl(decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
1116
1117        let c = self.arena.alloc(hir::Closure {
1118            def_id: closure_def_id,
1119            binder: binder_clause,
1120            capture_clause,
1121            bound_generic_params,
1122            fn_decl,
1123            body: body_id,
1124            fn_decl_span: self.lower_span(fn_decl_span),
1125            fn_arg_span: Some(self.lower_span(fn_arg_span)),
1126            kind: closure_kind,
1127            constness: self.lower_constness(constness),
1128        });
1129
1130        hir::ExprKind::Closure(c)
1131    }
1132
1133    fn closure_movability_for_fn(
1134        &mut self,
1135        decl: &FnDecl,
1136        fn_decl_span: Span,
1137        coroutine_kind: Option<hir::CoroutineKind>,
1138        movability: Movability,
1139    ) -> hir::ClosureKind {
1140        match coroutine_kind {
1141            Some(hir::CoroutineKind::Coroutine(_)) => {
1142                if decl.inputs.len() > 1 {
1143                    self.dcx().emit_err(CoroutineTooManyParameters { fn_decl_span });
1144                }
1145                hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(movability))
1146            }
1147            Some(
1148                hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
1149                | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)
1150                | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _),
1151            ) => {
1152                panic!("non-`async`/`gen` closure body turned `async`/`gen` during lowering");
1153            }
1154            None => {
1155                if movability == Movability::Static {
1156                    self.dcx().emit_err(ClosureCannotBeStatic { fn_decl_span });
1157                }
1158                hir::ClosureKind::Closure
1159            }
1160        }
1161    }
1162
1163    fn lower_closure_binder<'c>(
1164        &mut self,
1165        binder: &'c ClosureBinder,
1166    ) -> (hir::ClosureBinder, &'c [GenericParam]) {
1167        let (binder, params) = match binder {
1168            ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]),
1169            ClosureBinder::For { span, generic_params } => {
1170                let span = self.lower_span(*span);
1171                (hir::ClosureBinder::For { span }, &**generic_params)
1172            }
1173        };
1174
1175        (binder, params)
1176    }
1177
1178    fn lower_expr_coroutine_closure(
1179        &mut self,
1180        binder: &ClosureBinder,
1181        capture_clause: CaptureBy,
1182        closure_id: NodeId,
1183        closure_hir_id: HirId,
1184        coroutine_kind: CoroutineKind,
1185        decl: &FnDecl,
1186        body: &Expr,
1187        fn_decl_span: Span,
1188        fn_arg_span: Span,
1189    ) -> hir::ExprKind<'hir> {
1190        let closure_def_id = self.local_def_id(closure_id);
1191        let (binder_clause, generic_params) = self.lower_closure_binder(binder);
1192
1193        assert_matches!(
1194            coroutine_kind,
1195            CoroutineKind::Async { .. },
1196            "only async closures are supported currently"
1197        );
1198
1199        let body = self.with_new_scopes(fn_decl_span, |this| {
1200            let inner_decl =
1201                FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
1202
1203            // Transform `async |x: u8| -> X { ... }` into
1204            // `|x: u8| || -> X { ... }`.
1205            let body_id = this.lower_body(|this| {
1206                let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
1207                    &inner_decl,
1208                    |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
1209                    fn_decl_span,
1210                    body.span,
1211                    coroutine_kind,
1212                    hir::CoroutineSource::Closure,
1213                );
1214
1215                this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id);
1216
1217                (parameters, expr)
1218            });
1219            body_id
1220        });
1221
1222        let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
1223        // We need to lower the declaration outside the new scope, because we
1224        // have to conserve the state of being inside a loop condition for the
1225        // closure argument types.
1226        let fn_decl =
1227            self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
1228
1229        let c = self.arena.alloc(hir::Closure {
1230            def_id: closure_def_id,
1231            binder: binder_clause,
1232            capture_clause,
1233            bound_generic_params,
1234            fn_decl,
1235            body,
1236            fn_decl_span: self.lower_span(fn_decl_span),
1237            fn_arg_span: Some(self.lower_span(fn_arg_span)),
1238            // Lower this as a `CoroutineClosure`. That will ensure that HIR typeck
1239            // knows that a `FnDecl` output type like `-> &str` actually means
1240            // "coroutine that returns &str", rather than directly returning a `&str`.
1241            kind: hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async),
1242            constness: hir::Constness::NotConst,
1243        });
1244        hir::ExprKind::Closure(c)
1245    }
1246
1247    /// Destructure the LHS of complex assignments.
1248    /// For instance, lower `(a, b) = t` to `{ let (lhs1, lhs2) = t; a = lhs1; b = lhs2; }`.
1249    fn lower_expr_assign(
1250        &mut self,
1251        lhs: &Expr,
1252        rhs: &Expr,
1253        eq_sign_span: Span,
1254        whole_span: Span,
1255    ) -> hir::ExprKind<'hir> {
1256        // Return early in case of an ordinary assignment.
1257        fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
1258            match &lhs.kind {
1259                ExprKind::Array(..)
1260                | ExprKind::Struct(..)
1261                | ExprKind::Tup(..)
1262                | ExprKind::Underscore => false,
1263                // Check for unit struct constructor.
1264                ExprKind::Path(..) => lower_ctx.extract_unit_struct_path(lhs).is_none(),
1265                // Check for tuple struct constructor.
1266                ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(),
1267                ExprKind::Paren(e) => {
1268                    match e.kind {
1269                        // We special-case `(..)` for consistency with patterns.
1270                        ExprKind::Range(None, None, RangeLimits::HalfOpen) => false,
1271                        _ => is_ordinary(lower_ctx, e),
1272                    }
1273                }
1274                _ => true,
1275            }
1276        }
1277        if is_ordinary(self, lhs) {
1278            return hir::ExprKind::Assign(
1279                self.lower_expr(lhs),
1280                self.lower_expr(rhs),
1281                self.lower_span(eq_sign_span),
1282            );
1283        }
1284
1285        let mut assignments = vec![];
1286
1287        // The LHS becomes a pattern: `(lhs1, lhs2)`.
1288        let pat = self.destructure_assign(lhs, eq_sign_span, &mut assignments);
1289        let rhs = self.lower_expr(rhs);
1290
1291        // Introduce a `let` for destructuring: `let (lhs1, lhs2) = t`.
1292        let destructure_let = self.stmt_let_pat(
1293            None,
1294            whole_span,
1295            Some(rhs),
1296            pat,
1297            hir::LocalSource::AssignDesugar(self.lower_span(eq_sign_span)),
1298        );
1299
1300        // `a = lhs1; b = lhs2;`.
1301        let stmts = self.arena.alloc_from_iter(std::iter::once(destructure_let).chain(assignments));
1302
1303        // Wrap everything in a block.
1304        hir::ExprKind::Block(self.block_all(whole_span, stmts, None), None)
1305    }
1306
1307    /// If the given expression is a path to a tuple struct, returns that path.
1308    /// It is not a complete check, but just tries to reject most paths early
1309    /// if they are not tuple structs.
1310    /// Type checking will take care of the full validation later.
1311    fn extract_tuple_struct_path<'a>(
1312        &mut self,
1313        expr: &'a Expr,
1314    ) -> Option<(&'a Option<AstP<QSelf>>, &'a Path)> {
1315        if let ExprKind::Path(qself, path) = &expr.kind {
1316            // Does the path resolve to something disallowed in a tuple struct/variant pattern?
1317            if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
1318                if let Some(res) = partial_res.full_res()
1319                    && !res.expected_in_tuple_struct_pat()
1320                {
1321                    return None;
1322                }
1323            }
1324            return Some((qself, path));
1325        }
1326        None
1327    }
1328
1329    /// If the given expression is a path to a unit struct, returns that path.
1330    /// It is not a complete check, but just tries to reject most paths early
1331    /// if they are not unit structs.
1332    /// Type checking will take care of the full validation later.
1333    fn extract_unit_struct_path<'a>(
1334        &mut self,
1335        expr: &'a Expr,
1336    ) -> Option<(&'a Option<AstP<QSelf>>, &'a Path)> {
1337        if let ExprKind::Path(qself, path) = &expr.kind {
1338            // Does the path resolve to something disallowed in a unit struct/variant pattern?
1339            if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
1340                if let Some(res) = partial_res.full_res()
1341                    && !res.expected_in_unit_struct_pat()
1342                {
1343                    return None;
1344                }
1345            }
1346            return Some((qself, path));
1347        }
1348        None
1349    }
1350
1351    /// Convert the LHS of a destructuring assignment to a pattern.
1352    /// Each sub-assignment is recorded in `assignments`.
1353    fn destructure_assign(
1354        &mut self,
1355        lhs: &Expr,
1356        eq_sign_span: Span,
1357        assignments: &mut Vec<hir::Stmt<'hir>>,
1358    ) -> &'hir hir::Pat<'hir> {
1359        self.arena.alloc(self.destructure_assign_mut(lhs, eq_sign_span, assignments))
1360    }
1361
1362    fn destructure_assign_mut(
1363        &mut self,
1364        lhs: &Expr,
1365        eq_sign_span: Span,
1366        assignments: &mut Vec<hir::Stmt<'hir>>,
1367    ) -> hir::Pat<'hir> {
1368        match &lhs.kind {
1369            // Underscore pattern.
1370            ExprKind::Underscore => {
1371                return self.pat_without_dbm(lhs.span, hir::PatKind::Wild);
1372            }
1373            // Slice patterns.
1374            ExprKind::Array(elements) => {
1375                let (pats, rest) =
1376                    self.destructure_sequence(elements, "slice", eq_sign_span, assignments);
1377                let slice_pat = if let Some((i, span)) = rest {
1378                    let (before, after) = pats.split_at(i);
1379                    hir::PatKind::Slice(
1380                        before,
1381                        Some(self.arena.alloc(self.pat_without_dbm(span, hir::PatKind::Wild))),
1382                        after,
1383                    )
1384                } else {
1385                    hir::PatKind::Slice(pats, None, &[])
1386                };
1387                return self.pat_without_dbm(lhs.span, slice_pat);
1388            }
1389            // Tuple structs.
1390            ExprKind::Call(callee, args) => {
1391                if let Some((qself, path)) = self.extract_tuple_struct_path(callee) {
1392                    let (pats, rest) = self.destructure_sequence(
1393                        args,
1394                        "tuple struct or variant",
1395                        eq_sign_span,
1396                        assignments,
1397                    );
1398                    let qpath = self.lower_qpath(
1399                        callee.id,
1400                        qself,
1401                        path,
1402                        ParamMode::Optional,
1403                        AllowReturnTypeNotation::No,
1404                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
1405                        None,
1406                    );
1407                    // Destructure like a tuple struct.
1408                    let tuple_struct_pat = hir::PatKind::TupleStruct(
1409                        qpath,
1410                        pats,
1411                        hir::DotDotPos::new(rest.map(|r| r.0)),
1412                    );
1413                    return self.pat_without_dbm(lhs.span, tuple_struct_pat);
1414                }
1415            }
1416            // Unit structs and enum variants.
1417            ExprKind::Path(..) => {
1418                if let Some((qself, path)) = self.extract_unit_struct_path(lhs) {
1419                    let qpath = self.lower_qpath(
1420                        lhs.id,
1421                        qself,
1422                        path,
1423                        ParamMode::Optional,
1424                        AllowReturnTypeNotation::No,
1425                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
1426                        None,
1427                    );
1428                    // Destructure like a unit struct.
1429                    let unit_struct_pat = hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {
1430                        kind: hir::PatExprKind::Path(qpath),
1431                        hir_id: self.next_id(),
1432                        span: self.lower_span(lhs.span),
1433                    }));
1434                    return self.pat_without_dbm(lhs.span, unit_struct_pat);
1435                }
1436            }
1437            // Structs.
1438            ExprKind::Struct(se) => {
1439                let field_pats = self.arena.alloc_from_iter(se.fields.iter().map(|f| {
1440                    let pat = self.destructure_assign(&f.expr, eq_sign_span, assignments);
1441                    hir::PatField {
1442                        hir_id: self.next_id(),
1443                        ident: self.lower_ident(f.ident),
1444                        pat,
1445                        is_shorthand: f.is_shorthand,
1446                        span: self.lower_span(f.span),
1447                    }
1448                }));
1449                let qpath = self.lower_qpath(
1450                    lhs.id,
1451                    &se.qself,
1452                    &se.path,
1453                    ParamMode::Optional,
1454                    AllowReturnTypeNotation::No,
1455                    ImplTraitContext::Disallowed(ImplTraitPosition::Path),
1456                    None,
1457                );
1458                let fields_omitted = match &se.rest {
1459                    StructRest::Base(e) => {
1460                        self.dcx().emit_err(FunctionalRecordUpdateDestructuringAssignment {
1461                            span: e.span,
1462                        });
1463                        true
1464                    }
1465                    StructRest::Rest(_) => true,
1466                    StructRest::None => false,
1467                };
1468                let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted);
1469                return self.pat_without_dbm(lhs.span, struct_pat);
1470            }
1471            // Tuples.
1472            ExprKind::Tup(elements) => {
1473                let (pats, rest) =
1474                    self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);
1475                let tuple_pat = hir::PatKind::Tuple(pats, hir::DotDotPos::new(rest.map(|r| r.0)));
1476                return self.pat_without_dbm(lhs.span, tuple_pat);
1477            }
1478            ExprKind::Paren(e) => {
1479                // We special-case `(..)` for consistency with patterns.
1480                if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
1481                    let tuple_pat = hir::PatKind::Tuple(&[], hir::DotDotPos::new(Some(0)));
1482                    return self.pat_without_dbm(lhs.span, tuple_pat);
1483                } else {
1484                    return self.destructure_assign_mut(e, eq_sign_span, assignments);
1485                }
1486            }
1487            _ => {}
1488        }
1489        // Treat all other cases as normal lvalue.
1490        let ident = Ident::new(sym::lhs, self.lower_span(lhs.span));
1491        let (pat, binding) = self.pat_ident_mut(lhs.span, ident);
1492        let ident = self.expr_ident(lhs.span, ident, binding);
1493        let assign =
1494            hir::ExprKind::Assign(self.lower_expr(lhs), ident, self.lower_span(eq_sign_span));
1495        let expr = self.expr(lhs.span, assign);
1496        assignments.push(self.stmt_expr(lhs.span, expr));
1497        pat
1498    }
1499
1500    /// Destructure a sequence of expressions occurring on the LHS of an assignment.
1501    /// Such a sequence occurs in a tuple (struct)/slice.
1502    /// Return a sequence of corresponding patterns, and the index and the span of `..` if it
1503    /// exists.
1504    /// Each sub-assignment is recorded in `assignments`.
1505    fn destructure_sequence(
1506        &mut self,
1507        elements: &[AstP<Expr>],
1508        ctx: &str,
1509        eq_sign_span: Span,
1510        assignments: &mut Vec<hir::Stmt<'hir>>,
1511    ) -> (&'hir [hir::Pat<'hir>], Option<(usize, Span)>) {
1512        let mut rest = None;
1513        let elements =
1514            self.arena.alloc_from_iter(elements.iter().enumerate().filter_map(|(i, e)| {
1515                // Check for `..` pattern.
1516                if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
1517                    if let Some((_, prev_span)) = rest {
1518                        self.ban_extra_rest_pat(e.span, prev_span, ctx);
1519                    } else {
1520                        rest = Some((i, e.span));
1521                    }
1522                    None
1523                } else {
1524                    Some(self.destructure_assign_mut(e, eq_sign_span, assignments))
1525                }
1526            }));
1527        (elements, rest)
1528    }
1529
1530    /// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
1531    fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
1532        let e1 = self.lower_expr_mut(e1);
1533        let e2 = self.lower_expr_mut(e2);
1534        let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span));
1535        let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path)));
1536        hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
1537    }
1538
1539    fn lower_expr_range(
1540        &mut self,
1541        span: Span,
1542        e1: Option<&Expr>,
1543        e2: Option<&Expr>,
1544        lims: RangeLimits,
1545    ) -> hir::ExprKind<'hir> {
1546        use rustc_ast::RangeLimits::*;
1547
1548        let lang_item = match (e1, e2, lims) {
1549            (None, None, HalfOpen) => hir::LangItem::RangeFull,
1550            (Some(..), None, HalfOpen) => {
1551                if self.tcx.features().new_range() {
1552                    hir::LangItem::RangeFromCopy
1553                } else {
1554                    hir::LangItem::RangeFrom
1555                }
1556            }
1557            (None, Some(..), HalfOpen) => hir::LangItem::RangeTo,
1558            (Some(..), Some(..), HalfOpen) => {
1559                if self.tcx.features().new_range() {
1560                    hir::LangItem::RangeCopy
1561                } else {
1562                    hir::LangItem::Range
1563                }
1564            }
1565            (None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
1566            (Some(e1), Some(e2), Closed) => {
1567                if self.tcx.features().new_range() {
1568                    hir::LangItem::RangeInclusiveCopy
1569                } else {
1570                    return self.lower_expr_range_closed(span, e1, e2);
1571                }
1572            }
1573            (start, None, Closed) => {
1574                self.dcx().emit_err(InclusiveRangeWithNoEnd { span });
1575                match start {
1576                    Some(..) => {
1577                        if self.tcx.features().new_range() {
1578                            hir::LangItem::RangeFromCopy
1579                        } else {
1580                            hir::LangItem::RangeFrom
1581                        }
1582                    }
1583                    None => hir::LangItem::RangeFull,
1584                }
1585            }
1586        };
1587
1588        let fields = self.arena.alloc_from_iter(
1589            e1.iter().map(|e| (sym::start, e)).chain(e2.iter().map(|e| (sym::end, e))).map(
1590                |(s, e)| {
1591                    let expr = self.lower_expr(e);
1592                    let ident = Ident::new(s, self.lower_span(e.span));
1593                    self.expr_field(ident, expr, e.span)
1594                },
1595            ),
1596        );
1597
1598        hir::ExprKind::Struct(
1599            self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span))),
1600            fields,
1601            hir::StructTailExpr::None,
1602        )
1603    }
1604
1605    // Record labelled expr's HirId so that we can retrieve it in `lower_jump_destination` without
1606    // lowering node id again.
1607    fn lower_label(
1608        &mut self,
1609        opt_label: Option<Label>,
1610        dest_id: NodeId,
1611        dest_hir_id: hir::HirId,
1612    ) -> Option<Label> {
1613        let label = opt_label?;
1614        self.ident_and_label_to_local_id.insert(dest_id, dest_hir_id.local_id);
1615        Some(Label { ident: self.lower_ident(label.ident) })
1616    }
1617
1618    fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
1619        let target_id = match destination {
1620            Some((id, _)) => {
1621                if let Some(loop_id) = self.resolver.get_label_res(id) {
1622                    let local_id = self.ident_and_label_to_local_id[&loop_id];
1623                    let loop_hir_id = HirId { owner: self.current_hir_id_owner, local_id };
1624                    Ok(loop_hir_id)
1625                } else {
1626                    Err(hir::LoopIdError::UnresolvedLabel)
1627                }
1628            }
1629            None => {
1630                self.loop_scope.map(|id| Ok(id)).unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
1631            }
1632        };
1633        let label = destination
1634            .map(|(_, label)| label)
1635            .map(|label| Label { ident: self.lower_ident(label.ident) });
1636        hir::Destination { label, target_id }
1637    }
1638
1639    fn lower_jump_destination(&mut self, id: NodeId, opt_label: Option<Label>) -> hir::Destination {
1640        if self.is_in_loop_condition && opt_label.is_none() {
1641            hir::Destination {
1642                label: None,
1643                target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition),
1644            }
1645        } else {
1646            self.lower_loop_destination(opt_label.map(|label| (id, label)))
1647        }
1648    }
1649
1650    fn with_catch_scope<T>(&mut self, catch_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T {
1651        let old_scope = self.catch_scope.replace(catch_id);
1652        let result = f(self);
1653        self.catch_scope = old_scope;
1654        result
1655    }
1656
1657    fn with_loop_scope<T>(&mut self, loop_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T {
1658        // We're no longer in the base loop's condition; we're in another loop.
1659        let was_in_loop_condition = self.is_in_loop_condition;
1660        self.is_in_loop_condition = false;
1661
1662        let old_scope = self.loop_scope.replace(loop_id);
1663        let result = f(self);
1664        self.loop_scope = old_scope;
1665
1666        self.is_in_loop_condition = was_in_loop_condition;
1667
1668        result
1669    }
1670
1671    fn with_loop_condition_scope<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
1672        let was_in_loop_condition = self.is_in_loop_condition;
1673        self.is_in_loop_condition = true;
1674
1675        let result = f(self);
1676
1677        self.is_in_loop_condition = was_in_loop_condition;
1678
1679        result
1680    }
1681
1682    fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {
1683        let hir_id = self.lower_node_id(f.id);
1684        self.lower_attrs(hir_id, &f.attrs, f.span);
1685        hir::ExprField {
1686            hir_id,
1687            ident: self.lower_ident(f.ident),
1688            expr: self.lower_expr(&f.expr),
1689            span: self.lower_span(f.span),
1690            is_shorthand: f.is_shorthand,
1691        }
1692    }
1693
1694    fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
1695        let yielded =
1696            opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));
1697
1698        if !self.tcx.features().yield_expr()
1699            && !self.tcx.features().coroutines()
1700            && !self.tcx.features().gen_blocks()
1701        {
1702            rustc_session::parse::feature_err(
1703                &self.tcx.sess,
1704                sym::yield_expr,
1705                span,
1706                fluent_generated::ast_lowering_yield,
1707            )
1708            .emit();
1709        }
1710
1711        let is_async_gen = match self.coroutine_kind {
1712            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false,
1713            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
1714            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
1715                // Lower to a block `{ EXPR; <error> }` so that the awaited expr
1716                // is not accidentally orphaned.
1717                let stmt_id = self.next_id();
1718                let expr_err = self.expr(
1719                    yielded.span,
1720                    hir::ExprKind::Err(self.dcx().emit_err(AsyncCoroutinesNotSupported { span })),
1721                );
1722                return hir::ExprKind::Block(
1723                    self.block_all(
1724                        yielded.span,
1725                        arena_vec![self; hir::Stmt {
1726                            hir_id: stmt_id,
1727                            kind: hir::StmtKind::Semi(yielded),
1728                            span: yielded.span,
1729                        }],
1730                        Some(self.arena.alloc(expr_err)),
1731                    ),
1732                    None,
1733                );
1734            }
1735            Some(hir::CoroutineKind::Coroutine(_)) => false,
1736            None => {
1737                let suggestion = self.current_item.map(|s| s.shrink_to_lo());
1738                self.dcx().emit_err(YieldInClosure { span, suggestion });
1739                self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable));
1740
1741                false
1742            }
1743        };
1744
1745        if is_async_gen {
1746            // `yield $expr` is transformed into `task_context = yield async_gen_ready($expr)`.
1747            // This ensures that we store our resumed `ResumeContext` correctly, and also that
1748            // the apparent value of the `yield` expression is `()`.
1749            let wrapped_yielded = self.expr_call_lang_item_fn(
1750                span,
1751                hir::LangItem::AsyncGenReady,
1752                std::slice::from_ref(yielded),
1753            );
1754            let yield_expr = self.arena.alloc(
1755                self.expr(span, hir::ExprKind::Yield(wrapped_yielded, hir::YieldSource::Yield)),
1756            );
1757
1758            let Some(task_context_hid) = self.task_context else {
1759                unreachable!("use of `await` outside of an async context.");
1760            };
1761            let task_context_ident = Ident::with_dummy_span(sym::_task_context);
1762            let lhs = self.expr_ident(span, task_context_ident, task_context_hid);
1763
1764            hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span))
1765        } else {
1766            hir::ExprKind::Yield(yielded, hir::YieldSource::Yield)
1767        }
1768    }
1769
1770    /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
1771    /// ```ignore (pseudo-rust)
1772    /// {
1773    ///     let result = match IntoIterator::into_iter(<head>) {
1774    ///         mut iter => {
1775    ///             [opt_ident]: loop {
1776    ///                 match Iterator::next(&mut iter) {
1777    ///                     None => break,
1778    ///                     Some(<pat>) => <body>,
1779    ///                 };
1780    ///             }
1781    ///         }
1782    ///     };
1783    ///     result
1784    /// }
1785    /// ```
1786    fn lower_expr_for(
1787        &mut self,
1788        e: &Expr,
1789        pat: &Pat,
1790        head: &Expr,
1791        body: &Block,
1792        opt_label: Option<Label>,
1793        loop_kind: ForLoopKind,
1794    ) -> hir::Expr<'hir> {
1795        let head = self.lower_expr_mut(head);
1796        let pat = self.lower_pat(pat);
1797        let for_span =
1798            self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None);
1799        let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
1800        let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None);
1801
1802        let loop_hir_id = self.lower_node_id(e.id);
1803        let label = self.lower_label(opt_label, e.id, loop_hir_id);
1804
1805        // `None => break`
1806        let none_arm = {
1807            let break_expr =
1808                self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span));
1809            let pat = self.pat_none(for_span);
1810            self.arm(pat, break_expr)
1811        };
1812
1813        // Some(<pat>) => <body>,
1814        let some_arm = {
1815            let some_pat = self.pat_some(pat_span, pat);
1816            let body_block =
1817                self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false));
1818            let body_expr = self.arena.alloc(self.expr_block(body_block));
1819            self.arm(some_pat, body_expr)
1820        };
1821
1822        // `mut iter`
1823        let iter = Ident::with_dummy_span(sym::iter);
1824        let (iter_pat, iter_pat_nid) =
1825            self.pat_ident_binding_mode(head_span, iter, hir::BindingMode::MUT);
1826
1827        let match_expr = {
1828            let iter = self.expr_ident(head_span, iter, iter_pat_nid);
1829            let next_expr = match loop_kind {
1830                ForLoopKind::For => {
1831                    // `Iterator::next(&mut iter)`
1832                    let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
1833                    self.expr_call_lang_item_fn(
1834                        head_span,
1835                        hir::LangItem::IteratorNext,
1836                        arena_vec![self; ref_mut_iter],
1837                    )
1838                }
1839                ForLoopKind::ForAwait => {
1840                    // we'll generate `unsafe { Pin::new_unchecked(&mut iter) })` and then pass this
1841                    // to make_lowered_await with `FutureKind::AsyncIterator` which will generator
1842                    // calls to `poll_next`. In user code, this would probably be a call to
1843                    // `Pin::as_mut` but here it's easy enough to do `new_unchecked`.
1844
1845                    // `&mut iter`
1846                    let iter = self.expr_mut_addr_of(head_span, iter);
1847                    // `Pin::new_unchecked(...)`
1848                    let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(
1849                        head_span,
1850                        hir::LangItem::PinNewUnchecked,
1851                        arena_vec![self; iter],
1852                    ));
1853                    // `unsafe { ... }`
1854                    let iter = self.arena.alloc(self.expr_unsafe(iter));
1855                    let kind = self.make_lowered_await(head_span, iter, FutureKind::AsyncIterator);
1856                    self.arena.alloc(hir::Expr { hir_id: self.next_id(), kind, span: head_span })
1857                }
1858            };
1859            let arms = arena_vec![self; none_arm, some_arm];
1860
1861            // `match $next_expr { ... }`
1862            self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
1863        };
1864        let match_stmt = self.stmt_expr(for_span, match_expr);
1865
1866        let loop_block = self.block_all(for_span, arena_vec![self; match_stmt], None);
1867
1868        // `[opt_ident]: loop { ... }`
1869        let kind = hir::ExprKind::Loop(
1870            loop_block,
1871            label,
1872            hir::LoopSource::ForLoop,
1873            self.lower_span(for_span.with_hi(head.span.hi())),
1874        );
1875        let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span });
1876
1877        // `mut iter => { ... }`
1878        let iter_arm = self.arm(iter_pat, loop_expr);
1879
1880        let match_expr = match loop_kind {
1881            ForLoopKind::For => {
1882                // `::std::iter::IntoIterator::into_iter(<head>)`
1883                let into_iter_expr = self.expr_call_lang_item_fn(
1884                    head_span,
1885                    hir::LangItem::IntoIterIntoIter,
1886                    arena_vec![self; head],
1887                );
1888
1889                self.arena.alloc(self.expr_match(
1890                    for_span,
1891                    into_iter_expr,
1892                    arena_vec![self; iter_arm],
1893                    hir::MatchSource::ForLoopDesugar,
1894                ))
1895            }
1896            // `match into_async_iter(<head>) { ref mut iter => match unsafe { Pin::new_unchecked(iter) } { ... } }`
1897            ForLoopKind::ForAwait => {
1898                let iter_ident = iter;
1899                let (async_iter_pat, async_iter_pat_id) =
1900                    self.pat_ident_binding_mode(head_span, iter_ident, hir::BindingMode::REF_MUT);
1901                let iter = self.expr_ident_mut(head_span, iter_ident, async_iter_pat_id);
1902                // `Pin::new_unchecked(...)`
1903                let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(
1904                    head_span,
1905                    hir::LangItem::PinNewUnchecked,
1906                    arena_vec![self; iter],
1907                ));
1908                // `unsafe { ... }`
1909                let iter = self.arena.alloc(self.expr_unsafe(iter));
1910                let inner_match_expr = self.arena.alloc(self.expr_match(
1911                    for_span,
1912                    iter,
1913                    arena_vec![self; iter_arm],
1914                    hir::MatchSource::ForLoopDesugar,
1915                ));
1916
1917                // `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)`
1918                let iter = self.expr_call_lang_item_fn(
1919                    head_span,
1920                    hir::LangItem::IntoAsyncIterIntoIter,
1921                    arena_vec![self; head],
1922                );
1923                let iter_arm = self.arm(async_iter_pat, inner_match_expr);
1924                self.arena.alloc(self.expr_match(
1925                    for_span,
1926                    iter,
1927                    arena_vec![self; iter_arm],
1928                    hir::MatchSource::ForLoopDesugar,
1929                ))
1930            }
1931        };
1932
1933        // This is effectively `{ let _result = ...; _result }`.
1934        // The construct was introduced in #21984 and is necessary to make sure that
1935        // temporaries in the `head` expression are dropped and do not leak to the
1936        // surrounding scope of the `match` since the `match` is not a terminating scope.
1937        //
1938        // Also, add the attributes to the outer returned expr node.
1939        let expr = self.expr_drop_temps_mut(for_span, match_expr);
1940        self.lower_attrs(expr.hir_id, &e.attrs, e.span);
1941        expr
1942    }
1943
1944    /// Desugar `ExprKind::Try` from: `<expr>?` into:
1945    /// ```ignore (pseudo-rust)
1946    /// match Try::branch(<expr>) {
1947    ///     ControlFlow::Continue(val) => #[allow(unreachable_code)] val,,
1948    ///     ControlFlow::Break(residual) =>
1949    ///         #[allow(unreachable_code)]
1950    ///         // If there is an enclosing `try {...}`:
1951    ///         break 'catch_target Try::from_residual(residual),
1952    ///         // Otherwise:
1953    ///         return Try::from_residual(residual),
1954    /// }
1955    /// ```
1956    fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> {
1957        let unstable_span = self.mark_span_with_reason(
1958            DesugaringKind::QuestionMark,
1959            span,
1960            Some(Arc::clone(&self.allow_try_trait)),
1961        );
1962        let try_span = self.tcx.sess.source_map().end_point(span);
1963        let try_span = self.mark_span_with_reason(
1964            DesugaringKind::QuestionMark,
1965            try_span,
1966            Some(Arc::clone(&self.allow_try_trait)),
1967        );
1968
1969        // `Try::branch(<expr>)`
1970        let scrutinee = {
1971            // expand <expr>
1972            let sub_expr = self.lower_expr_mut(sub_expr);
1973
1974            self.expr_call_lang_item_fn(
1975                unstable_span,
1976                hir::LangItem::TryTraitBranch,
1977                arena_vec![self; sub_expr],
1978            )
1979        };
1980
1981        // `#[allow(unreachable_code)]`
1982        let attr = attr::mk_attr_nested_word(
1983            &self.tcx.sess.psess.attr_id_generator,
1984            AttrStyle::Outer,
1985            Safety::Default,
1986            sym::allow,
1987            sym::unreachable_code,
1988            try_span,
1989        );
1990        let attrs: AttrVec = thin_vec![attr];
1991
1992        // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
1993        let continue_arm = {
1994            let val_ident = Ident::with_dummy_span(sym::val);
1995            let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
1996            let val_expr = self.expr_ident(span, val_ident, val_pat_nid);
1997            self.lower_attrs(val_expr.hir_id, &attrs, span);
1998            let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
1999            self.arm(continue_pat, val_expr)
2000        };
2001
2002        // `ControlFlow::Break(residual) =>
2003        //     #[allow(unreachable_code)]
2004        //     return Try::from_residual(residual),`
2005        let break_arm = {
2006            let residual_ident = Ident::with_dummy_span(sym::residual);
2007            let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident);
2008            let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid);
2009            let from_residual_expr = self.wrap_in_try_constructor(
2010                hir::LangItem::TryTraitFromResidual,
2011                try_span,
2012                self.arena.alloc(residual_expr),
2013                unstable_span,
2014            );
2015            let ret_expr = if let Some(catch_id) = self.catch_scope {
2016                let target_id = Ok(catch_id);
2017                self.arena.alloc(self.expr(
2018                    try_span,
2019                    hir::ExprKind::Break(
2020                        hir::Destination { label: None, target_id },
2021                        Some(from_residual_expr),
2022                    ),
2023                ))
2024            } else {
2025                let ret_expr = self.checked_return(Some(from_residual_expr));
2026                self.arena.alloc(self.expr(try_span, ret_expr))
2027            };
2028            self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span);
2029
2030            let break_pat = self.pat_cf_break(try_span, residual_local);
2031            self.arm(break_pat, ret_expr)
2032        };
2033
2034        hir::ExprKind::Match(
2035            scrutinee,
2036            arena_vec![self; break_arm, continue_arm],
2037            hir::MatchSource::TryDesugar(scrutinee.hir_id),
2038        )
2039    }
2040
2041    /// Desugar `ExprKind::Yeet` from: `do yeet <expr>` into:
2042    /// ```ignore(illustrative)
2043    /// // If there is an enclosing `try {...}`:
2044    /// break 'catch_target FromResidual::from_residual(Yeet(residual));
2045    /// // Otherwise:
2046    /// return FromResidual::from_residual(Yeet(residual));
2047    /// ```
2048    /// But to simplify this, there's a `from_yeet` lang item function which
2049    /// handles the combined `FromResidual::from_residual(Yeet(residual))`.
2050    fn lower_expr_yeet(&mut self, span: Span, sub_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
2051        // The expression (if present) or `()` otherwise.
2052        let (yeeted_span, yeeted_expr) = if let Some(sub_expr) = sub_expr {
2053            (sub_expr.span, self.lower_expr(sub_expr))
2054        } else {
2055            (self.mark_span_with_reason(DesugaringKind::YeetExpr, span, None), self.expr_unit(span))
2056        };
2057
2058        let unstable_span = self.mark_span_with_reason(
2059            DesugaringKind::YeetExpr,
2060            span,
2061            Some(Arc::clone(&self.allow_try_trait)),
2062        );
2063
2064        let from_yeet_expr = self.wrap_in_try_constructor(
2065            hir::LangItem::TryTraitFromYeet,
2066            unstable_span,
2067            yeeted_expr,
2068            yeeted_span,
2069        );
2070
2071        if let Some(catch_id) = self.catch_scope {
2072            let target_id = Ok(catch_id);
2073            hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr))
2074        } else {
2075            self.checked_return(Some(from_yeet_expr))
2076        }
2077    }
2078
2079    // =========================================================================
2080    // Helper methods for building HIR.
2081    // =========================================================================
2082
2083    /// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps`.
2084    ///
2085    /// In terms of drop order, it has the same effect as wrapping `expr` in
2086    /// `{ let _t = $expr; _t }` but should provide better compile-time performance.
2087    ///
2088    /// The drop order can be important in e.g. `if expr { .. }`.
2089    pub(super) fn expr_drop_temps(
2090        &mut self,
2091        span: Span,
2092        expr: &'hir hir::Expr<'hir>,
2093    ) -> &'hir hir::Expr<'hir> {
2094        self.arena.alloc(self.expr_drop_temps_mut(span, expr))
2095    }
2096
2097    pub(super) fn expr_drop_temps_mut(
2098        &mut self,
2099        span: Span,
2100        expr: &'hir hir::Expr<'hir>,
2101    ) -> hir::Expr<'hir> {
2102        self.expr(span, hir::ExprKind::DropTemps(expr))
2103    }
2104
2105    pub(super) fn expr_match(
2106        &mut self,
2107        span: Span,
2108        arg: &'hir hir::Expr<'hir>,
2109        arms: &'hir [hir::Arm<'hir>],
2110        source: hir::MatchSource,
2111    ) -> hir::Expr<'hir> {
2112        self.expr(span, hir::ExprKind::Match(arg, arms, source))
2113    }
2114
2115    fn expr_break(&mut self, span: Span) -> hir::Expr<'hir> {
2116        let expr_break = hir::ExprKind::Break(self.lower_loop_destination(None), None);
2117        self.expr(span, expr_break)
2118    }
2119
2120    fn expr_break_alloc(&mut self, span: Span) -> &'hir hir::Expr<'hir> {
2121        let expr_break = self.expr_break(span);
2122        self.arena.alloc(expr_break)
2123    }
2124
2125    fn expr_mut_addr_of(&mut self, span: Span, e: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
2126        self.expr(span, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e))
2127    }
2128
2129    fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
2130        self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[])))
2131    }
2132
2133    fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> {
2134        let lit = self.arena.alloc(hir::Lit {
2135            span: sp,
2136            node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)),
2137        });
2138        self.expr(sp, hir::ExprKind::Lit(lit))
2139    }
2140
2141    pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> {
2142        self.expr_uint(sp, ast::UintTy::Usize, value as u128)
2143    }
2144
2145    pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> {
2146        self.expr_uint(sp, ast::UintTy::U32, value as u128)
2147    }
2148
2149    pub(super) fn expr_u16(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> {
2150        self.expr_uint(sp, ast::UintTy::U16, value as u128)
2151    }
2152
2153    pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
2154        let lit = self
2155            .arena
2156            .alloc(hir::Lit { span: sp, node: ast::LitKind::Str(value, ast::StrStyle::Cooked) });
2157        self.expr(sp, hir::ExprKind::Lit(lit))
2158    }
2159
2160    pub(super) fn expr_call_mut(
2161        &mut self,
2162        span: Span,
2163        e: &'hir hir::Expr<'hir>,
2164        args: &'hir [hir::Expr<'hir>],
2165    ) -> hir::Expr<'hir> {
2166        self.expr(span, hir::ExprKind::Call(e, args))
2167    }
2168
2169    pub(super) fn expr_call(
2170        &mut self,
2171        span: Span,
2172        e: &'hir hir::Expr<'hir>,
2173        args: &'hir [hir::Expr<'hir>],
2174    ) -> &'hir hir::Expr<'hir> {
2175        self.arena.alloc(self.expr_call_mut(span, e, args))
2176    }
2177
2178    pub(super) fn expr_call_lang_item_fn_mut(
2179        &mut self,
2180        span: Span,
2181        lang_item: hir::LangItem,
2182        args: &'hir [hir::Expr<'hir>],
2183    ) -> hir::Expr<'hir> {
2184        let path = self.arena.alloc(self.expr_lang_item_path(span, lang_item));
2185        self.expr_call_mut(span, path, args)
2186    }
2187
2188    pub(super) fn expr_call_lang_item_fn(
2189        &mut self,
2190        span: Span,
2191        lang_item: hir::LangItem,
2192        args: &'hir [hir::Expr<'hir>],
2193    ) -> &'hir hir::Expr<'hir> {
2194        self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args))
2195    }
2196
2197    fn expr_lang_item_path(&mut self, span: Span, lang_item: hir::LangItem) -> hir::Expr<'hir> {
2198        self.expr(span, hir::ExprKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span))))
2199    }
2200
2201    /// `<LangItem>::name`
2202    pub(super) fn expr_lang_item_type_relative(
2203        &mut self,
2204        span: Span,
2205        lang_item: hir::LangItem,
2206        name: Symbol,
2207    ) -> hir::Expr<'hir> {
2208        let qpath = self.make_lang_item_qpath(lang_item, self.lower_span(span), None);
2209        let path = hir::ExprKind::Path(hir::QPath::TypeRelative(
2210            self.arena.alloc(self.ty(span, hir::TyKind::Path(qpath))),
2211            self.arena.alloc(hir::PathSegment::new(
2212                Ident::new(name, self.lower_span(span)),
2213                self.next_id(),
2214                Res::Err,
2215            )),
2216        ));
2217        self.expr(span, path)
2218    }
2219
2220    pub(super) fn expr_ident(
2221        &mut self,
2222        sp: Span,
2223        ident: Ident,
2224        binding: HirId,
2225    ) -> &'hir hir::Expr<'hir> {
2226        self.arena.alloc(self.expr_ident_mut(sp, ident, binding))
2227    }
2228
2229    pub(super) fn expr_ident_mut(
2230        &mut self,
2231        span: Span,
2232        ident: Ident,
2233        binding: HirId,
2234    ) -> hir::Expr<'hir> {
2235        let hir_id = self.next_id();
2236        let res = Res::Local(binding);
2237        let expr_path = hir::ExprKind::Path(hir::QPath::Resolved(
2238            None,
2239            self.arena.alloc(hir::Path {
2240                span: self.lower_span(span),
2241                res,
2242                segments: arena_vec![self; hir::PathSegment::new(ident, hir_id, res)],
2243            }),
2244        ));
2245
2246        self.expr(span, expr_path)
2247    }
2248
2249    fn expr_unsafe(&mut self, expr: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
2250        let hir_id = self.next_id();
2251        let span = expr.span;
2252        self.expr(
2253            span,
2254            hir::ExprKind::Block(
2255                self.arena.alloc(hir::Block {
2256                    stmts: &[],
2257                    expr: Some(expr),
2258                    hir_id,
2259                    rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
2260                    span: self.lower_span(span),
2261                    targeted_by_break: false,
2262                }),
2263                None,
2264            ),
2265        )
2266    }
2267
2268    fn expr_block_empty(&mut self, span: Span) -> &'hir hir::Expr<'hir> {
2269        let blk = self.block_all(span, &[], None);
2270        let expr = self.expr_block(blk);
2271        self.arena.alloc(expr)
2272    }
2273
2274    pub(super) fn expr_block(&mut self, b: &'hir hir::Block<'hir>) -> hir::Expr<'hir> {
2275        self.expr(b.span, hir::ExprKind::Block(b, None))
2276    }
2277
2278    pub(super) fn expr_array_ref(
2279        &mut self,
2280        span: Span,
2281        elements: &'hir [hir::Expr<'hir>],
2282    ) -> hir::Expr<'hir> {
2283        let addrof = hir::ExprKind::AddrOf(
2284            hir::BorrowKind::Ref,
2285            hir::Mutability::Not,
2286            self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements))),
2287        );
2288        self.expr(span, addrof)
2289    }
2290
2291    pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind<'hir>) -> hir::Expr<'hir> {
2292        let hir_id = self.next_id();
2293        hir::Expr { hir_id, kind, span: self.lower_span(span) }
2294    }
2295
2296    pub(super) fn expr_field(
2297        &mut self,
2298        ident: Ident,
2299        expr: &'hir hir::Expr<'hir>,
2300        span: Span,
2301    ) -> hir::ExprField<'hir> {
2302        hir::ExprField {
2303            hir_id: self.next_id(),
2304            ident,
2305            span: self.lower_span(span),
2306            expr,
2307            is_shorthand: false,
2308        }
2309    }
2310
2311    pub(super) fn arm(
2312        &mut self,
2313        pat: &'hir hir::Pat<'hir>,
2314        expr: &'hir hir::Expr<'hir>,
2315    ) -> hir::Arm<'hir> {
2316        hir::Arm {
2317            hir_id: self.next_id(),
2318            pat,
2319            guard: None,
2320            span: self.lower_span(expr.span),
2321            body: expr,
2322        }
2323    }
2324}
2325
2326/// Used by [`LoweringContext::make_lowered_await`] to customize the desugaring based on what kind
2327/// of future we are awaiting.
2328#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2329enum FutureKind {
2330    /// We are awaiting a normal future
2331    Future,
2332    /// We are awaiting something that's known to be an AsyncIterator (i.e. we are in the header of
2333    /// a `for await` loop)
2334    AsyncIterator,
2335}