compiler/rustc_ast_lowering/src/expr.rs RUST 2,402 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,402.
1use std::mem;2use std::ops::ControlFlow;3use std::sync::Arc;45use rustc_ast::*;6use rustc_ast_pretty::pprust::expr_to_string;7use rustc_data_structures::stack::ensure_sufficient_stack;8use rustc_errors::msg;9use rustc_hir as hir;10use rustc_hir::def::{DefKind, Res};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::{ByteSymbol, DUMMY_SP, DesugaringKind, Ident, Span, Spanned, Symbol, respan, sym};16use thin_vec::{ThinVec, thin_vec};17use visit::{Visitor, walk_expr};1819use super::errors::{20    AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, ClosureCannotBeStatic,21    CoroutineTooManyParameters, FunctionalRecordUpdateDestructuringAssignment,22    InclusiveRangeWithNoEnd, MatchArmWithNoBody, NeverPatternWithBody, NeverPatternWithGuard,23    UnderscoreExprLhsAssign,24};25use super::{26    GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,27};28use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};29use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope};3031pub(super) struct WillCreateDefIdsVisitor;3233impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor {34    type Result = ControlFlow<Span>;3536    fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {37        ControlFlow::Break(c.value.span)38    }3940    fn visit_item(&mut self, item: &'v Item) -> Self::Result {41        ControlFlow::Break(item.span)42    }4344    fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result {45        match ex.kind {46            ExprKind::Gen(..) | ExprKind::ConstBlock(..) | ExprKind::Closure(..) => {47                ControlFlow::Break(ex.span)48            }49            _ => walk_expr(self, ex),50        }51    }52}5354impl<'hir> LoweringContext<'_, 'hir> {55    fn lower_exprs(&mut self, exprs: &[Box<Expr>]) -> &'hir [hir::Expr<'hir>] {56        self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))57    }5859    pub(super) fn lower_expr(&mut self, e: &Expr) -> &'hir hir::Expr<'hir> {60        self.arena.alloc(self.lower_expr_mut(e))61    }6263    pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {64        ensure_sufficient_stack(|| {65            let mut span = self.lower_span(e.span);66            match &e.kind {67                // Parenthesis expression does not have a HirId and is handled specially.68                ExprKind::Paren(ex) => {69                    let mut ex = self.lower_expr_mut(ex);70                    // Include parens in span, but only if it is a super-span.71                    if e.span.contains(ex.span) {72                        ex.span = self.lower_span(e.span.with_ctxt(ex.span.ctxt()));73                    }74                    // Merge attributes into the inner expression.75                    if !e.attrs.is_empty() {76                        let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]);77                        let new_attrs = self78                            .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e))79                            .into_iter()80                            .chain(old_attrs.iter().cloned());81                        let new_attrs = &*self.arena.alloc_from_iter(new_attrs);82                        if new_attrs.is_empty() {83                            return ex;84                        }85                        self.attrs.insert(ex.hir_id.local_id, new_attrs);86                    }87                    return ex;88                }89                // Desugar `ExprForLoop`90                // from: `[opt_ident]: for await? <pat> in <iter> <body>`91                //92                // This also needs special handling because the HirId of the returned `hir::Expr` will not93                // correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.94                ExprKind::ForLoop { pat, iter, body, label, kind } => {95                    return self.lower_expr_for(e, pat, iter, body, *label, *kind);96                }97                _ => (),98            }99100            let expr_hir_id = self.lower_node_id(e.id);101            let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e));102103            let kind = match &e.kind {104                ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),105                ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)),106                ExprKind::Repeat(expr, count) => {107                    let expr = self.lower_expr(expr);108                    let count = self.lower_array_length_to_const_arg(count);109                    hir::ExprKind::Repeat(expr, count)110                }111                ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),112                ExprKind::Call(f, args) => {113                    if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f, self.tcx)114                    {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 modifiers129                        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 = self158                        .lower_ty_alloc(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 = self164                        .lower_ty_alloc(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, opt_ty) => {203                    self.lower_expr_try_block(body, opt_ty.as_deref())204                }205                ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match(206                    self.lower_expr(expr),207                    self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),208                    match kind {209                        MatchKind::Prefix => hir::MatchSource::Normal,210                        MatchKind::Postfix => hir::MatchSource::Postfix,211                    },212                ),213                ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),214                ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr),215                ExprKind::Closure(box Closure {216                    binder,217                    capture_clause,218                    constness,219                    coroutine_kind,220                    movability,221                    fn_decl,222                    body,223                    fn_decl_span,224                    fn_arg_span,225                }) => match coroutine_kind {226                    Some(coroutine_kind) => self.lower_expr_coroutine_closure(227                        binder,228                        *capture_clause,229                        e.id,230                        expr_hir_id,231                        *coroutine_kind,232                        *constness,233                        fn_decl,234                        body,235                        *fn_decl_span,236                        *fn_arg_span,237                    ),238                    None => self.lower_expr_closure(239                        attrs,240                        binder,241                        *capture_clause,242                        e.id,243                        *constness,244                        *movability,245                        fn_decl,246                        body,247                        *fn_decl_span,248                        *fn_arg_span,249                    ),250                },251                ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => {252                    let desugaring_kind = match genblock_kind {253                        GenBlockKind::Async => hir::CoroutineDesugaring::Async,254                        GenBlockKind::Gen => hir::CoroutineDesugaring::Gen,255                        GenBlockKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen,256                    };257                    self.make_desugared_coroutine_expr(258                        *capture_clause,259                        e.id,260                        None,261                        *decl_span,262                        e.span,263                        desugaring_kind,264                        hir::CoroutineSource::Block,265                        |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),266                    )267                }268                ExprKind::Block(blk, opt_label) => {269                    // Different from loops, label of block resolves to block id rather than270                    // expr node id.271                    let block_hir_id = self.lower_node_id(blk.id);272                    let opt_label = self.lower_label(*opt_label, blk.id, block_hir_id);273                    let hir_block = self.arena.alloc(self.lower_block_noalloc(274                        block_hir_id,275                        blk,276                        opt_label.is_some(),277                    ));278                    hir::ExprKind::Block(hir_block, opt_label)279                }280                ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span),281                ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp(282                    self.lower_assign_op(*op),283                    self.lower_expr(el),284                    self.lower_expr(er),285                ),286                ExprKind::Field(el, ident) => {287                    hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident))288                }289                ExprKind::Index(el, er, brackets_span) => hir::ExprKind::Index(290                    self.lower_expr(el),291                    self.lower_expr(er),292                    self.lower_span(*brackets_span),293                ),294                ExprKind::Range(e1, e2, lims) => {295                    span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None);296                    self.lower_expr_range(span, e1.as_deref(), e2.as_deref(), *lims)297                }298                ExprKind::Underscore => {299                    let guar = self.dcx().emit_err(UnderscoreExprLhsAssign { span: e.span });300                    hir::ExprKind::Err(guar)301                }302                ExprKind::Path(qself, path) => {303                    let qpath = self.lower_qpath(304                        e.id,305                        qself,306                        path,307                        ParamMode::Optional,308                        AllowReturnTypeNotation::No,309                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),310                        None,311                    );312                    hir::ExprKind::Path(qpath)313                }314                ExprKind::Break(opt_label, opt_expr) => {315                    let opt_expr = opt_expr.as_ref().map(|x| self.lower_expr(x));316                    hir::ExprKind::Break(self.lower_jump_destination(e.id, *opt_label), opt_expr)317                }318                ExprKind::Continue(opt_label) => {319                    hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label))320                }321                ExprKind::Ret(e) => {322                    let expr = e.as_ref().map(|x| self.lower_expr(x));323                    self.checked_return(expr)324                }325                ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),326                ExprKind::Become(sub_expr) => {327                    let sub_expr = self.lower_expr(sub_expr);328                    hir::ExprKind::Become(sub_expr)329                }330                ExprKind::InlineAsm(asm) => {331                    hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))332                }333                ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),334                ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(335                    self.lower_ty_alloc(336                        container,337                        ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),338                    ),339                    self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))),340                ),341                ExprKind::Struct(se) => {342                    let rest = match se.rest {343                        StructRest::Base(ref e) => hir::StructTailExpr::Base(self.lower_expr(e)),344                        StructRest::Rest(sp) => {345                            hir::StructTailExpr::DefaultFields(self.lower_span(sp))346                        }347                        StructRest::None => hir::StructTailExpr::None,348                        StructRest::NoneWithError(guar) => hir::StructTailExpr::NoneWithError(guar),349                    };350                    hir::ExprKind::Struct(351                        self.arena.alloc(self.lower_qpath(352                            e.id,353                            &se.qself,354                            &se.path,355                            ParamMode::Optional,356                            AllowReturnTypeNotation::No,357                            ImplTraitContext::Disallowed(ImplTraitPosition::Path),358                            None,359                        )),360                        self.arena361                            .alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),362                        rest,363                    )364                }365                ExprKind::Yield(kind) => self.lower_expr_yield(e.span, kind.expr().map(|x| &**x)),366                ExprKind::Err(guar) => hir::ExprKind::Err(*guar),367368                ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(369                    *kind,370                    self.lower_expr(expr),371                    ty.as_ref().map(|ty| {372                        self.lower_ty_alloc(373                            ty,374                            ImplTraitContext::Disallowed(ImplTraitPosition::Cast),375                        )376                    }),377                ),378379                ExprKind::Dummy => {380                    span_bug!(e.span, "lowered ExprKind::Dummy")381                }382383                ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),384385                ExprKind::Paren(_) | ExprKind::ForLoop { .. } => {386                    unreachable!("already handled")387                }388389                ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),390            };391392            hir::Expr { hir_id: expr_hir_id, kind, span }393        })394    }395396    pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {397        self.with_new_scopes(c.value.span, |this| {398            let def_id = this.local_def_id(c.id);399            hir::ConstBlock {400                def_id,401                hir_id: this.lower_node_id(c.id),402                body: this.lower_const_body(c.value.span, Some(&c.value)),403            }404        })405    }406407    pub(crate) fn lower_lit(&mut self, token_lit: &token::Lit, span: Span) -> hir::Lit {408        let lit_kind = match LitKind::from_token_lit(*token_lit) {409            Ok(lit_kind) => lit_kind,410            Err(err) => {411                let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span);412                LitKind::Err(guar)413            }414        };415        respan(self.lower_span(span), lit_kind)416    }417418    fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {419        match u {420            UnOp::Deref => hir::UnOp::Deref,421            UnOp::Not => hir::UnOp::Not,422            UnOp::Neg => hir::UnOp::Neg,423        }424    }425426    fn lower_binop(&mut self, b: BinOp) -> BinOp {427        Spanned { node: b.node, span: self.lower_span(b.span) }428    }429430    fn lower_assign_op(&mut self, a: AssignOp) -> AssignOp {431        Spanned { node: a.node, span: self.lower_span(a.span) }432    }433434    fn lower_legacy_const_generics(435        &mut self,436        mut f: Expr,437        args: ThinVec<Box<Expr>>,438        legacy_args_idx: &[usize],439    ) -> hir::ExprKind<'hir> {440        let ExprKind::Path(None, path) = &mut f.kind else {441            unreachable!();442        };443444        let mut error = None;445        let mut invalid_expr_error = |tcx: TyCtxt<'_>, span| {446            // Avoid emitting the error multiple times.447            if error.is_none() {448                let mut const_args = vec![];449                let mut other_args = vec![];450                for (idx, arg) in args.iter().enumerate() {451                    if legacy_args_idx.contains(&idx) {452                        const_args.push(format!("{{ {} }}", expr_to_string(arg)));453                    } else {454                        other_args.push(expr_to_string(arg));455                    }456                }457                let suggestion = UseConstGenericArg {458                    end_of_fn: f.span.shrink_to_hi(),459                    const_args: const_args.join(", "),460                    other_args: other_args.join(", "),461                    call_args: args[0].span.to(args.last().unwrap().span),462                };463                error = Some(tcx.dcx().emit_err(InvalidLegacyConstGenericArg { span, suggestion }));464            }465            error.unwrap()466        };467468        // Split the arguments into const generics and normal arguments469        let mut real_args = vec![];470        let mut generic_args = ThinVec::new();471        for (idx, arg) in args.iter().cloned().enumerate() {472            if legacy_args_idx.contains(&idx) {473                let node_id = self.next_node_id();474                self.create_def(node_id, None, DefKind::AnonConst, f.span);475                let const_value =476                    if let ControlFlow::Break(span) = WillCreateDefIdsVisitor.visit_expr(&arg) {477                        Box::new(Expr {478                            id: self.next_node_id(),479                            kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),480                            span: f.span,481                            attrs: [].into(),482                            tokens: None,483                        })484                    } else {485                        arg486                    };487488                let anon_const = AnonConst {489                    id: node_id,490                    value: const_value,491                    mgca_disambiguation: MgcaDisambiguation::AnonConst,492                };493                generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));494            } else {495                real_args.push(arg);496            }497        }498499        // Add generic args to the last element of the path.500        let last_segment = path.segments.last_mut().unwrap();501        assert!(last_segment.args.is_none());502        last_segment.args = Some(Box::new(GenericArgs::AngleBracketed(AngleBracketedArgs {503            span: DUMMY_SP,504            args: generic_args,505        })));506507        // Now lower everything as normal.508        let f = self.lower_expr(&f);509        hir::ExprKind::Call(f, self.lower_exprs(&real_args))510    }511512    fn lower_expr_if(513        &mut self,514        cond: &Expr,515        then: &Block,516        else_opt: Option<&Expr>,517    ) -> hir::ExprKind<'hir> {518        let lowered_cond = self.lower_expr(cond);519        let then_expr = self.lower_block_expr(then);520        if let Some(rslt) = else_opt {521            hir::ExprKind::If(522                lowered_cond,523                self.arena.alloc(then_expr),524                Some(self.lower_expr(rslt)),525            )526        } else {527            hir::ExprKind::If(lowered_cond, self.arena.alloc(then_expr), None)528        }529    }530531    // We desugar: `'label: while $cond $body` into:532    //533    // ```534    // 'label: loop {535    //   if { let _t = $cond; _t } {536    //     $body537    //   }538    //   else {539    //     break;540    //   }541    // }542    // ```543    //544    // Wrap in a construct equivalent to `{ let _t = $cond; _t }`545    // to preserve drop semantics since `while $cond { ... }` does not546    // let temporaries live outside of `cond`.547    fn lower_expr_while_in_loop_scope(548        &mut self,549        span: Span,550        cond: &Expr,551        body: &Block,552        opt_label: Option<Label>,553    ) -> hir::ExprKind<'hir> {554        let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond));555        let then = self.lower_block_expr(body);556        let expr_break = self.expr_break(span);557        let stmt_break = self.stmt_expr(span, expr_break);558        let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);559        let else_expr = self.arena.alloc(self.expr_block(else_blk));560        let if_kind = hir::ExprKind::If(lowered_cond, self.arena.alloc(then), Some(else_expr));561        let if_expr = self.expr(span, if_kind);562        let block = self.block_expr(self.arena.alloc(if_expr));563        let span = self.lower_span(span.with_hi(cond.span.hi()));564        hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span)565    }566567    /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,568    /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }`569    /// and save the block id to use it as a break target for desugaring of the `?` operator.570    fn lower_expr_try_block(&mut self, body: &Block, opt_ty: Option<&Ty>) -> hir::ExprKind<'hir> {571        let body_hir_id = self.lower_node_id(body.id);572        let new_scope = if opt_ty.is_some() {573            TryBlockScope::Heterogeneous(body_hir_id)574        } else {575            TryBlockScope::Homogeneous(body_hir_id)576        };577        let whole_block = self.with_try_block_scope(new_scope, |this| {578            let mut block = this.lower_block_noalloc(body_hir_id, body, true);579580            // Final expression of the block (if present) or `()` with span at the end of block581            let (try_span, tail_expr) = if let Some(expr) = block.expr.take() {582                (583                    this.mark_span_with_reason(584                        DesugaringKind::TryBlock,585                        expr.span,586                        Some(Arc::clone(&this.allow_try_trait)),587                    ),588                    expr,589                )590            } else {591                let try_span = this.mark_span_with_reason(592                    DesugaringKind::TryBlock,593                    this.tcx.sess.source_map().end_point(body.span),594                    Some(Arc::clone(&this.allow_try_trait)),595                );596597                (try_span, this.expr_unit(try_span))598            };599600            let ok_wrapped_span =601                this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);602603            // `::std::ops::Try::from_output($tail_expr)`604            block.expr = Some(this.wrap_in_try_constructor(605                hir::LangItem::TryTraitFromOutput,606                try_span,607                tail_expr,608                ok_wrapped_span,609            ));610611            this.arena.alloc(block)612        });613614        if let Some(ty) = opt_ty {615            let ty = self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path));616            let block_expr = self.arena.alloc(self.expr_block(whole_block));617            hir::ExprKind::Type(block_expr, ty)618        } else {619            hir::ExprKind::Block(whole_block, None)620        }621    }622623    fn wrap_in_try_constructor(624        &mut self,625        lang_item: hir::LangItem,626        method_span: Span,627        expr: &'hir hir::Expr<'hir>,628        overall_span: Span,629    ) -> &'hir hir::Expr<'hir> {630        let constructor = self.arena.alloc(self.expr_lang_item_path(method_span, lang_item));631        self.expr_call(overall_span, constructor, std::slice::from_ref(expr))632    }633634    fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {635        let pat = self.lower_pat(&arm.pat);636        let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond));637        let hir_id = self.next_id();638        let span = self.lower_span(arm.span);639        self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm);640        let is_never_pattern = pat.is_never_pattern();641        // We need to lower the body even if it's unneeded for never pattern in match,642        // ensure that we can get HirId for DefId if need (issue #137708).643        let body = arm.body.as_ref().map(|x| self.lower_expr(x));644        let body = if let Some(body) = body645            && !is_never_pattern646        {647            body648        } else {649            // Either `body.is_none()` or `is_never_pattern` here.650            if !is_never_pattern {651                if self.tcx.features().never_patterns() {652                    // If the feature is off we already emitted the error after parsing.653                    let suggestion = span.shrink_to_hi();654                    self.dcx().emit_err(MatchArmWithNoBody { span, suggestion });655                }656            } else if let Some(body) = &arm.body {657                self.dcx().emit_err(NeverPatternWithBody { span: body.span });658            } else if let Some(g) = &arm.guard {659                self.dcx().emit_err(NeverPatternWithGuard { span: g.span() });660            }661662            // We add a fake `loop {}` arm body so that it typecks to `!`. The mir lowering of never663            // patterns ensures this loop is not reachable.664            let block = self.arena.alloc(hir::Block {665                stmts: &[],666                expr: None,667                hir_id: self.next_id(),668                rules: hir::BlockCheckMode::DefaultBlock,669                span,670                targeted_by_break: false,671            });672            self.arena.alloc(hir::Expr {673                hir_id: self.next_id(),674                kind: hir::ExprKind::Loop(block, None, hir::LoopSource::Loop, span),675                span,676            })677        };678        hir::Arm { hir_id, pat, guard, body, span }679    }680681    fn lower_capture_clause(&mut self, capture_clause: CaptureBy) -> CaptureBy {682        match capture_clause {683            CaptureBy::Ref => CaptureBy::Ref,684            CaptureBy::Use { use_kw } => CaptureBy::Use { use_kw: self.lower_span(use_kw) },685            CaptureBy::Value { move_kw } => CaptureBy::Value { move_kw: self.lower_span(move_kw) },686        }687    }688689    /// Lower/desugar a coroutine construct.690    ///691    /// In particular, this creates the correct async resume argument and `_task_context`.692    ///693    /// This results in:694    ///695    /// ```text696    /// static move? |<_task_context?>| -> <return_ty> {697    ///     <body>698    /// }699    /// ```700    pub(super) fn make_desugared_coroutine_expr(701        &mut self,702        capture_clause: CaptureBy,703        closure_node_id: NodeId,704        return_ty: Option<hir::FnRetTy<'hir>>,705        fn_decl_span: Span,706        span: Span,707        desugaring_kind: hir::CoroutineDesugaring,708        coroutine_source: hir::CoroutineSource,709        body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,710    ) -> hir::ExprKind<'hir> {711        let closure_def_id = self.local_def_id(closure_node_id);712        let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source);713714        // The `async` desugaring takes a resume argument and maintains a `task_context`,715        // whereas a generator does not.716        let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind {717            hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => {718                // Resume argument type: `ResumeTy`719                let unstable_span = self.mark_span_with_reason(720                    DesugaringKind::Async,721                    self.lower_span(span),722                    Some(Arc::clone(&self.allow_gen_future)),723                );724                let resume_ty =725                    self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None);726                let input_ty = hir::Ty {727                    hir_id: self.next_id(),728                    kind: hir::TyKind::Path(resume_ty),729                    span: unstable_span,730                };731                let inputs = arena_vec![self; input_ty];732733                // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.734                let (pat, task_context_hid) = self.pat_ident_binding_mode(735                    span,736                    Ident::with_dummy_span(sym::_task_context),737                    hir::BindingMode::MUT,738                );739                let param = hir::Param {740                    hir_id: self.next_id(),741                    pat,742                    ty_span: self.lower_span(span),743                    span: self.lower_span(span),744                };745                let params = arena_vec![self; param];746747                (inputs, params, Some(task_context_hid))748            }749            hir::CoroutineDesugaring::Gen => (&[], &[], None),750        };751752        let output =753            return_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));754755        let fn_decl = self.arena.alloc(hir::FnDecl {756            inputs,757            output,758            fn_decl_kind: hir::FnDeclFlags::default(),759        });760761        let body = self.lower_body(move |this| {762            this.coroutine_kind = Some(coroutine_kind);763764            let old_ctx = this.task_context;765            if task_context.is_some() {766                this.task_context = task_context;767            }768            let res = body(this);769            this.task_context = old_ctx;770771            (params, res)772        });773774        // `static |<_task_context?>| -> <return_ty> { <body> }`:775        hir::ExprKind::Closure(self.arena.alloc(hir::Closure {776            def_id: closure_def_id,777            binder: hir::ClosureBinder::Default,778            capture_clause: self.lower_capture_clause(capture_clause),779            bound_generic_params: &[],780            fn_decl,781            body,782            fn_decl_span: self.lower_span(fn_decl_span),783            fn_arg_span: None,784            kind: hir::ClosureKind::Coroutine(coroutine_kind),785            constness: hir::Constness::NotConst,786        }))787    }788789    /// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to790    /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.791    pub(super) fn maybe_forward_track_caller(792        &mut self,793        span: Span,794        outer_hir_id: HirId,795        inner_hir_id: HirId,796    ) {797        if self.tcx.features().async_fn_track_caller()798            && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)799            && find_attr!(*attrs, TrackCaller(_))800        {801            let unstable_span = self.mark_span_with_reason(802                DesugaringKind::Async,803                span,804                Some(Arc::clone(&self.allow_gen_future)),805            );806            self.lower_attrs(807                inner_hir_id,808                &[Attribute {809                    kind: AttrKind::Normal(Box::new(NormalAttr::from_ident(Ident::new(810                        sym::track_caller,811                        span,812                    )))),813                    id: self.tcx.sess.psess.attr_id_generator.mk_attr_id(),814                    style: AttrStyle::Outer,815                    span: unstable_span,816                }],817                span,818                Target::Fn,819            );820        }821    }822823    /// Desugar `<expr>.await` into:824    /// ```ignore (pseudo-rust)825    /// match ::std::future::IntoFuture::into_future(<expr>) {826    ///     mut __awaitee => loop {827    ///         match unsafe { ::std::future::Future::poll(828    ///             <::std::pin::Pin>::new_unchecked(&mut __awaitee),829    ///             ::std::future::get_context(task_context),830    ///         ) } {831    ///             ::std::task::Poll::Ready(result) => break result,832    ///             ::std::task::Poll::Pending => {}833    ///         }834    ///         task_context = yield ();835    ///     }836    /// }837    /// ```838    fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {839        let expr = self.arena.alloc(self.lower_expr_mut(expr));840        self.make_lowered_await(await_kw_span, expr, FutureKind::Future)841    }842843    /// Takes an expr that has already been lowered and generates a desugared await loop around it844    fn make_lowered_await(845        &mut self,846        await_kw_span: Span,847        expr: &'hir hir::Expr<'hir>,848        await_kind: FutureKind,849    ) -> hir::ExprKind<'hir> {850        let full_span = expr.span.to(await_kw_span);851852        let is_async_gen = match self.coroutine_kind {853            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false,854            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,855            Some(hir::CoroutineKind::Coroutine(_))856            | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _))857            | None => {858                // Lower to a block `{ EXPR; <error> }` so that the awaited expr859                // is not accidentally orphaned.860                let stmt_id = self.next_id();861                let expr_err = self.expr(862                    expr.span,863                    hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {864                        await_kw_span,865                        item_span: self.current_item,866                    })),867                );868                return hir::ExprKind::Block(869                    self.block_all(870                        expr.span,871                        arena_vec![self; hir::Stmt {872                            hir_id: stmt_id,873                            kind: hir::StmtKind::Semi(expr),874                            span: expr.span,875                        }],876                        Some(self.arena.alloc(expr_err)),877                    ),878                    None,879                );880            }881        };882883        let features = match await_kind {884            FutureKind::Future if is_async_gen => Some(Arc::clone(&self.allow_async_gen)),885            FutureKind::Future => None,886            FutureKind::AsyncIterator => Some(Arc::clone(&self.allow_for_await)),887        };888        let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features);889        let gen_future_span = self.mark_span_with_reason(890            DesugaringKind::Await,891            full_span,892            Some(Arc::clone(&self.allow_gen_future)),893        );894        let expr_hir_id = expr.hir_id;895896        // Note that the name of this binding must not be changed to something else because897        // debuggers and debugger extensions expect it to be called `__awaitee`. They use898        // this name to identify what is being awaited by a suspended async functions.899        let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);900        let (awaitee_pat, awaitee_pat_hid) =901            self.pat_ident_binding_mode(gen_future_span, awaitee_ident, hir::BindingMode::MUT);902903        let task_context_ident = Ident::with_dummy_span(sym::_task_context);904905        // unsafe {906        //     ::std::future::Future::poll(907        //         ::std::pin::Pin::new_unchecked(&mut __awaitee),908        //         ::std::future::get_context(task_context),909        //     )910        // }911        let poll_expr = {912            let awaitee = self.expr_ident(span, awaitee_ident, awaitee_pat_hid);913            let ref_mut_awaitee = self.expr_mut_addr_of(span, awaitee);914915            let Some(task_context_hid) = self.task_context else {916                unreachable!("use of `await` outside of an async context.");917            };918919            let task_context = self.expr_ident_mut(span, task_context_ident, task_context_hid);920921            let new_unchecked = self.expr_call_lang_item_fn_mut(922                span,923                hir::LangItem::PinNewUnchecked,924                arena_vec![self; ref_mut_awaitee],925            );926            let get_context = self.expr_call_lang_item_fn_mut(927                gen_future_span,928                hir::LangItem::GetContext,929                arena_vec![self; task_context],930            );931            let call = match await_kind {932                FutureKind::Future => self.expr_call_lang_item_fn(933                    span,934                    hir::LangItem::FuturePoll,935                    arena_vec![self; new_unchecked, get_context],936                ),937                FutureKind::AsyncIterator => self.expr_call_lang_item_fn(938                    span,939                    hir::LangItem::AsyncIteratorPollNext,940                    arena_vec![self; new_unchecked, get_context],941                ),942            };943            self.arena.alloc(self.expr_unsafe(span, call))944        };945946        // `::std::task::Poll::Ready(result) => break result`947        let loop_node_id = self.next_node_id();948        let loop_hir_id = self.lower_node_id(loop_node_id);949        let ready_arm = {950            let x_ident = Ident::with_dummy_span(sym::result);951            let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident);952            let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);953            let ready_field = self.single_pat_field(gen_future_span, x_pat);954            let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);955            let break_x = self.with_loop_scope(loop_hir_id, move |this| {956                let expr_break =957                    hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));958                this.arena.alloc(this.expr(gen_future_span, expr_break))959            });960            self.arm(ready_pat, break_x, span)961        };962963        // `::std::task::Poll::Pending => {}`964        let pending_arm = {965            let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);966            let empty_block = self.expr_block_empty(span);967            self.arm(pending_pat, empty_block, span)968        };969970        let inner_match_stmt = {971            let match_expr = self.expr_match(972                span,973                poll_expr,974                arena_vec![self; ready_arm, pending_arm],975                hir::MatchSource::AwaitDesugar,976            );977            self.stmt_expr(span, match_expr)978        };979980        // Depending on `async` of `async gen`:981        // async     - task_context = yield ();982        // async gen - task_context = yield ASYNC_GEN_PENDING;983        let yield_stmt = {984            let yielded = if is_async_gen {985                self.arena.alloc(self.expr_lang_item_path(span, hir::LangItem::AsyncGenPending))986            } else {987                self.expr_unit(span)988            };989990            let yield_expr = self.expr(991                span,992                hir::ExprKind::Yield(yielded, hir::YieldSource::Await { expr: Some(expr_hir_id) }),993            );994            let yield_expr = self.arena.alloc(yield_expr);995996            let Some(task_context_hid) = self.task_context else {997                unreachable!("use of `await` outside of an async context.");998            };9991000            let lhs = self.expr_ident(span, task_context_ident, task_context_hid);1001            let assign =1002                self.expr(span, hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span)));1003            self.stmt_expr(span, assign)1004        };10051006        let loop_block = self.block_all(span, arena_vec![self; inner_match_stmt, yield_stmt], None);10071008        // loop { .. }1009        let loop_expr = self.arena.alloc(hir::Expr {1010            hir_id: loop_hir_id,1011            kind: hir::ExprKind::Loop(1012                loop_block,1013                None,1014                hir::LoopSource::Loop,1015                self.lower_span(span),1016            ),1017            span: self.lower_span(span),1018        });10191020        // mut __awaitee => loop { ... }1021        let awaitee_arm = self.arm(awaitee_pat, loop_expr, span);10221023        // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`1024        let into_future_expr = match await_kind {1025            FutureKind::Future => self.expr_call_lang_item_fn(1026                span,1027                hir::LangItem::IntoFutureIntoFuture,1028                arena_vec![self; *expr],1029            ),1030            // Not needed for `for await` because we expect to have already called1031            // `IntoAsyncIterator::into_async_iter` on it.1032            FutureKind::AsyncIterator => expr,1033        };10341035        // match <into_future_expr> {1036        //     mut __awaitee => loop { .. }1037        // }1038        hir::ExprKind::Match(1039            into_future_expr,1040            arena_vec![self; awaitee_arm],1041            hir::MatchSource::AwaitDesugar,1042        )1043    }10441045    fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {1046        hir::ExprKind::Use(self.lower_expr(expr), self.lower_span(use_kw_span))1047    }10481049    fn lower_expr_closure(1050        &mut self,1051        attrs: &[rustc_hir::Attribute],1052        binder: &ClosureBinder,1053        capture_clause: CaptureBy,1054        closure_id: NodeId,1055        constness: Const,1056        movability: Movability,1057        decl: &FnDecl,1058        body: &Expr,1059        fn_decl_span: Span,1060        fn_arg_span: Span,1061    ) -> hir::ExprKind<'hir> {1062        let closure_def_id = self.local_def_id(closure_id);1063        let (binder_clause, generic_params) = self.lower_closure_binder(binder);10641065        let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {1066            let mut coroutine_kind =1067                find_attr!(attrs, Coroutine => hir::CoroutineKind::Coroutine(Movability::Movable));10681069            // FIXME(contracts): Support contracts on closures?1070            let body_id = this.lower_fn_body(decl, None, |this| {1071                this.coroutine_kind = coroutine_kind;1072                let e = this.lower_expr_mut(body);1073                coroutine_kind = this.coroutine_kind;1074                e1075            });1076            let coroutine_option =1077                this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);1078            (body_id, coroutine_option)1079        });10801081        let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);1082        // Lower outside new scope to preserve `is_in_loop_condition`.1083        let fn_decl = self.lower_fn_decl(decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);10841085        let c = self.arena.alloc(hir::Closure {1086            def_id: closure_def_id,1087            binder: binder_clause,1088            capture_clause: self.lower_capture_clause(capture_clause),1089            bound_generic_params,1090            fn_decl,1091            body: body_id,1092            fn_decl_span: self.lower_span(fn_decl_span),1093            fn_arg_span: Some(self.lower_span(fn_arg_span)),1094            kind: closure_kind,1095            constness: self.lower_constness(constness),1096        });10971098        hir::ExprKind::Closure(c)1099    }11001101    fn closure_movability_for_fn(1102        &mut self,1103        decl: &FnDecl,1104        fn_decl_span: Span,1105        coroutine_kind: Option<hir::CoroutineKind>,1106        movability: Movability,1107    ) -> hir::ClosureKind {1108        match coroutine_kind {1109            Some(hir::CoroutineKind::Coroutine(_)) => {1110                if decl.inputs.len() > 1 {1111                    self.dcx().emit_err(CoroutineTooManyParameters { fn_decl_span });1112                }1113                hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(movability))1114            }1115            Some(1116                hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)1117                | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)1118                | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _),1119            ) => {1120                panic!("non-`async`/`gen` closure body turned `async`/`gen` during lowering");1121            }1122            None => {1123                if movability == Movability::Static {1124                    self.dcx().emit_err(ClosureCannotBeStatic { fn_decl_span });1125                }1126                hir::ClosureKind::Closure1127            }1128        }1129    }11301131    fn lower_closure_binder<'c>(1132        &mut self,1133        binder: &'c ClosureBinder,1134    ) -> (hir::ClosureBinder, &'c [GenericParam]) {1135        let (binder, params) = match binder {1136            ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]),1137            ClosureBinder::For { span, generic_params } => {1138                let span = self.lower_span(*span);1139                (hir::ClosureBinder::For { span }, &**generic_params)1140            }1141        };11421143        (binder, params)1144    }11451146    fn lower_expr_coroutine_closure(1147        &mut self,1148        binder: &ClosureBinder,1149        capture_clause: CaptureBy,1150        closure_id: NodeId,1151        closure_hir_id: HirId,1152        coroutine_kind: CoroutineKind,1153        constness: Const,1154        decl: &FnDecl,1155        body: &Expr,1156        fn_decl_span: Span,1157        fn_arg_span: Span,1158    ) -> hir::ExprKind<'hir> {1159        let closure_def_id = self.local_def_id(closure_id);1160        let (binder_clause, generic_params) = self.lower_closure_binder(binder);11611162        let coroutine_desugaring = match coroutine_kind {1163            CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,1164            CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,1165            CoroutineKind::AsyncGen { span, .. } => {1166                span_bug!(span, "only async closures and `iter!` closures are supported currently")1167            }1168        };11691170        let body = self.with_new_scopes(fn_decl_span, |this| {1171            let inner_decl =1172                FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };11731174            // Transform `async |x: u8| -> X { ... }` into1175            // `|x: u8| || -> X { ... }`.1176            let body_id = this.lower_body(|this| {1177                let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(1178                    &inner_decl,1179                    |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),1180                    fn_decl_span,1181                    body.span,1182                    coroutine_kind,1183                    hir::CoroutineSource::Closure,1184                );11851186                this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id);11871188                (parameters, expr)1189            });1190            body_id1191        });11921193        let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);1194        // We need to lower the declaration outside the new scope, because we1195        // have to conserve the state of being inside a loop condition for the1196        // closure argument types.1197        let fn_decl =1198            self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);11991200        if let Const::Yes(span) = constness {1201            self.dcx().span_err(span, "const coroutines are not supported");1202        }12031204        let c = self.arena.alloc(hir::Closure {1205            def_id: closure_def_id,1206            binder: binder_clause,1207            capture_clause: self.lower_capture_clause(capture_clause),1208            bound_generic_params,1209            fn_decl,1210            body,1211            fn_decl_span: self.lower_span(fn_decl_span),1212            fn_arg_span: Some(self.lower_span(fn_arg_span)),1213            // Lower this as a `CoroutineClosure`. That will ensure that HIR typeck1214            // knows that a `FnDecl` output type like `-> &str` actually means1215            // "coroutine that returns &str", rather than directly returning a `&str`.1216            kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring),1217            constness: self.lower_constness(constness),1218        });1219        hir::ExprKind::Closure(c)1220    }12211222    /// Destructure the LHS of complex assignments.1223    /// For instance, lower `(a, b) = t` to `{ let (lhs1, lhs2) = t; a = lhs1; b = lhs2; }`.1224    fn lower_expr_assign(1225        &mut self,1226        lhs: &Expr,1227        rhs: &Expr,1228        eq_sign_span: Span,1229        whole_span: Span,1230    ) -> hir::ExprKind<'hir> {1231        // Return early in case of an ordinary assignment.1232        fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {1233            match &lhs.kind {1234                ExprKind::Array(..)1235                | ExprKind::Struct(..)1236                | ExprKind::Tup(..)1237                | ExprKind::Underscore => false,1238                // Check for unit struct constructor.1239                ExprKind::Path(..) => lower_ctx.extract_unit_struct_path(lhs).is_none(),1240                // Check for tuple struct constructor.1241                ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(),1242                ExprKind::Paren(e) => {1243                    match e.kind {1244                        // We special-case `(..)` for consistency with patterns.1245                        ExprKind::Range(None, None, RangeLimits::HalfOpen) => false,1246                        _ => is_ordinary(lower_ctx, e),1247                    }1248                }1249                _ => true,1250            }1251        }1252        if is_ordinary(self, lhs) {1253            return hir::ExprKind::Assign(1254                self.lower_expr(lhs),1255                self.lower_expr(rhs),1256                self.lower_span(eq_sign_span),1257            );1258        }12591260        let mut assignments = vec![];12611262        // The LHS becomes a pattern: `(lhs1, lhs2)`.1263        let pat = self.destructure_assign(lhs, eq_sign_span, &mut assignments);1264        let rhs = self.lower_expr(rhs);12651266        // Introduce a `let` for destructuring: `let (lhs1, lhs2) = t`.1267        let destructure_let =1268            self.stmt_let_pat(None, whole_span, Some(rhs), pat, hir::LocalSource::AssignDesugar);12691270        // `a = lhs1; b = lhs2;`.1271        let stmts = self.arena.alloc_from_iter(std::iter::once(destructure_let).chain(assignments));12721273        // Wrap everything in a block.1274        hir::ExprKind::Block(self.block_all(whole_span, stmts, None), None)1275    }12761277    /// If the given expression is a path to a tuple struct, returns that path.1278    /// It is not a complete check, but just tries to reject most paths early1279    /// if they are not tuple structs.1280    /// Type checking will take care of the full validation later.1281    fn extract_tuple_struct_path<'a>(1282        &mut self,1283        expr: &'a Expr,1284    ) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> {1285        if let ExprKind::Path(qself, path) = &expr.kind {1286            // Does the path resolve to something disallowed in a tuple struct/variant pattern?1287            if let Some(partial_res) = self.get_partial_res(expr.id) {1288                if let Some(res) = partial_res.full_res()1289                    && !res.expected_in_tuple_struct_pat()1290                {1291                    return None;1292                }1293            }1294            return Some((qself, path));1295        }1296        None1297    }12981299    /// If the given expression is a path to a unit struct, returns that path.1300    /// It is not a complete check, but just tries to reject most paths early1301    /// if they are not unit structs.1302    /// Type checking will take care of the full validation later.1303    fn extract_unit_struct_path<'a>(1304        &mut self,1305        expr: &'a Expr,1306    ) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> {1307        if let ExprKind::Path(qself, path) = &expr.kind {1308            // Does the path resolve to something disallowed in a unit struct/variant pattern?1309            if let Some(partial_res) = self.get_partial_res(expr.id) {1310                if let Some(res) = partial_res.full_res()1311                    && !res.expected_in_unit_struct_pat()1312                {1313                    return None;1314                }1315            }1316            return Some((qself, path));1317        }1318        None1319    }13201321    /// Convert the LHS of a destructuring assignment to a pattern.1322    /// Each sub-assignment is recorded in `assignments`.1323    fn destructure_assign(1324        &mut self,1325        lhs: &Expr,1326        eq_sign_span: Span,1327        assignments: &mut Vec<hir::Stmt<'hir>>,1328    ) -> &'hir hir::Pat<'hir> {1329        self.arena.alloc(self.destructure_assign_mut(lhs, eq_sign_span, assignments))1330    }13311332    fn destructure_assign_mut(1333        &mut self,1334        lhs: &Expr,1335        eq_sign_span: Span,1336        assignments: &mut Vec<hir::Stmt<'hir>>,1337    ) -> hir::Pat<'hir> {1338        match &lhs.kind {1339            // Underscore pattern.1340            ExprKind::Underscore => {1341                return self.pat_without_dbm(lhs.span, hir::PatKind::Wild);1342            }1343            // Slice patterns.1344            ExprKind::Array(elements) => {1345                let (pats, rest) =1346                    self.destructure_sequence(elements, "slice", eq_sign_span, assignments);1347                let slice_pat = if let Some((i, span)) = rest {1348                    let (before, after) = pats.split_at(i);1349                    hir::PatKind::Slice(1350                        before,1351                        Some(self.arena.alloc(self.pat_without_dbm(span, hir::PatKind::Wild))),1352                        after,1353                    )1354                } else {1355                    hir::PatKind::Slice(pats, None, &[])1356                };1357                return self.pat_without_dbm(lhs.span, slice_pat);1358            }1359            // Tuple structs.1360            ExprKind::Call(callee, args) => {1361                if let Some((qself, path)) = self.extract_tuple_struct_path(callee) {1362                    let (pats, rest) = self.destructure_sequence(1363                        args,1364                        "tuple struct or variant",1365                        eq_sign_span,1366                        assignments,1367                    );1368                    let qpath = self.lower_qpath(1369                        callee.id,1370                        qself,1371                        path,1372                        ParamMode::Optional,1373                        AllowReturnTypeNotation::No,1374                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),1375                        None,1376                    );1377                    // Destructure like a tuple struct.1378                    let tuple_struct_pat = hir::PatKind::TupleStruct(1379                        qpath,1380                        pats,1381                        hir::DotDotPos::new(rest.map(|r| r.0)),1382                    );1383                    return self.pat_without_dbm(lhs.span, tuple_struct_pat);1384                }1385            }1386            // Unit structs and enum variants.1387            ExprKind::Path(..) => {1388                if let Some((qself, path)) = self.extract_unit_struct_path(lhs) {1389                    let qpath = self.lower_qpath(1390                        lhs.id,1391                        qself,1392                        path,1393                        ParamMode::Optional,1394                        AllowReturnTypeNotation::No,1395                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),1396                        None,1397                    );1398                    // Destructure like a unit struct.1399                    let unit_struct_pat = hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {1400                        kind: hir::PatExprKind::Path(qpath),1401                        hir_id: self.next_id(),1402                        span: self.lower_span(lhs.span),1403                    }));1404                    return self.pat_without_dbm(lhs.span, unit_struct_pat);1405                }1406            }1407            // Structs.1408            ExprKind::Struct(se) => {1409                let field_pats = self.arena.alloc_from_iter(se.fields.iter().map(|f| {1410                    let pat = self.destructure_assign(&f.expr, eq_sign_span, assignments);1411                    hir::PatField {1412                        hir_id: self.next_id(),1413                        ident: self.lower_ident(f.ident),1414                        pat,1415                        is_shorthand: f.is_shorthand,1416                        span: self.lower_span(f.span),1417                    }1418                }));1419                let qpath = self.lower_qpath(1420                    lhs.id,1421                    &se.qself,1422                    &se.path,1423                    ParamMode::Optional,1424                    AllowReturnTypeNotation::No,1425                    ImplTraitContext::Disallowed(ImplTraitPosition::Path),1426                    None,1427                );1428                let fields_omitted = match &se.rest {1429                    StructRest::Base(e) => {1430                        self.dcx().emit_err(FunctionalRecordUpdateDestructuringAssignment {1431                            span: e.span,1432                        });1433                        Some(self.lower_span(e.span))1434                    }1435                    StructRest::Rest(span) => Some(self.lower_span(*span)),1436                    StructRest::None | StructRest::NoneWithError(_) => None,1437                };1438                let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted);1439                return self.pat_without_dbm(lhs.span, struct_pat);1440            }1441            // Tuples.1442            ExprKind::Tup(elements) => {1443                let (pats, rest) =1444                    self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);1445                let tuple_pat = hir::PatKind::Tuple(pats, hir::DotDotPos::new(rest.map(|r| r.0)));1446                return self.pat_without_dbm(lhs.span, tuple_pat);1447            }1448            ExprKind::Paren(e) => {1449                // We special-case `(..)` for consistency with patterns.1450                if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {1451                    let tuple_pat = hir::PatKind::Tuple(&[], hir::DotDotPos::new(Some(0)));1452                    return self.pat_without_dbm(lhs.span, tuple_pat);1453                } else {1454                    return self.destructure_assign_mut(e, eq_sign_span, assignments);1455                }1456            }1457            _ => {}1458        }1459        // Treat all other cases as normal lvalue.1460        let ident = Ident::new(sym::lhs, self.lower_span(lhs.span));1461        let (pat, binding) = self.pat_ident_mut(lhs.span, ident);1462        let ident = self.expr_ident(lhs.span, ident, binding);1463        let assign =1464            hir::ExprKind::Assign(self.lower_expr(lhs), ident, self.lower_span(eq_sign_span));1465        let expr = self.expr(lhs.span, assign);1466        assignments.push(self.stmt_expr(lhs.span, expr));1467        pat1468    }14691470    /// Destructure a sequence of expressions occurring on the LHS of an assignment.1471    /// Such a sequence occurs in a tuple (struct)/slice.1472    /// Return a sequence of corresponding patterns, and the index and the span of `..` if it1473    /// exists.1474    /// Each sub-assignment is recorded in `assignments`.1475    fn destructure_sequence(1476        &mut self,1477        elements: &[Box<Expr>],1478        ctx: &str,1479        eq_sign_span: Span,1480        assignments: &mut Vec<hir::Stmt<'hir>>,1481    ) -> (&'hir [hir::Pat<'hir>], Option<(usize, Span)>) {1482        let mut rest = None;1483        let elements =1484            self.arena.alloc_from_iter(elements.iter().enumerate().filter_map(|(i, e)| {1485                // Check for `..` pattern.1486                if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {1487                    if let Some((_, prev_span)) = rest {1488                        self.ban_extra_rest_pat(e.span, prev_span, ctx);1489                    } else {1490                        rest = Some((i, e.span));1491                    }1492                    None1493                } else {1494                    Some(self.destructure_assign_mut(e, eq_sign_span, assignments))1495                }1496            }));1497        (elements, rest)1498    }14991500    /// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.1501    fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {1502        let e1 = self.lower_expr_mut(e1);1503        let e2 = self.lower_expr_mut(e2);1504        let fn_path = self.make_lang_item_qpath(hir::LangItem::RangeInclusiveNew, span, None);1505        let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path)));1506        hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])1507    }15081509    fn lower_expr_range(1510        &mut self,1511        span: Span,1512        e1: Option<&Expr>,1513        e2: Option<&Expr>,1514        lims: RangeLimits,1515    ) -> hir::ExprKind<'hir> {1516        use rustc_ast::RangeLimits::*;15171518        let lang_item = match (e1, e2, lims) {1519            (None, None, HalfOpen) => hir::LangItem::RangeFull,1520            (Some(..), None, HalfOpen) => {1521                if self.tcx.features().new_range() {1522                    hir::LangItem::RangeFromCopy1523                } else {1524                    hir::LangItem::RangeFrom1525                }1526            }1527            (None, Some(..), HalfOpen) => hir::LangItem::RangeTo,1528            (Some(..), Some(..), HalfOpen) => {1529                if self.tcx.features().new_range() {1530                    hir::LangItem::RangeCopy1531                } else {1532                    hir::LangItem::Range1533                }1534            }1535            (None, Some(..), Closed) => {1536                if self.tcx.features().new_range() {1537                    hir::LangItem::RangeToInclusiveCopy1538                } else {1539                    hir::LangItem::RangeToInclusive1540                }1541            }1542            (Some(e1), Some(e2), Closed) => {1543                if self.tcx.features().new_range() {1544                    hir::LangItem::RangeInclusiveCopy1545                } else {1546                    return self.lower_expr_range_closed(span, e1, e2);1547                }1548            }1549            (start, None, Closed) => {1550                self.dcx().emit_err(InclusiveRangeWithNoEnd { span });1551                match start {1552                    Some(..) => {1553                        if self.tcx.features().new_range() {1554                            hir::LangItem::RangeFromCopy1555                        } else {1556                            hir::LangItem::RangeFrom1557                        }1558                    }1559                    None => hir::LangItem::RangeFull,1560                }1561            }1562        };15631564        let fields = self.arena.alloc_from_iter(1565            e1.iter()1566                .map(|e| (sym::start, e))1567                .chain(e2.iter().map(|e| {1568                    (1569                        if matches!(1570                            lang_item,1571                            hir::LangItem::RangeInclusiveCopy | hir::LangItem::RangeToInclusiveCopy1572                        ) {1573                            sym::last1574                        } else {1575                            sym::end1576                        },1577                        e,1578                    )1579                }))1580                .map(|(s, e)| {1581                    let span = self.lower_span(e.span);1582                    let span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None);1583                    let expr = self.lower_expr(e);1584                    let ident = Ident::new(s, span);1585                    self.expr_field(ident, expr, span)1586                }),1587        );15881589        hir::ExprKind::Struct(1590            self.arena.alloc(self.make_lang_item_qpath(lang_item, span, None)),1591            fields,1592            hir::StructTailExpr::None,1593        )1594    }15951596    // Record labelled expr's HirId so that we can retrieve it in `lower_jump_destination` without1597    // lowering node id again.1598    fn lower_label(1599        &mut self,1600        opt_label: Option<Label>,1601        dest_id: NodeId,1602        dest_hir_id: hir::HirId,1603    ) -> Option<Label> {1604        let label = opt_label?;1605        self.ident_and_label_to_local_id.insert(dest_id, dest_hir_id.local_id);1606        Some(Label { ident: self.lower_ident(label.ident) })1607    }16081609    fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {1610        let target_id = match destination {1611            Some((id, _)) => {1612                if let Some(loop_id) = self.resolver.get_label_res(id) {1613                    let local_id = self.ident_and_label_to_local_id[&loop_id];1614                    let loop_hir_id = HirId { owner: self.current_hir_id_owner, local_id };1615                    Ok(loop_hir_id)1616                } else {1617                    Err(hir::LoopIdError::UnresolvedLabel)1618                }1619            }1620            None => {1621                self.loop_scope.map(|id| Ok(id)).unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))1622            }1623        };1624        let label = destination1625            .map(|(_, label)| label)1626            .map(|label| Label { ident: self.lower_ident(label.ident) });1627        hir::Destination { label, target_id }1628    }16291630    fn lower_jump_destination(&mut self, id: NodeId, opt_label: Option<Label>) -> hir::Destination {1631        if self.is_in_loop_condition && opt_label.is_none() {1632            hir::Destination {1633                label: None,1634                target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition),1635            }1636        } else {1637            self.lower_loop_destination(opt_label.map(|label| (id, label)))1638        }1639    }16401641    fn with_try_block_scope<T>(1642        &mut self,1643        scope: TryBlockScope,1644        f: impl FnOnce(&mut Self) -> T,1645    ) -> T {1646        let old_scope = mem::replace(&mut self.try_block_scope, scope);1647        let result = f(self);1648        self.try_block_scope = old_scope;1649        result1650    }16511652    fn with_loop_scope<T>(&mut self, loop_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T {1653        // We're no longer in the base loop's condition; we're in another loop.1654        let was_in_loop_condition = self.is_in_loop_condition;1655        self.is_in_loop_condition = false;16561657        let old_scope = self.loop_scope.replace(loop_id);1658        let result = f(self);1659        self.loop_scope = old_scope;16601661        self.is_in_loop_condition = was_in_loop_condition;16621663        result1664    }16651666    fn with_loop_condition_scope<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {1667        let was_in_loop_condition = self.is_in_loop_condition;1668        self.is_in_loop_condition = true;16691670        let result = f(self);16711672        self.is_in_loop_condition = was_in_loop_condition;16731674        result1675    }16761677    fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {1678        let hir_id = self.lower_node_id(f.id);1679        self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField);1680        hir::ExprField {1681            hir_id,1682            ident: self.lower_ident(f.ident),1683            expr: self.lower_expr(&f.expr),1684            span: self.lower_span(f.span),1685            is_shorthand: f.is_shorthand,1686        }1687    }16881689    fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {1690        let yielded =1691            opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));16921693        if !self.tcx.features().yield_expr()1694            && !self.tcx.features().coroutines()1695            && !self.tcx.features().gen_blocks()1696        {1697            rustc_session::errors::feature_err(1698                &self.tcx.sess,1699                sym::yield_expr,1700                span,1701                msg!("yield syntax is experimental"),1702            )1703            .emit();1704        }17051706        let is_async_gen = match self.coroutine_kind {1707            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false,1708            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,1709            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {1710                // Lower to a block `{ EXPR; <error> }` so that the awaited expr1711                // is not accidentally orphaned.1712                let stmt_id = self.next_id();1713                let expr_err = self.expr(1714                    yielded.span,1715                    hir::ExprKind::Err(self.dcx().emit_err(AsyncCoroutinesNotSupported { span })),1716                );1717                return hir::ExprKind::Block(1718                    self.block_all(1719                        yielded.span,1720                        arena_vec![self; hir::Stmt {1721                            hir_id: stmt_id,1722                            kind: hir::StmtKind::Semi(yielded),1723                            span: yielded.span,1724                        }],1725                        Some(self.arena.alloc(expr_err)),1726                    ),1727                    None,1728                );1729            }1730            Some(hir::CoroutineKind::Coroutine(_)) => false,1731            None => {1732                let suggestion = self.current_item.map(|s| s.shrink_to_lo());1733                self.dcx().emit_err(YieldInClosure { span, suggestion });1734                self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable));17351736                false1737            }1738        };17391740        if is_async_gen {1741            // `yield $expr` is transformed into `task_context = yield async_gen_ready($expr)`.1742            // This ensures that we store our resumed `ResumeContext` correctly, and also that1743            // the apparent value of the `yield` expression is `()`.1744            let desugar_span = self.mark_span_with_reason(1745                DesugaringKind::Async,1746                span,1747                Some(Arc::clone(&self.allow_async_gen)),1748            );1749            let wrapped_yielded = self.expr_call_lang_item_fn(1750                desugar_span,1751                hir::LangItem::AsyncGenReady,1752                std::slice::from_ref(yielded),1753            );1754            let yield_expr = self.arena.alloc(1755                self.expr(span, hir::ExprKind::Yield(wrapped_yielded, hir::YieldSource::Yield)),1756            );17571758            let Some(task_context_hid) = self.task_context else {1759                unreachable!("use of `await` outside of an async context.");1760            };1761            let task_context_ident = Ident::with_dummy_span(sym::_task_context);1762            let lhs = self.expr_ident(desugar_span, task_context_ident, task_context_hid);17631764            hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span))1765        } else {1766            hir::ExprKind::Yield(yielded, hir::YieldSource::Yield)1767        }1768    }17691770    /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:1771    /// ```ignore (pseudo-rust)1772    /// {1773    ///     let result = match IntoIterator::into_iter(<head>) {1774    ///         mut iter => {1775    ///             [opt_ident]: loop {1776    ///                 match Iterator::next(&mut iter) {1777    ///                     None => break,1778    ///                     Some(<pat>) => <body>,1779    ///                 };1780    ///             }1781    ///         }1782    ///     };1783    ///     result1784    /// }1785    /// ```1786    fn lower_expr_for(1787        &mut self,1788        e: &Expr,1789        pat: &Pat,1790        head: &Expr,1791        body: &Block,1792        opt_label: Option<Label>,1793        loop_kind: ForLoopKind,1794    ) -> hir::Expr<'hir> {1795        let head = self.lower_expr_mut(head);1796        let pat = self.lower_pat(pat);1797        let for_span =1798            self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None);1799        let for_ctxt = for_span.ctxt();18001801        // Try to point both the head and pat spans to their position in the for loop1802        // rather than inside a macro.1803        let head_span =1804            head.span.find_ancestor_in_same_ctxt(e.span).unwrap_or(head.span).with_ctxt(for_ctxt);1805        let pat_span =1806            pat.span.find_ancestor_in_same_ctxt(e.span).unwrap_or(pat.span).with_ctxt(for_ctxt);18071808        let loop_hir_id = self.lower_node_id(e.id);1809        let label = self.lower_label(opt_label, e.id, loop_hir_id);18101811        // `None => break`1812        let none_arm = {1813            let break_expr =1814                self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span));1815            let pat = self.pat_none(for_span);1816            self.arm(pat, break_expr, for_span)1817        };18181819        // Some(<pat>) => <body>,1820        let some_arm = {1821            let some_pat = self.pat_some(pat_span, pat);1822            let body_block =1823                self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false));1824            let body_expr = self.arena.alloc(self.expr_block(body_block));1825            self.arm(some_pat, body_expr, for_span)1826        };18271828        // `mut iter`1829        let iter = Ident::with_dummy_span(sym::iter);1830        let (iter_pat, iter_pat_nid) =1831            self.pat_ident_binding_mode(head_span, iter, hir::BindingMode::MUT);18321833        let match_expr = {1834            let iter = self.expr_ident(head_span, iter, iter_pat_nid);1835            let next_expr = match loop_kind {1836                ForLoopKind::For => {1837                    // `Iterator::next(&mut iter)`1838                    let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);1839                    self.expr_call_lang_item_fn(1840                        head_span,1841                        hir::LangItem::IteratorNext,1842                        arena_vec![self; ref_mut_iter],1843                    )1844                }1845                ForLoopKind::ForAwait => {1846                    // we'll generate `unsafe { Pin::new_unchecked(&mut iter) })` and then pass this1847                    // to make_lowered_await with `FutureKind::AsyncIterator` which will generator1848                    // calls to `poll_next`. In user code, this would probably be a call to1849                    // `Pin::as_mut` but here it's easy enough to do `new_unchecked`.18501851                    // `&mut iter`1852                    let iter = self.expr_mut_addr_of(head_span, iter);1853                    // `Pin::new_unchecked(...)`1854                    let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(1855                        head_span,1856                        hir::LangItem::PinNewUnchecked,1857                        arena_vec![self; iter],1858                    ));1859                    // `unsafe { ... }`1860                    let iter = self.arena.alloc(self.expr_unsafe(head_span, iter));1861                    let kind = self.make_lowered_await(head_span, iter, FutureKind::AsyncIterator);1862                    self.arena.alloc(hir::Expr { hir_id: self.next_id(), kind, span: head_span })1863                }1864            };1865            let arms = arena_vec![self; none_arm, some_arm];18661867            // `match $next_expr { ... }`1868            self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)1869        };1870        let match_stmt = self.stmt_expr(for_span, match_expr);18711872        let loop_block = self.block_all(for_span, arena_vec![self; match_stmt], None);18731874        // `[opt_ident]: loop { ... }`1875        let kind = hir::ExprKind::Loop(1876            loop_block,1877            label,1878            hir::LoopSource::ForLoop,1879            self.lower_span(for_span.with_hi(head.span.hi())),1880        );1881        let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span });18821883        // `mut iter => { ... }`1884        let iter_arm = self.arm(iter_pat, loop_expr, for_span);18851886        let match_expr = match loop_kind {1887            ForLoopKind::For => {1888                // `::std::iter::IntoIterator::into_iter(<head>)`1889                let into_iter_expr = self.expr_call_lang_item_fn(1890                    head_span,1891                    hir::LangItem::IntoIterIntoIter,1892                    arena_vec![self; head],1893                );18941895                self.arena.alloc(self.expr_match(1896                    for_span,1897                    into_iter_expr,1898                    arena_vec![self; iter_arm],1899                    hir::MatchSource::ForLoopDesugar,1900                ))1901            }1902            // `match into_async_iter(<head>) { ref mut iter => match unsafe { Pin::new_unchecked(iter) } { ... } }`1903            ForLoopKind::ForAwait => {1904                let iter_ident = iter;1905                let (async_iter_pat, async_iter_pat_id) =1906                    self.pat_ident_binding_mode(head_span, iter_ident, hir::BindingMode::REF_MUT);1907                let iter = self.expr_ident_mut(head_span, iter_ident, async_iter_pat_id);1908                // `Pin::new_unchecked(...)`1909                let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(1910                    head_span,1911                    hir::LangItem::PinNewUnchecked,1912                    arena_vec![self; iter],1913                ));1914                // `unsafe { ... }`1915                let iter = self.arena.alloc(self.expr_unsafe(head_span, iter));1916                let inner_match_expr = self.arena.alloc(self.expr_match(1917                    for_span,1918                    iter,1919                    arena_vec![self; iter_arm],1920                    hir::MatchSource::ForLoopDesugar,1921                ));19221923                // `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)`1924                let iter = self.expr_call_lang_item_fn(1925                    head_span,1926                    hir::LangItem::IntoAsyncIterIntoIter,1927                    arena_vec![self; head],1928                );1929                let iter_arm = self.arm(async_iter_pat, inner_match_expr, for_span);1930                self.arena.alloc(self.expr_match(1931                    for_span,1932                    iter,1933                    arena_vec![self; iter_arm],1934                    hir::MatchSource::ForLoopDesugar,1935                ))1936            }1937        };19381939        // This is effectively `{ let _result = ...; _result }`.1940        // The construct was introduced in #21984 and is necessary to make sure that1941        // temporaries in the `head` expression are dropped and do not leak to the1942        // surrounding scope of the `match` since the `match` is not a terminating scope.1943        //1944        // Also, add the attributes to the outer returned expr node.1945        let expr = self.expr_drop_temps_mut(for_span, match_expr);1946        self.lower_attrs(expr.hir_id, &e.attrs, e.span, Target::from_expr(e));1947        expr1948    }19491950    /// Desugar `ExprKind::Try` from: `<expr>?` into:1951    /// ```ignore (pseudo-rust)1952    /// match Try::branch(<expr>) {1953    ///     ControlFlow::Continue(val) => #[allow(unreachable_code)] val,,1954    ///     ControlFlow::Break(residual) =>1955    ///         #[allow(unreachable_code)]1956    ///         // If there is an enclosing `try {...}`:1957    ///         break 'catch_target Residual::into_try_type(residual),1958    ///         // Otherwise:1959    ///         return Try::from_residual(residual),1960    /// }1961    /// ```1962    fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> {1963        let unstable_span = self.mark_span_with_reason(1964            DesugaringKind::QuestionMark,1965            span,1966            Some(Arc::clone(&self.allow_try_trait)),1967        );1968        let try_span = self.tcx.sess.source_map().end_point(span);1969        let try_span = self.mark_span_with_reason(1970            DesugaringKind::QuestionMark,1971            try_span,1972            Some(Arc::clone(&self.allow_try_trait)),1973        );19741975        // `Try::branch(<expr>)`1976        let scrutinee = {1977            // expand <expr>1978            let sub_expr = self.lower_expr_mut(sub_expr);19791980            self.expr_call_lang_item_fn(1981                unstable_span,1982                hir::LangItem::TryTraitBranch,1983                arena_vec![self; sub_expr],1984            )1985        };19861987        let attrs: AttrVec = thin_vec![self.unreachable_code_attr(try_span)];19881989        // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`1990        let continue_arm = {1991            let val_ident = Ident::with_dummy_span(sym::val);1992            let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);1993            let val_expr = self.expr_ident(span, val_ident, val_pat_nid);1994            self.lower_attrs(val_expr.hir_id, &attrs, span, Target::Expression);1995            let continue_pat = self.pat_cf_continue(unstable_span, val_pat);1996            self.arm(continue_pat, val_expr, try_span)1997        };19981999        // `ControlFlow::Break(residual) =>2000        //     #[allow(unreachable_code)]

Code quality findings 35

Critical: Use of 'unsafe' keyword bypasses Rust's safety guarantees. Requires careful auditing, clear justification (FFI, specific optimizations), and minimal scope.
error safety unsafe-block
/// match unsafe { ::std::future::Future::poll(
Critical: Use of 'unsafe' keyword bypasses Rust's safety guarantees. Requires careful auditing, clear justification (FFI, specific optimizations), and minimal scope.
error safety unsafe-block
// unsafe {
Critical: Use of 'unsafe' keyword bypasses Rust's safety guarantees. Requires careful auditing, clear justification (FFI, specific optimizations), and minimal scope.
error safety unsafe-block
// we'll generate `unsafe { Pin::new_unchecked(&mut iter) })` and then pass this
Critical: Use of 'unsafe' keyword bypasses Rust's safety guarantees. Requires careful auditing, clear justification (FFI, specific optimizations), and minimal scope.
error safety unsafe-block
// `unsafe { ... }`
Critical: Use of 'unsafe' keyword bypasses Rust's safety guarantees. Requires careful auditing, clear justification (FFI, specific optimizations), and minimal scope.
error safety unsafe-block
// `match into_async_iter(<head>) { ref mut iter => match unsafe { Pin::new_unchecked(iter) } { ... } }`
Critical: Use of 'unsafe' keyword bypasses Rust's safety guarantees. Requires careful auditing, clear justification (FFI, specific optimizations), and minimal scope.
error safety unsafe-block
// `unsafe { ... }`
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
fn lower_exprs(&mut self, exprs: &[Box<Expr>]) -> &'hir [hir::Expr<'hir>] {
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
call_args: args[0].span.to(args.last().unwrap().span),
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
call_args: args[0].span.to(args.last().unwrap().span),
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
error.unwrap()
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
let last_segment = path.segments.last_mut().unwrap();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
) -> (hir::ClosureBinder, &'c [GenericParam]) {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]),
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
) -> (&'hir [hir::Pat<'hir>], Option<(usize, Span)>) {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let local_id = self.ident_and_label_to_local_id[&loop_id];
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
arms: &'hir [hir::Arm<'hir>],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
args: &'hir [hir::Expr<'hir>],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
fields: &'hir [hir::ExprField<'hir>],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
fields: &'hir [hir::Expr<'hir>],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
fields: &'hir [hir::Expr<'hir>],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
args: &'hir [hir::Expr<'hir>],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
args: &'hir [hir::Expr<'hir>],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
args: &'hir [hir::Expr<'hir>],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
/// Used by [`LoweringContext::make_lowered_await`] to customize the desugaring based on what kind
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use rustc_ast::*;
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match ex.kind {
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
const_args.push(format!("{{ {} }}", expr_to_string(arg)));
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
other_args.push(expr_to_string(arg));
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match e.kind {
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use rustc_ast::RangeLimits::*;
Info: Usage of `#[allow(...)]` suppresses compiler lints. Ensure the allowance is justified, well-scoped, and ideally temporary. Overuse can hide potential issues.
info maintainability allow-lint
/// ControlFlow::Continue(val) => #[allow(unreachable_code)] val,,
Info: Usage of `#[allow(...)]` suppresses compiler lints. Ensure the allowance is justified, well-scoped, and ideally temporary. Overuse can hide potential issues.
info maintainability allow-lint
/// #[allow(unreachable_code)]
Info: Usage of `#[allow(...)]` suppresses compiler lints. Ensure the allowance is justified, well-scoped, and ideally temporary. Overuse can hide potential issues.
info maintainability allow-lint
// `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
Info: Usage of `#[allow(...)]` suppresses compiler lints. Ensure the allowance is justified, well-scoped, and ideally temporary. Overuse can hide potential issues.
info maintainability allow-lint
// #[allow(unreachable_code)]
Info: Usage of `#[allow(...)]` suppresses compiler lints. Ensure the allowance is justified, well-scoped, and ideally temporary. Overuse can hide potential issues.
info maintainability allow-lint
/// `#[allow(unreachable_code)]`

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.