rustc_ast_lowering/
expr.rs

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