compiler/rustc_ast_lowering/src/expr.rs RUST 2,322 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,322.
1use std::mem;2use std::ops::ControlFlow;3use std::sync::Arc;45use rustc_ast::node_id::NodeMap;6use rustc_ast::*;7use rustc_errors::msg;8use rustc_hir as hir;9use rustc_hir::attrs::lang_items::LangItem;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::diagnostics::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};1819mod closure;2021use crate::diagnostics::{22    AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks,23    FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd,24    InvalidLegacyConstGenericArg, MatchArmWithNoBody, MoveExprOnlyInPlainClosures,25    NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign, UseConstGenericArg,26    YieldInClosure,27};28use crate::{29    AllowReturnTypeNotation, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext,30    ParamMode, ResolverAstLoweringExt, TryBlockScope,31};3233pub(super) struct WillCreateDefIdsVisitor;3435/// A `move(...)` expression found while looking up generated initializers.36struct MoveExprInitializer<'a> {37    /// The `NodeId` of the outer `move(...)` expression.38    id: NodeId,39    /// Span of the `move` token, used for the generated binding name.40    move_kw_span: Span,41    /// The expression inside `move(...)`; e.g. `foo.bar` in `move(foo.bar)`.42    expr: &'a Expr,43}4445/// State for `move(...)` expressions found while lowering one plain closure body.46pub(super) struct MoveExprState<'hir> {47    pub(super) bindings: NodeMap<(Ident, HirId)>,48    pub(super) occurrences: Vec<MoveExprOccurrence<'hir>>,49}5051impl<'hir> Default for MoveExprState<'hir> {52    fn default() -> Self {53        Self { bindings: NodeMap::default(), occurrences: Vec::new() }54    }55}5657pub(super) struct MoveExprOccurrence<'hir> {58    id: NodeId,59    ident: Ident,60    pat: &'hir hir::Pat<'hir>,61    binding: HirId,62    explicit_capture: bool,63}6465/// Looks up the initializer expression for each `move(...)` occurrence.66struct MoveExprInitializerFinder<'a> {67    initializers: Vec<MoveExprInitializer<'a>>,68}6970impl<'a> MoveExprInitializerFinder<'a> {71    fn collect(expr: &'a Expr) -> Vec<MoveExprInitializer<'a>> {72        let mut this = Self { initializers: Vec::new() };73        this.visit_expr(expr);74        this.initializers75    }76}7778impl<'a> Visitor<'a> for MoveExprInitializerFinder<'a> {79    fn visit_expr(&mut self, expr: &'a Expr) {80        match &expr.kind {81            ExprKind::Move(inner, move_kw_span) => {82                self.visit_expr(inner);83                self.initializers.push(MoveExprInitializer {84                    id: expr.id,85                    move_kw_span: *move_kw_span,86                    expr: inner,87                });88            }89            ExprKind::Closure(..) | ExprKind::Gen(..) | ExprKind::ConstBlock(..) => {}90            _ => walk_expr(self, expr),91        }92    }9394    fn visit_item(&mut self, _: &'a Item) {}95}9697impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor {98    type Result = ControlFlow<Span>;99100    fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {101        ControlFlow::Break(c.value.span)102    }103104    fn visit_item(&mut self, item: &'v Item) -> Self::Result {105        ControlFlow::Break(item.span)106    }107108    fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result {109        match ex.kind {110            ExprKind::Gen(..) | ExprKind::ConstBlock(..) | ExprKind::Closure(..) => {111                ControlFlow::Break(ex.span)112            }113            _ => walk_expr(self, ex),114        }115    }116}117118impl<'hir> LoweringContext<'_, 'hir> {119    fn with_move_expr_bindings<T>(120        &mut self,121        state: Option<MoveExprState<'hir>>,122        f: impl FnOnce(&mut Self) -> T,123    ) -> (T, Option<MoveExprState<'hir>>) {124        self.move_expr_bindings.push(state);125        let result = f(self);126        let state = self.move_expr_bindings.pop().unwrap_or_else(|| {127            span_bug!(DUMMY_SP, "`move_expr_bindings` stack was empty after lowering")128        });129        (result, state)130    }131132    fn record_move_expr(133        &mut self,134        id: NodeId,135        inner: &Expr,136        move_kw_span: Span,137        explicit_capture: bool,138    ) -> (Ident, HirId) {139        let index = self140            .move_expr_bindings141            .last()142            .and_then(|state| state.as_ref())143            .map_or(0, |state| state.occurrences.len());144        let ident = Ident::from_str_and_span(&format!("__move_expr_{index}"), move_kw_span);145        let (pat, binding) = self.pat_ident(inner.span, ident);146        let Some(state) = self.move_expr_bindings.last_mut().and_then(|state| state.as_mut())147        else {148            span_bug!(move_kw_span, "`move(...)` lowered without a plain closure body state");149        };150        state.bindings.insert(id, (ident, binding));151        state.occurrences.push(MoveExprOccurrence { id, ident, pat, binding, explicit_capture });152        (ident, binding)153    }154155    fn lower_exprs(&mut self, exprs: &[Box<Expr>]) -> &'hir [hir::Expr<'hir>] {156        self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))157    }158159    pub(super) fn lower_expr(&mut self, e: &Expr) -> &'hir hir::Expr<'hir> {160        self.arena.alloc(self.lower_expr_mut(e))161    }162163    pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {164        let mut span = self.lower_span(e.span);165        match &e.kind {166            // Parenthesis expression does not have a HirId and is handled specially.167            ExprKind::Paren(ex) => {168                let mut ex = self.lower_expr_mut(ex);169                // Include parens in span, but only if it is a super-span.170                if e.span.contains(ex.span) {171                    ex.span = self.lower_span(e.span.with_ctxt(ex.span.ctxt()));172                }173                // Merge attributes into the inner expression.174                if !e.attrs.is_empty() {175                    let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]);176                    let new_attrs = self177                        .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e))178                        .into_iter()179                        .chain(old_attrs.iter().cloned());180                    let new_attrs = &*self.arena.alloc_from_iter(new_attrs);181                    if new_attrs.is_empty() {182                        return ex;183                    }184                    self.attrs.insert(ex.hir_id.local_id, new_attrs);185                }186                return ex;187            }188            // Desugar `ExprForLoop`189            // from: `[opt_ident]: for await? <pat> in <iter> <body>`190            //191            // This also needs special handling because the HirId of the returned `hir::Expr` will not192            // correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.193            ExprKind::ForLoop(ForLoop { pat, iter, body, label, kind }) => {194                return self.lower_expr_for(e, pat, iter, body, *label, *kind);195            }196            ExprKind::Closure(closure) => return self.lower_expr_closure_expr(e, closure),197            _ => (),198        }199200        let expr_hir_id = self.lower_node_id(e.id);201        self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e));202203        let kind = match &e.kind {204            ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),205            ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)),206            ExprKind::Repeat(expr, count) => {207                let expr = self.lower_expr(expr);208                let count = self.lower_array_length_to_const_arg(count);209                hir::ExprKind::Repeat(expr, count)210            }211            ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),212            ExprKind::Call(f, args) => {213                if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f, self.tcx) {214                    self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)215                } else {216                    let f = self.lower_expr(f);217                    hir::ExprKind::Call(f, self.lower_exprs(args))218                }219            }220            ExprKind::MethodCall(MethodCall { seg, receiver, args, span }) => {221                let hir_seg = self.arena.alloc(self.lower_path_segment(222                    e.span,223                    seg,224                    ParamMode::Optional,225                    GenericArgsMode::Err,226                    ImplTraitContext::Disallowed(ImplTraitPosition::Path),227                    // Method calls can't have bound modifiers228                    None,229                ));230                let receiver = self.lower_expr(receiver);231                let args = self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x)));232                hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(*span))233            }234            ExprKind::Binary(binop, lhs, rhs) => {235                let binop = self.lower_binop(*binop);236                let lhs = self.lower_expr(lhs);237                let rhs = self.lower_expr(rhs);238                hir::ExprKind::Binary(binop, lhs, rhs)239            }240            ExprKind::Unary(op, ohs) => {241                let op = self.lower_unop(*op);242                let ohs = self.lower_expr(ohs);243                hir::ExprKind::Unary(op, ohs)244            }245            ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)),246            ExprKind::IncludedBytes(byte_sym) => {247                let lit =248                    respan(self.lower_span(e.span), LitKind::ByteStr(*byte_sym, StrStyle::Cooked));249                hir::ExprKind::Lit(lit)250            }251            ExprKind::Cast(expr, ty) => {252                let expr = self.lower_expr(expr);253                let ty =254                    self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));255                hir::ExprKind::Cast(expr, ty)256            }257            ExprKind::Type(expr, ty) => {258                let expr = self.lower_expr(expr);259                let ty =260                    self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));261                hir::ExprKind::Type(expr, ty)262            }263            ExprKind::AddrOf(k, m, ohs) => {264                let ohs = self.lower_expr(ohs);265                hir::ExprKind::AddrOf(*k, *m, ohs)266            }267            ExprKind::Let(pat, scrutinee, span, recovered) => {268                hir::ExprKind::Let(self.arena.alloc(hir::LetExpr {269                    span: self.lower_span(*span),270                    pat: self.lower_pat(pat),271                    ty: None,272                    init: self.lower_expr(scrutinee),273                    recovered: *recovered,274                }))275            }276            ExprKind::If(cond, then, else_opt) => {277                self.lower_expr_if(cond, then, else_opt.as_deref())278            }279            ExprKind::While(cond, body, opt_label) => self.with_loop_scope(expr_hir_id, |this| {280                let span = this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None);281                let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id);282                this.lower_expr_while_in_loop_scope(span, cond, body, opt_label)283            }),284            ExprKind::Loop(body, opt_label, span) => self.with_loop_scope(expr_hir_id, |this| {285                let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id);286                hir::ExprKind::Loop(287                    this.lower_block(body, false),288                    opt_label,289                    hir::LoopSource::Loop,290                    this.lower_span(*span),291                )292            }),293            ExprKind::TryBlock(body, opt_ty) => self.lower_expr_try_block(body, opt_ty.as_deref()),294            ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match(295                self.lower_expr(expr),296                self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),297                match kind {298                    MatchKind::Prefix => hir::MatchSource::Normal,299                    MatchKind::Postfix => hir::MatchSource::Postfix,300                },301            ),302            ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),303            ExprKind::Move(inner, move_kw_span) => {304                if !self.tcx.features().move_expr() {305                    return self.expr_err(*move_kw_span, self.dcx().has_errors().unwrap());306                }307                if let Some(state) = self.move_expr_bindings.last().and_then(Option::as_ref) {308                    let existing = state.bindings.get(&e.id).copied();309                    let (ident, binding) = existing.unwrap_or_else(|| {310                        for nested in MoveExprInitializerFinder::collect(inner) {311                            self.record_move_expr(312                                nested.id,313                                nested.expr,314                                nested.move_kw_span,315                                false,316                            );317                        }318                        self.record_move_expr(e.id, inner, *move_kw_span, true)319                    });320                    hir::ExprKind::Path(hir::QPath::Resolved(321                        None,322                        self.arena.alloc(hir::Path {323                            span: self.lower_span(e.span),324                            res: Res::Local(binding),325                            segments: arena_vec![326                                self;327                                hir::PathSegment::new(328                                    self.lower_ident(ident),329                                    self.next_id(),330                                    Res::Local(binding),331                                )332                            ],333                        }),334                    ))335                } else {336                    let guar =337                        self.dcx().emit_err(MoveExprOnlyInPlainClosures { span: *move_kw_span });338                    hir::ExprKind::Err(guar)339                }340            }341            ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr),342            ExprKind::Gen(capture_clause, block, coroutine_kind, decl_span) => {343                let desugaring_kind = match coroutine_kind {344                    CoroutineKind::Async => hir::CoroutineDesugaring::Async,345                    CoroutineKind::Gen => hir::CoroutineDesugaring::Gen,346                    CoroutineKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen,347                };348                self.make_desugared_coroutine_expr(349                    *capture_clause,350                    e.id,351                    None,352                    *decl_span,353                    e.span,354                    desugaring_kind,355                    hir::CoroutineSource::Block,356                    |this| {357                        this.with_new_scopes(e.span, |this| {358                            let (expr, _) = this359                                .with_move_expr_bindings(None, |this| this.lower_block_expr(block));360                            expr361                        })362                    },363                )364            }365            ExprKind::Block(blk, opt_label) => {366                // Different from loops, label of block resolves to block id rather than367                // expr node id.368                let block_hir_id = self.lower_node_id(blk.id);369                let opt_label = self.lower_label(*opt_label, blk.id, block_hir_id);370                let hir_block = self.arena.alloc(self.lower_block_noalloc(371                    block_hir_id,372                    blk,373                    opt_label.is_some(),374                ));375                hir::ExprKind::Block(hir_block, opt_label)376            }377            ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span),378            ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp(379                self.lower_assign_op(*op),380                self.lower_expr(el),381                self.lower_expr(er),382            ),383            ExprKind::Field(el, ident) => {384                hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident))385            }386            ExprKind::Index(el, er, brackets_span) => hir::ExprKind::Index(387                self.lower_expr(el),388                self.lower_expr(er),389                self.lower_span(*brackets_span),390            ),391            ExprKind::Range(e1, e2, lims) => {392                span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None);393                self.lower_expr_range(span, e1.as_deref(), e2.as_deref(), *lims)394            }395            ExprKind::Underscore => {396                let guar = self.dcx().emit_err(UnderscoreExprLhsAssign { span: e.span });397                hir::ExprKind::Err(guar)398            }399            ExprKind::Path(qself, path) => {400                let qpath = self.lower_qpath(401                    e.id,402                    qself,403                    path,404                    ParamMode::Optional,405                    AllowReturnTypeNotation::No,406                    ImplTraitContext::Disallowed(ImplTraitPosition::Path),407                    None,408                );409                hir::ExprKind::Path(qpath)410            }411            ExprKind::Break(opt_label, opt_expr) => {412                let opt_expr = opt_expr.as_ref().map(|x| self.lower_expr(x));413                hir::ExprKind::Break(self.lower_jump_destination(e.id, *opt_label), opt_expr)414            }415            ExprKind::Continue(opt_label) => {416                hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label))417            }418            ExprKind::Ret(e) => {419                let expr = e.as_ref().map(|x| self.lower_expr(x));420                self.checked_return(expr)421            }422            ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),423            ExprKind::Become(sub_expr) => {424                let sub_expr = self.lower_expr(sub_expr);425                hir::ExprKind::Become(sub_expr)426            }427            ExprKind::InlineAsm(asm) => {428                hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))429            }430            ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),431            ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(432                self.lower_ty_alloc(433                    container,434                    ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),435                ),436                self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))),437            ),438            ExprKind::Struct(se) => {439                let rest = match se.rest {440                    StructRest::Base(ref e) => hir::StructTailExpr::Base(self.lower_expr(e)),441                    StructRest::Rest(sp) => hir::StructTailExpr::DefaultFields(self.lower_span(sp)),442                    StructRest::None => hir::StructTailExpr::None,443                    StructRest::NoneWithError(guar) => hir::StructTailExpr::NoneWithError(guar),444                };445                hir::ExprKind::Struct(446                    self.arena.alloc(self.lower_qpath(447                        e.id,448                        &se.qself,449                        &se.path,450                        ParamMode::Optional,451                        AllowReturnTypeNotation::No,452                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),453                        None,454                    )),455                    self.arena.alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),456                    rest,457                )458            }459            ExprKind::Yield(kind) => self.lower_expr_yield(e.span, kind.expr().map(|x| &**x)),460            ExprKind::Err(guar) => hir::ExprKind::Err(*guar),461462            ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(463                *kind,464                self.lower_expr(expr),465                ty.as_ref().map(|ty| {466                    self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))467                }),468            ),469470            ExprKind::Dummy => {471                span_bug!(e.span, "lowered ExprKind::Dummy")472            }473474            ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),475476            ExprKind::Paren(_) | ExprKind::ForLoop { .. } | ExprKind::Closure(..) => {477                unreachable!("already handled")478            }479480            ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),481482            ExprKind::DirectConstArg(expr) => {483                let e = self.emit_bad_direct_const_arg(e.span, expr, "expression");484                hir::ExprKind::Err(e)485            }486        };487488        hir::Expr { hir_id: expr_hir_id, kind, span }489    }490491    pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {492        self.with_new_scopes(c.value.span, |this| {493            let def_id = this.local_def_id(c.id);494            let hir_id = this.lower_node_id(c.id);495            let (body, _) = this.with_move_expr_bindings(None, |this| {496                this.lower_const_body(c.value.span, Some(&c.value))497            });498            hir::ConstBlock { def_id, hir_id, body }499        })500    }501502    pub(crate) fn lower_lit(&mut self, token_lit: &token::Lit, span: Span) -> hir::Lit {503        let lit_kind = match LitKind::from_token_lit(*token_lit) {504            Ok(lit_kind) => lit_kind,505            Err(err) => {506                let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span);507                LitKind::Err(guar)508            }509        };510        respan(self.lower_span(span), lit_kind)511    }512513    fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {514        match u {515            UnOp::Deref => hir::UnOp::Deref,516            UnOp::Not => hir::UnOp::Not,517            UnOp::Neg => hir::UnOp::Neg,518        }519    }520521    fn lower_binop(&mut self, b: BinOp) -> BinOp {522        Spanned { node: b.node, span: self.lower_span(b.span) }523    }524525    fn lower_assign_op(&mut self, a: AssignOp) -> AssignOp {526        Spanned { node: a.node, span: self.lower_span(a.span) }527    }528529    fn lower_legacy_const_generics(530        &mut self,531        mut f: Expr,532        args: ThinVec<Box<Expr>>,533        legacy_args_idx: &[usize],534    ) -> hir::ExprKind<'hir> {535        let ExprKind::Path(None, path) = &mut f.kind else {536            unreachable!();537        };538539        let mut error = None;540        let mut invalid_expr_error = |tcx: TyCtxt<'_>, span| {541            // Avoid emitting the error multiple times.542            if error.is_none() {543                let sm = tcx.sess.source_map();544                let mut const_args = vec![];545                let mut other_args = vec![];546                for (idx, arg) in args.iter().enumerate() {547                    if let Ok(arg) = sm.span_to_snippet(arg.span) {548                        if legacy_args_idx.contains(&idx) {549                            const_args.push(format!("{{ {} }}", arg));550                        } else {551                            other_args.push(arg);552                        }553                    }554                }555                let suggestion = UseConstGenericArg {556                    end_of_fn: f.span.shrink_to_hi(),557                    const_args: const_args.join(", "),558                    other_args: other_args.join(", "),559                    call_args: args[0].span.to(args.last().unwrap().span),560                };561                error = Some(tcx.dcx().emit_err(InvalidLegacyConstGenericArg { span, suggestion }));562            }563            error.unwrap()564        };565566        // Split the arguments into const generics and normal arguments567        let mut real_args = vec![];568        let mut generic_args = ThinVec::new();569        for (idx, arg) in args.iter().cloned().enumerate() {570            if legacy_args_idx.contains(&idx) {571                let node_id = self.next_node_id();572                self.create_def(node_id, None, DefKind::AnonConst, arg.span);573                let const_value =574                    if let ControlFlow::Break(span) = WillCreateDefIdsVisitor.visit_expr(&arg) {575                        Box::new(Expr {576                            id: self.next_node_id(),577                            kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),578                            span: f.span,579                            attrs: [].into(),580                            tokens: None,581                        })582                    } else {583                        arg584                    };585586                let anon_const = AnonConst { id: node_id, value: const_value };587                generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));588            } else {589                real_args.push(arg);590            }591        }592593        // Add generic args to the last element of the path.594        let last_segment = path.segments.last_mut().unwrap();595        assert!(last_segment.args.is_none());596        last_segment.args = Some(Box::new(GenericArgs::AngleBracketed(AngleBracketedArgs {597            span: DUMMY_SP,598            args: generic_args,599        })));600601        // Now lower everything as normal.602        let f = self.lower_expr(&f);603        hir::ExprKind::Call(f, self.lower_exprs(&real_args))604    }605606    fn lower_expr_if(607        &mut self,608        cond: &Expr,609        then: &Block,610        else_opt: Option<&Expr>,611    ) -> hir::ExprKind<'hir> {612        let lowered_cond = self.lower_expr(cond);613        let then_expr = self.lower_block_expr(then);614        if let Some(rslt) = else_opt {615            hir::ExprKind::If(616                lowered_cond,617                self.arena.alloc(then_expr),618                Some(self.lower_expr(rslt)),619            )620        } else {621            hir::ExprKind::If(lowered_cond, self.arena.alloc(then_expr), None)622        }623    }624625    // We desugar: `'label: while $cond $body` into:626    //627    // ```628    // 'label: loop {629    //   if { let _t = $cond; _t } {630    //     $body631    //   }632    //   else {633    //     break;634    //   }635    // }636    // ```637    //638    // Wrap in a construct equivalent to `{ let _t = $cond; _t }`639    // to preserve drop semantics since `while $cond { ... }` does not640    // let temporaries live outside of `cond`.641    fn lower_expr_while_in_loop_scope(642        &mut self,643        span: Span,644        cond: &Expr,645        body: &Block,646        opt_label: Option<Label>,647    ) -> hir::ExprKind<'hir> {648        let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond));649        let then = self.lower_block_expr(body);650        let expr_break = self.expr_break(span);651        let stmt_break = self.stmt_expr(span, expr_break);652        let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);653        let else_expr = self.arena.alloc(self.expr_block(else_blk));654        let if_kind = hir::ExprKind::If(lowered_cond, self.arena.alloc(then), Some(else_expr));655        let if_expr = self.expr(span, if_kind);656        let block = self.block_expr(self.arena.alloc(if_expr));657        let span = self.lower_span(span.with_hi(cond.span.hi()));658        hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span)659    }660661    /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,662    /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }`663    /// and save the block id to use it as a break target for desugaring of the `?` operator.664    fn lower_expr_try_block(&mut self, body: &Block, opt_ty: Option<&Ty>) -> hir::ExprKind<'hir> {665        let body_hir_id = self.lower_node_id(body.id);666        let new_scope = if opt_ty.is_some() {667            TryBlockScope::Heterogeneous(body_hir_id)668        } else {669            TryBlockScope::Homogeneous(body_hir_id)670        };671        let whole_block = self.with_try_block_scope(new_scope, |this| {672            let mut block = this.lower_block_noalloc(body_hir_id, body, true);673674            // Final expression of the block (if present) or `()` with span at the end of block675            let (try_span, tail_expr) = if let Some(expr) = block.expr.take() {676                (677                    this.mark_span_with_reason(678                        DesugaringKind::TryBlock,679                        expr.span,680                        Some(Arc::clone(&this.allow_try_trait)),681                    ),682                    expr,683                )684            } else {685                let try_span = this.mark_span_with_reason(686                    DesugaringKind::TryBlock,687                    this.tcx.sess.source_map().end_point(body.span),688                    Some(Arc::clone(&this.allow_try_trait)),689                );690691                (try_span, this.expr_unit(try_span))692            };693694            let ok_wrapped_span =695                this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);696697            // `::std::ops::Try::from_output($tail_expr)`698            block.expr = Some(this.wrap_in_try_constructor(699                LangItem::TryTraitFromOutput,700                try_span,701                tail_expr,702                ok_wrapped_span,703            ));704705            this.arena.alloc(block)706        });707708        if let Some(ty) = opt_ty {709            let ty = self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path));710            let block_expr = self.arena.alloc(self.expr_block(whole_block));711            hir::ExprKind::Type(block_expr, ty)712        } else {713            hir::ExprKind::Block(whole_block, None)714        }715    }716717    fn wrap_in_try_constructor(718        &mut self,719        lang_item: LangItem,720        method_span: Span,721        expr: &'hir hir::Expr<'hir>,722        overall_span: Span,723    ) -> &'hir hir::Expr<'hir> {724        let constructor = self.arena.alloc(self.expr_lang_item_path(method_span, lang_item));725        self.expr_call(overall_span, constructor, std::slice::from_ref(expr))726    }727728    fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {729        let pat = self.lower_pat(&arm.pat);730        let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond));731        let hir_id = self.next_id();732        let span = self.lower_span(arm.span);733        self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm);734        let is_never_pattern = pat.is_never_pattern();735        // We need to lower the body even if it's unneeded for never pattern in match,736        // ensure that we can get HirId for DefId if need (issue #137708).737        let body = arm.body.as_ref().map(|x| self.lower_expr(x));738        let body = if let Some(body) = body739            && !is_never_pattern740        {741            body742        } else {743            // Either `body.is_none()` or `is_never_pattern` here.744            if !is_never_pattern {745                if self.tcx.features().never_patterns() {746                    // If the feature is off we already emitted the error after parsing.747                    let suggestion = span.shrink_to_hi();748                    self.dcx().emit_err(MatchArmWithNoBody { span, suggestion });749                }750            } else if let Some(body) = &arm.body {751                self.dcx().emit_err(NeverPatternWithBody { span: body.span });752            } else if let Some(g) = &arm.guard {753                self.dcx().emit_err(NeverPatternWithGuard { span: g.span() });754            }755756            // We add a fake `loop {}` arm body so that it typecks to `!`. The mir lowering of never757            // patterns ensures this loop is not reachable.758            let block = self.arena.alloc(hir::Block {759                stmts: &[],760                expr: None,761                hir_id: self.next_id(),762                rules: hir::BlockCheckMode::DefaultBlock,763                span,764                targeted_by_break: false,765            });766            self.arena.alloc(hir::Expr {767                hir_id: self.next_id(),768                kind: hir::ExprKind::Loop(block, None, hir::LoopSource::Loop, span),769                span,770            })771        };772        hir::Arm { hir_id, pat, guard, body, span }773    }774775    fn lower_capture_clause(&mut self, capture_clause: CaptureBy) -> CaptureBy {776        match capture_clause {777            CaptureBy::Ref => CaptureBy::Ref,778            CaptureBy::Use { use_kw } => CaptureBy::Use { use_kw: self.lower_span(use_kw) },779            CaptureBy::Value { move_kw } => CaptureBy::Value { move_kw: self.lower_span(move_kw) },780        }781    }782783    /// Lower/desugar a coroutine construct.784    ///785    /// In particular, this creates the correct async resume argument and `_task_context`.786    ///787    /// This results in:788    ///789    /// ```text790    /// static move? |<_task_context?>| -> <return_ty> {791    ///     <body>792    /// }793    /// ```794    pub(super) fn make_desugared_coroutine_expr(795        &mut self,796        capture_clause: CaptureBy,797        closure_node_id: NodeId,798        return_ty: Option<hir::FnRetTy<'hir>>,799        fn_decl_span: Span,800        span: Span,801        desugaring_kind: hir::CoroutineDesugaring,802        coroutine_source: hir::CoroutineSource,803        body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,804    ) -> hir::ExprKind<'hir> {805        let closure_def_id = self.local_def_id(closure_node_id);806        let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source);807808        // The `async` desugaring takes a resume argument and maintains a `task_context`,809        // whereas a generator does not.810        let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind {811            hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => {812                // Resume argument type: `ResumeTy`813                let unstable_span = self.mark_span_with_reason(814                    DesugaringKind::Async,815                    self.lower_span(span),816                    Some(Arc::clone(&self.allow_gen_future)),817                );818                let resume_ty = self.make_lang_item_qpath(LangItem::ResumeTy, unstable_span, None);819                let input_ty = hir::Ty {820                    hir_id: self.next_id(),821                    kind: hir::TyKind::Path(resume_ty),822                    span: unstable_span,823                };824                let inputs = arena_vec![self; input_ty];825826                // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.827                let (pat, task_context_hid) = self.pat_ident_binding_mode(828                    span,829                    Ident::with_dummy_span(sym::_task_context),830                    hir::BindingMode::MUT,831                );832                let param = hir::Param {833                    hir_id: self.next_id(),834                    pat,835                    ty_span: self.lower_span(span),836                    span: self.lower_span(span),837                };838                let params = arena_vec![self; param];839840                (inputs, params, Some(task_context_hid))841            }842            hir::CoroutineDesugaring::Gen => (&[], &[], None),843        };844845        let output =846            return_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));847848        let fn_decl = self.arena.alloc(hir::FnDecl {849            inputs,850            output,851            fn_decl_kind: hir::FnDeclFlags::default(),852        });853854        let body = self.lower_body(move |this| {855            this.coroutine_kind = Some(coroutine_kind);856857            let old_ctx = this.task_context;858            if task_context.is_some() {859                this.task_context = task_context;860            }861            let res = body(this);862            this.task_context = old_ctx;863864            (params, res)865        });866867        // `static |<_task_context?>| -> <return_ty> { <body> }`:868        hir::ExprKind::Closure(self.arena.alloc(hir::Closure {869            def_id: closure_def_id,870            binder: hir::ClosureBinder::Default,871            capture_clause: self.lower_capture_clause(capture_clause),872            bound_generic_params: &[],873            fn_decl,874            body,875            fn_decl_span: self.lower_span(fn_decl_span),876            fn_arg_span: None,877            kind: hir::ClosureKind::Coroutine(coroutine_kind),878            constness: hir::Constness::NotConst,879            explicit_captures: &[],880        }))881    }882883    /// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to884    /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.885    pub(super) fn maybe_forward_track_caller(886        &mut self,887        span: Span,888        outer_hir_id: HirId,889        inner_hir_id: HirId,890    ) {891        if self.tcx.features().async_fn_track_caller()892            && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)893            && find_attr!(*attrs, TrackCaller(_))894        {895            let unstable_span = self.mark_span_with_reason(896                DesugaringKind::Async,897                span,898                Some(Arc::clone(&self.allow_gen_future)),899            );900            self.lower_attrs(901                inner_hir_id,902                &[Attribute {903                    kind: AttrKind::Normal(Box::new(NormalAttr::from_ident(Ident::new(904                        sym::track_caller,905                        span,906                    )))),907                    id: self.tcx.sess.psess.attr_id_generator.mk_attr_id(),908                    style: AttrStyle::Outer,909                    span: unstable_span,910                }],911                span,912                Target::Fn,913            );914        }915    }916917    /// Desugar `<expr>.await` into:918    /// ```ignore (pseudo-rust)919    /// match ::std::future::IntoFuture::into_future(<expr>) {920    ///     mut __awaitee => loop {921    ///         match unsafe { ::std::future::Future::poll(922    ///             <::std::pin::Pin>::new_unchecked(&mut __awaitee),923    ///             ::std::future::get_context(task_context),924    ///         ) } {925    ///             ::std::task::Poll::Ready(result) => break result,926    ///             ::std::task::Poll::Pending => {}927    ///         }928    ///         task_context = yield ();929    ///     }930    /// }931    /// ```932    fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {933        let expr = self.arena.alloc(self.lower_expr_mut(expr));934        self.make_lowered_await(await_kw_span, expr, FutureKind::Future)935    }936937    /// Takes an expr that has already been lowered and generates a desugared await loop around it938    fn make_lowered_await(939        &mut self,940        await_kw_span: Span,941        expr: &'hir hir::Expr<'hir>,942        await_kind: FutureKind,943    ) -> hir::ExprKind<'hir> {944        let full_span = expr.span.to(await_kw_span);945946        let is_async_gen = match self.coroutine_kind {947            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false,948            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,949            Some(hir::CoroutineKind::Coroutine(_))950            | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _))951            | None => {952                // Lower to a block `{ EXPR; <error> }` so that the awaited expr953                // is not accidentally orphaned.954                let stmt_id = self.next_id();955                let expr_err = self.expr(956                    expr.span,957                    hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {958                        await_kw_span,959                        item_span: self.current_item,960                    })),961                );962                return hir::ExprKind::Block(963                    self.block_all(964                        expr.span,965                        arena_vec![self; hir::Stmt {966                            hir_id: stmt_id,967                            kind: hir::StmtKind::Semi(expr),968                            span: expr.span,969                        }],970                        Some(self.arena.alloc(expr_err)),971                    ),972                    None,973                );974            }975        };976977        let features = match await_kind {978            FutureKind::Future if is_async_gen => Some(Arc::clone(&self.allow_async_gen)),979            FutureKind::Future => None,980            FutureKind::AsyncIterator => Some(Arc::clone(&self.allow_for_await)),981        };982        let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features);983        let gen_future_span = self.mark_span_with_reason(984            DesugaringKind::Await,985            full_span,986            Some(Arc::clone(&self.allow_gen_future)),987        );988        let expr_hir_id = expr.hir_id;989990        // Note that the name of this binding must not be changed to something else because991        // debuggers and debugger extensions expect it to be called `__awaitee`. They use992        // this name to identify what is being awaited by a suspended async functions.993        let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);994        let (awaitee_pat, awaitee_pat_hid) =995            self.pat_ident_binding_mode(gen_future_span, awaitee_ident, hir::BindingMode::MUT);996997        let task_context_ident = Ident::with_dummy_span(sym::_task_context);998999        // unsafe {1000        //     ::std::future::Future::poll(1001        //         ::std::pin::Pin::new_unchecked(&mut __awaitee),1002        //         ::std::future::get_context(task_context),1003        //     )1004        // }1005        let poll_expr = {1006            let awaitee = self.expr_ident(span, awaitee_ident, awaitee_pat_hid);1007            let ref_mut_awaitee = self.expr_mut_addr_of(span, awaitee);10081009            let Some(task_context_hid) = self.task_context else {1010                unreachable!("use of `await` outside of an async context.");1011            };10121013            let task_context = self.expr_ident_mut(span, task_context_ident, task_context_hid);10141015            let new_unchecked = self.expr_call_lang_item_fn_mut(1016                span,1017                LangItem::PinNewUnchecked,1018                arena_vec![self; ref_mut_awaitee],1019            );1020            let get_context = self.expr_call_lang_item_fn_mut(1021                gen_future_span,1022                LangItem::GetContext,1023                arena_vec![self; task_context],1024            );1025            let call = match await_kind {1026                FutureKind::Future => self.expr_call_lang_item_fn(1027                    span,1028                    LangItem::FuturePoll,1029                    arena_vec![self; new_unchecked, get_context],1030                ),1031                FutureKind::AsyncIterator => self.expr_call_lang_item_fn(1032                    span,1033                    LangItem::AsyncIteratorPollNext,1034                    arena_vec![self; new_unchecked, get_context],1035                ),1036            };1037            self.arena.alloc(self.expr_unsafe(span, call))1038        };10391040        // `::std::task::Poll::Ready(result) => break result`1041        let loop_node_id = self.next_node_id();1042        let loop_hir_id = self.lower_node_id(loop_node_id);1043        let ready_arm = {1044            let x_ident = Ident::with_dummy_span(sym::result);1045            let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident);1046            let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);1047            let ready_field = self.single_pat_field(gen_future_span, x_pat);1048            let ready_pat = self.pat_lang_item_variant(span, LangItem::PollReady, ready_field);1049            let break_x = self.with_loop_scope(loop_hir_id, move |this| {1050                let expr_break =1051                    hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));1052                this.arena.alloc(this.expr(gen_future_span, expr_break))1053            });1054            self.arm(ready_pat, break_x, span)1055        };10561057        // `::std::task::Poll::Pending => {}`1058        let pending_arm = {1059            let pending_pat = self.pat_lang_item_variant(span, LangItem::PollPending, &[]);1060            let empty_block = self.expr_block_empty(span);1061            self.arm(pending_pat, empty_block, span)1062        };10631064        let inner_match_stmt = {1065            let match_expr = self.expr_match(1066                span,1067                poll_expr,1068                arena_vec![self; ready_arm, pending_arm],1069                hir::MatchSource::AwaitDesugar,1070            );1071            self.stmt_expr(span, match_expr)1072        };10731074        // Depending on `async` of `async gen`:1075        // async     - task_context = yield ();1076        // async gen - task_context = yield ASYNC_GEN_PENDING;1077        let yield_stmt = {1078            let yielded = if is_async_gen {1079                self.arena.alloc(self.expr_lang_item_path(span, LangItem::AsyncGenPending))1080            } else {1081                self.expr_unit(span)1082            };10831084            let yield_expr = self.expr(1085                span,1086                hir::ExprKind::Yield(yielded, hir::YieldSource::Await { expr: Some(expr_hir_id) }),1087            );1088            let yield_expr = self.arena.alloc(yield_expr);10891090            let Some(task_context_hid) = self.task_context else {1091                unreachable!("use of `await` outside of an async context.");1092            };10931094            let lhs = self.expr_ident(span, task_context_ident, task_context_hid);1095            let assign =1096                self.expr(span, hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span)));1097            self.stmt_expr(span, assign)1098        };10991100        let loop_block = self.block_all(span, arena_vec![self; inner_match_stmt, yield_stmt], None);11011102        // loop { .. }1103        let loop_expr = self.arena.alloc(hir::Expr {1104            hir_id: loop_hir_id,1105            kind: hir::ExprKind::Loop(1106                loop_block,1107                None,1108                hir::LoopSource::Loop,1109                self.lower_span(span),1110            ),1111            span: self.lower_span(span),1112        });11131114        // mut __awaitee => loop { ... }1115        let awaitee_arm = self.arm(awaitee_pat, loop_expr, span);11161117        // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`1118        let into_future_expr = match await_kind {1119            FutureKind::Future => self.expr_call_lang_item_fn(1120                span,1121                LangItem::IntoFutureIntoFuture,1122                arena_vec![self; *expr],1123            ),1124            // Not needed for `for await` because we expect to have already called1125            // `IntoAsyncIterator::into_async_iter` on it.1126            FutureKind::AsyncIterator => expr,1127        };11281129        // match <into_future_expr> {1130        //     mut __awaitee => loop { .. }1131        // }1132        hir::ExprKind::Match(1133            into_future_expr,1134            arena_vec![self; awaitee_arm],1135            hir::MatchSource::AwaitDesugar,1136        )1137    }11381139    fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {1140        hir::ExprKind::Use(self.lower_expr(expr), self.lower_span(use_kw_span))1141    }11421143    /// Destructure the LHS of complex assignments.1144    /// For instance, lower `(a, b) = t` to `{ let (lhs1, lhs2) = t; a = lhs1; b = lhs2; }`.1145    fn lower_expr_assign(1146        &mut self,1147        lhs: &Expr,1148        rhs: &Expr,1149        eq_sign_span: Span,1150        whole_span: Span,1151    ) -> hir::ExprKind<'hir> {1152        // Return early in case of an ordinary assignment.1153        fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {1154            match &lhs.kind {1155                ExprKind::Array(..)1156                | ExprKind::Struct(..)1157                | ExprKind::Tup(..)1158                | ExprKind::Underscore => false,1159                // Check for unit struct constructor.1160                ExprKind::Path(..) => lower_ctx.extract_unit_struct_path(lhs).is_none(),1161                // Check for tuple struct constructor.1162                ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(),1163                ExprKind::Paren(e) => {1164                    match e.kind {1165                        // We special-case `(..)` for consistency with patterns.1166                        ExprKind::Range(None, None, RangeLimits::HalfOpen) => false,1167                        _ => is_ordinary(lower_ctx, e),1168                    }1169                }1170                _ => true,1171            }1172        }1173        if is_ordinary(self, lhs) {1174            return hir::ExprKind::Assign(1175                self.lower_expr(lhs),1176                self.lower_expr(rhs),1177                self.lower_span(eq_sign_span),1178            );1179        }11801181        let mut assignments = vec![];11821183        // The LHS becomes a pattern: `(lhs1, lhs2)`.1184        let pat = self.destructure_assign(lhs, eq_sign_span, &mut assignments);1185        let rhs = self.lower_expr(rhs);11861187        // Introduce a `let` for destructuring: `let (lhs1, lhs2) = t`.1188        let destructure_let =1189            self.stmt_let_pat(None, whole_span, Some(rhs), pat, hir::LocalSource::AssignDesugar);11901191        // `a = lhs1; b = lhs2;`.1192        let stmts = self.arena.alloc_from_iter(std::iter::once(destructure_let).chain(assignments));11931194        // Wrap everything in a block.1195        hir::ExprKind::Block(self.block_all(whole_span, stmts, None), None)1196    }11971198    /// If the given expression is a path to a tuple struct, returns that path.1199    /// It is not a complete check, but just tries to reject most paths early1200    /// if they are not tuple structs.1201    /// Type checking will take care of the full validation later.1202    fn extract_tuple_struct_path<'a>(1203        &mut self,1204        expr: &'a Expr,1205    ) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> {1206        if let ExprKind::Path(qself, path) = &expr.kind {1207            // Does the path resolve to something disallowed in a tuple struct/variant pattern?1208            if let Some(partial_res) = self.get_partial_res(expr.id) {1209                if let Some(res) = partial_res.full_res()1210                    && !res.expected_in_tuple_struct_pat()1211                {1212                    return None;1213                }1214            }1215            return Some((qself, path));1216        }1217        None1218    }12191220    /// If the given expression is a path to a unit struct, returns that path.1221    /// It is not a complete check, but just tries to reject most paths early1222    /// if they are not unit structs.1223    /// Type checking will take care of the full validation later.1224    fn extract_unit_struct_path<'a>(1225        &mut self,1226        expr: &'a Expr,1227    ) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> {1228        if let ExprKind::Path(qself, path) = &expr.kind {1229            // Does the path resolve to something disallowed in a unit struct/variant pattern?1230            if let Some(partial_res) = self.get_partial_res(expr.id) {1231                if let Some(res) = partial_res.full_res()1232                    && !res.expected_in_unit_struct_pat()1233                {1234                    return None;1235                }1236            }1237            return Some((qself, path));1238        }1239        None1240    }12411242    /// Convert the LHS of a destructuring assignment to a pattern.1243    /// Each sub-assignment is recorded in `assignments`.1244    fn destructure_assign(1245        &mut self,1246        lhs: &Expr,1247        eq_sign_span: Span,1248        assignments: &mut Vec<hir::Stmt<'hir>>,1249    ) -> &'hir hir::Pat<'hir> {1250        self.arena.alloc(self.destructure_assign_mut(lhs, eq_sign_span, assignments))1251    }12521253    fn destructure_assign_mut(1254        &mut self,1255        lhs: &Expr,1256        eq_sign_span: Span,1257        assignments: &mut Vec<hir::Stmt<'hir>>,1258    ) -> hir::Pat<'hir> {1259        match &lhs.kind {1260            // Underscore pattern.1261            ExprKind::Underscore => {1262                return self.pat_without_dbm(lhs.span, hir::PatKind::Wild);1263            }1264            // Slice patterns.1265            ExprKind::Array(elements) => {1266                let (pats, rest) =1267                    self.destructure_sequence(elements, "slice", eq_sign_span, assignments);1268                let slice_pat = if let Some((i, span)) = rest {1269                    let (before, after) = pats.split_at(i);1270                    hir::PatKind::Slice(1271                        before,1272                        Some(self.arena.alloc(self.pat_without_dbm(span, hir::PatKind::Wild))),1273                        after,1274                    )1275                } else {1276                    hir::PatKind::Slice(pats, None, &[])1277                };1278                return self.pat_without_dbm(lhs.span, slice_pat);1279            }1280            // Tuple structs.1281            ExprKind::Call(callee, args) => {1282                if let Some((qself, path)) = self.extract_tuple_struct_path(callee) {1283                    let (pats, rest) = self.destructure_sequence(1284                        args,1285                        "tuple struct or variant",1286                        eq_sign_span,1287                        assignments,1288                    );1289                    let qpath = self.lower_qpath(1290                        callee.id,1291                        qself,1292                        path,1293                        ParamMode::Optional,1294                        AllowReturnTypeNotation::No,1295                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),1296                        None,1297                    );1298                    // Destructure like a tuple struct.1299                    let tuple_struct_pat = hir::PatKind::TupleStruct(1300                        qpath,1301                        pats,1302                        hir::DotDotPos::new(rest.map(|r| r.0)),1303                    );1304                    return self.pat_without_dbm(lhs.span, tuple_struct_pat);1305                }1306            }1307            // Unit structs and enum variants.1308            ExprKind::Path(..) => {1309                if let Some((qself, path)) = self.extract_unit_struct_path(lhs) {1310                    let qpath = self.lower_qpath(1311                        lhs.id,1312                        qself,1313                        path,1314                        ParamMode::Optional,1315                        AllowReturnTypeNotation::No,1316                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),1317                        None,1318                    );1319                    // Destructure like a unit struct.1320                    let unit_struct_pat = hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {1321                        kind: hir::PatExprKind::Path(qpath),1322                        hir_id: self.next_id(),1323                        span: self.lower_span(lhs.span),1324                    }));1325                    return self.pat_without_dbm(lhs.span, unit_struct_pat);1326                }1327            }1328            // Structs.1329            ExprKind::Struct(se) => {1330                let field_pats = self.arena.alloc_from_iter(se.fields.iter().map(|f| {1331                    let pat = self.destructure_assign(&f.expr, eq_sign_span, assignments);1332                    hir::PatField {1333                        hir_id: self.next_id(),1334                        ident: self.lower_ident(f.ident),1335                        pat,1336                        is_shorthand: f.is_shorthand,1337                        span: self.lower_span(f.span),1338                    }1339                }));1340                let qpath = self.lower_qpath(1341                    lhs.id,1342                    &se.qself,1343                    &se.path,1344                    ParamMode::Optional,1345                    AllowReturnTypeNotation::No,1346                    ImplTraitContext::Disallowed(ImplTraitPosition::Path),1347                    None,1348                );1349                let fields_omitted = match &se.rest {1350                    StructRest::Base(e) => {1351                        self.dcx().emit_err(FunctionalRecordUpdateDestructuringAssignment {1352                            span: e.span,1353                        });1354                        Some(self.lower_span(e.span))1355                    }1356                    StructRest::Rest(span) => Some(self.lower_span(*span)),1357                    StructRest::None | StructRest::NoneWithError(_) => None,1358                };1359                let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted);1360                return self.pat_without_dbm(lhs.span, struct_pat);1361            }1362            // Tuples.1363            ExprKind::Tup(elements) => {1364                let (pats, rest) =1365                    self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);1366                let tuple_pat = hir::PatKind::Tuple(pats, hir::DotDotPos::new(rest.map(|r| r.0)));1367                return self.pat_without_dbm(lhs.span, tuple_pat);1368            }1369            ExprKind::Paren(e) => {1370                // We special-case `(..)` for consistency with patterns.1371                if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {1372                    let tuple_pat = hir::PatKind::Tuple(&[], hir::DotDotPos::new(Some(0)));1373                    return self.pat_without_dbm(lhs.span, tuple_pat);1374                } else {1375                    return self.destructure_assign_mut(e, eq_sign_span, assignments);1376                }1377            }1378            _ => {}1379        }1380        // Treat all other cases as normal lvalue.1381        let ident = Ident::new(sym::lhs, self.lower_span(lhs.span));1382        let (pat, binding) = self.pat_ident_mut(lhs.span, ident);1383        let ident = self.expr_ident(lhs.span, ident, binding);1384        let assign =1385            hir::ExprKind::Assign(self.lower_expr(lhs), ident, self.lower_span(eq_sign_span));1386        let expr = self.expr(lhs.span, assign);1387        assignments.push(self.stmt_expr(lhs.span, expr));1388        pat1389    }13901391    /// Destructure a sequence of expressions occurring on the LHS of an assignment.1392    /// Such a sequence occurs in a tuple (struct)/slice.1393    /// Return a sequence of corresponding patterns, and the index and the span of `..` if it1394    /// exists.1395    /// Each sub-assignment is recorded in `assignments`.1396    fn destructure_sequence(1397        &mut self,1398        elements: &[Box<Expr>],1399        ctx: &str,1400        eq_sign_span: Span,1401        assignments: &mut Vec<hir::Stmt<'hir>>,1402    ) -> (&'hir [hir::Pat<'hir>], Option<(usize, Span)>) {1403        let mut rest = None;1404        let elements =1405            self.arena.alloc_from_iter(elements.iter().enumerate().filter_map(|(i, e)| {1406                // Check for `..` pattern.1407                if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {1408                    if let Some((_, prev_span)) = rest {1409                        self.ban_extra_rest_pat(e.span, prev_span, ctx);1410                    } else {1411                        rest = Some((i, e.span));1412                    }1413                    None1414                } else {1415                    Some(self.destructure_assign_mut(e, eq_sign_span, assignments))1416                }1417            }));1418        (elements, rest)1419    }14201421    /// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.1422    fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {1423        let e1 = self.lower_expr_mut(e1);1424        let e2 = self.lower_expr_mut(e2);1425        let fn_path = self.make_lang_item_qpath(LangItem::RangeInclusiveNew, span, None);1426        let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path)));1427        hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])1428    }14291430    fn lower_expr_range(1431        &mut self,1432        span: Span,1433        e1: Option<&Expr>,1434        e2: Option<&Expr>,1435        lims: RangeLimits,1436    ) -> hir::ExprKind<'hir> {1437        use rustc_ast::RangeLimits::*;14381439        let lang_item = match (e1, e2, lims) {1440            (None, None, HalfOpen) => LangItem::RangeFull,1441            (Some(..), None, HalfOpen) => {1442                if self.tcx.features().new_range() {1443                    LangItem::RangeFromCopy1444                } else {1445                    LangItem::RangeFrom1446                }1447            }1448            (None, Some(..), HalfOpen) => LangItem::RangeTo,1449            (Some(..), Some(..), HalfOpen) => {1450                if self.tcx.features().new_range() {1451                    LangItem::RangeCopy1452                } else {1453                    LangItem::Range1454                }1455            }1456            (None, Some(..), Closed) => {1457                if self.tcx.features().new_range() {1458                    LangItem::RangeToInclusiveCopy1459                } else {1460                    LangItem::RangeToInclusive1461                }1462            }1463            (Some(e1), Some(e2), Closed) => {1464                if self.tcx.features().new_range() {1465                    LangItem::RangeInclusiveCopy1466                } else {1467                    return self.lower_expr_range_closed(span, e1, e2);1468                }1469            }1470            (start, None, Closed) => {1471                self.dcx().emit_err(InclusiveRangeWithNoEnd { span });1472                match start {1473                    Some(..) => {1474                        if self.tcx.features().new_range() {1475                            LangItem::RangeFromCopy1476                        } else {1477                            LangItem::RangeFrom1478                        }1479                    }1480                    None => LangItem::RangeFull,1481                }1482            }1483        };14841485        let fields = self.arena.alloc_from_iter(1486            e1.iter()1487                .map(|e| (sym::start, e))1488                .chain(e2.iter().map(|e| {1489                    (1490                        if matches!(1491                            lang_item,1492                            LangItem::RangeInclusiveCopy | LangItem::RangeToInclusiveCopy1493                        ) {1494                            sym::last1495                        } else {1496                            sym::end1497                        },1498                        e,1499                    )1500                }))1501                .map(|(s, e)| {1502                    let span = self.lower_span(e.span);1503                    let span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None);1504                    let expr = self.lower_expr(e);1505                    let ident = Ident::new(s, span);1506                    self.expr_field(ident, expr, span)1507                }),1508        );15091510        hir::ExprKind::Struct(1511            self.arena.alloc(self.make_lang_item_qpath(lang_item, span, None)),1512            fields,1513            hir::StructTailExpr::None,1514        )1515    }15161517    // Record labelled expr's HirId so that we can retrieve it in `lower_jump_destination` without1518    // lowering node id again.1519    fn lower_label(1520        &mut self,1521        opt_label: Option<Label>,1522        dest_id: NodeId,1523        dest_hir_id: hir::HirId,1524    ) -> Option<Label> {1525        let label = opt_label?;1526        self.ident_and_label_to_local_id.insert(dest_id, dest_hir_id.local_id);1527        Some(Label { ident: self.lower_ident(label.ident) })1528    }15291530    fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {1531        let target_id = match destination {1532            Some((id, _)) => {1533                if let Some(loop_id) = self.owner.get_label_res(id) {1534                    let local_id = self.ident_and_label_to_local_id[&loop_id];1535                    let loop_hir_id = HirId { owner: self.current_hir_id_owner, local_id };1536                    Ok(loop_hir_id)1537                } else {1538                    Err(hir::LoopIdError::UnresolvedLabel)1539                }1540            }1541            None => {1542                self.loop_scope.map(|id| Ok(id)).unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))1543            }1544        };1545        let label = destination1546            .map(|(_, label)| label)1547            .map(|label| Label { ident: self.lower_ident(label.ident) });1548        hir::Destination { label, target_id }1549    }15501551    fn lower_jump_destination(&mut self, id: NodeId, opt_label: Option<Label>) -> hir::Destination {1552        if self.is_in_loop_condition && opt_label.is_none() {1553            hir::Destination {1554                label: None,1555                target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition),1556            }1557        } else {1558            self.lower_loop_destination(opt_label.map(|label| (id, label)))1559        }1560    }15611562    fn with_try_block_scope<T>(1563        &mut self,1564        scope: TryBlockScope,1565        f: impl FnOnce(&mut Self) -> T,1566    ) -> T {1567        let old_scope = mem::replace(&mut self.try_block_scope, scope);1568        let result = f(self);1569        self.try_block_scope = old_scope;1570        result1571    }15721573    fn with_loop_scope<T>(&mut self, loop_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T {1574        // We're no longer in the base loop's condition; we're in another loop.1575        let was_in_loop_condition = self.is_in_loop_condition;1576        self.is_in_loop_condition = false;15771578        let old_scope = self.loop_scope.replace(loop_id);1579        let result = f(self);1580        self.loop_scope = old_scope;15811582        self.is_in_loop_condition = was_in_loop_condition;15831584        result1585    }15861587    fn with_loop_condition_scope<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {1588        let was_in_loop_condition = self.is_in_loop_condition;1589        self.is_in_loop_condition = true;15901591        let result = f(self);15921593        self.is_in_loop_condition = was_in_loop_condition;15941595        result1596    }15971598    fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {1599        let hir_id = self.lower_node_id(f.id);1600        self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField);1601        hir::ExprField {1602            hir_id,1603            ident: self.lower_ident(f.ident),1604            expr: self.lower_expr(&f.expr),1605            span: self.lower_span(f.span),1606            is_shorthand: f.is_shorthand,1607        }1608    }16091610    fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {1611        let yielded =1612            opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));16131614        if !self.tcx.features().yield_expr()1615            && !self.tcx.features().coroutines()1616            && !self.tcx.features().gen_blocks()1617        {1618            rustc_session::diagnostics::feature_err(1619                &self.tcx.sess,1620                sym::yield_expr,1621                span,1622                msg!("yield syntax is experimental"),1623            )1624            .emit();1625        }16261627        let is_async_gen = match self.coroutine_kind {1628            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false,1629            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,1630            Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {1631                // Lower to a block `{ EXPR; <error> }` so that the awaited expr1632                // is not accidentally orphaned.1633                let stmt_id = self.next_id();1634                let expr_err = self.expr(1635                    yielded.span,1636                    hir::ExprKind::Err(self.dcx().emit_err(AsyncCoroutinesNotSupported { span })),1637                );1638                return hir::ExprKind::Block(1639                    self.block_all(1640                        yielded.span,1641                        arena_vec![self; hir::Stmt {1642                            hir_id: stmt_id,1643                            kind: hir::StmtKind::Semi(yielded),1644                            span: yielded.span,1645                        }],1646                        Some(self.arena.alloc(expr_err)),1647                    ),1648                    None,1649                );1650            }1651            Some(hir::CoroutineKind::Coroutine(_)) => false,1652            None => {1653                let suggestion = self.current_item.map(|s| s.shrink_to_lo());1654                self.dcx().emit_err(YieldInClosure { span, suggestion });1655                self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable));16561657                false1658            }1659        };16601661        if is_async_gen {1662            // `yield $expr` is transformed into `task_context = yield async_gen_ready($expr)`.1663            // This ensures that we store our resumed `ResumeContext` correctly, and also that1664            // the apparent value of the `yield` expression is `()`.1665            let desugar_span = self.mark_span_with_reason(1666                DesugaringKind::Async,1667                span,1668                Some(Arc::clone(&self.allow_async_gen)),1669            );1670            let wrapped_yielded = self.expr_call_lang_item_fn(1671                desugar_span,1672                LangItem::AsyncGenReady,1673                std::slice::from_ref(yielded),1674            );1675            let yield_expr = self.arena.alloc(1676                self.expr(span, hir::ExprKind::Yield(wrapped_yielded, hir::YieldSource::Yield)),1677            );16781679            let Some(task_context_hid) = self.task_context else {1680                unreachable!("use of `await` outside of an async context.");1681            };1682            let task_context_ident = Ident::with_dummy_span(sym::_task_context);1683            let lhs = self.expr_ident(desugar_span, task_context_ident, task_context_hid);16841685            hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span))1686        } else {1687            hir::ExprKind::Yield(yielded, hir::YieldSource::Yield)1688        }1689    }16901691    /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:1692    /// ```ignore (pseudo-rust)1693    /// {1694    ///     let result = match IntoIterator::into_iter(<head>) {1695    ///         mut iter => {1696    ///             [opt_ident]: loop {1697    ///                 match Iterator::next(&mut iter) {1698    ///                     None => break,1699    ///                     Some(<pat>) => <body>,1700    ///                 };1701    ///             }1702    ///         }1703    ///     };1704    ///     result1705    /// }1706    /// ```1707    fn lower_expr_for(1708        &mut self,1709        e: &Expr,1710        pat: &Pat,1711        head: &Expr,1712        body: &Block,1713        opt_label: Option<Label>,1714        loop_kind: ForLoopKind,1715    ) -> hir::Expr<'hir> {1716        let head = self.lower_expr_mut(head);1717        let pat = self.lower_pat(pat);1718        let for_span =1719            self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None);1720        let for_ctxt = for_span.ctxt();17211722        // Try to point both the head and pat spans to their position in the for loop1723        // rather than inside a macro.1724        let head_span =1725            head.span.find_ancestor_in_same_ctxt(e.span).unwrap_or(head.span).with_ctxt(for_ctxt);1726        let pat_span =1727            pat.span.find_ancestor_in_same_ctxt(e.span).unwrap_or(pat.span).with_ctxt(for_ctxt);17281729        let loop_hir_id = self.lower_node_id(e.id);1730        let label = self.lower_label(opt_label, e.id, loop_hir_id);17311732        // `None => break`1733        let none_arm = {1734            let break_expr =1735                self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span));1736            let pat = self.pat_none(for_span);1737            self.arm(pat, break_expr, for_span)1738        };17391740        // Some(<pat>) => <body>,1741        let some_arm = {1742            let some_pat = self.pat_some(pat_span, pat);1743            let body_block =1744                self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false));1745            let body_expr = self.arena.alloc(self.expr_block(body_block));1746            self.arm(some_pat, body_expr, for_span)1747        };17481749        // `mut iter`1750        let iter = Ident::with_dummy_span(sym::iter);1751        let (iter_pat, iter_pat_nid) =1752            self.pat_ident_binding_mode(head_span, iter, hir::BindingMode::MUT);17531754        let match_expr = {1755            let iter = self.expr_ident(head_span, iter, iter_pat_nid);1756            let next_expr = match loop_kind {1757                ForLoopKind::For => {1758                    // `Iterator::next(&mut iter)`1759                    let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);1760                    self.expr_call_lang_item_fn(1761                        head_span,1762                        LangItem::IteratorNext,1763                        arena_vec![self; ref_mut_iter],1764                    )1765                }1766                ForLoopKind::ForAwait => {1767                    // we'll generate `unsafe { Pin::new_unchecked(&mut iter) })` and then pass this1768                    // to make_lowered_await with `FutureKind::AsyncIterator` which will generator1769                    // calls to `poll_next`. In user code, this would probably be a call to1770                    // `Pin::as_mut` but here it's easy enough to do `new_unchecked`.17711772                    // `&mut iter`1773                    let iter = self.expr_mut_addr_of(head_span, iter);1774                    // `Pin::new_unchecked(...)`1775                    let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(1776                        head_span,1777                        LangItem::PinNewUnchecked,1778                        arena_vec![self; iter],1779                    ));1780                    // `unsafe { ... }`1781                    let iter = self.arena.alloc(self.expr_unsafe(head_span, iter));1782                    let kind = self.make_lowered_await(head_span, iter, FutureKind::AsyncIterator);1783                    self.arena.alloc(hir::Expr { hir_id: self.next_id(), kind, span: head_span })1784                }1785            };1786            let arms = arena_vec![self; none_arm, some_arm];17871788            // `match $next_expr { ... }`1789            self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)1790        };1791        let match_stmt = self.stmt_expr(for_span, match_expr);17921793        let loop_block = self.block_all(for_span, arena_vec![self; match_stmt], None);17941795        // `[opt_ident]: loop { ... }`1796        let kind = hir::ExprKind::Loop(1797            loop_block,1798            label,1799            hir::LoopSource::ForLoop,1800            self.lower_span(for_span.with_hi(head.span.hi())),1801        );1802        let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span });18031804        // `mut iter => { ... }`1805        let iter_arm = self.arm(iter_pat, loop_expr, for_span);18061807        let match_expr = match loop_kind {1808            ForLoopKind::For => {1809                // `::std::iter::IntoIterator::into_iter(<head>)`1810                let into_iter_expr = self.expr_call_lang_item_fn(1811                    head_span,1812                    LangItem::IntoIterIntoIter,1813                    arena_vec![self; head],1814                );18151816                self.arena.alloc(self.expr_match(1817                    for_span,1818                    into_iter_expr,1819                    arena_vec![self; iter_arm],1820                    hir::MatchSource::ForLoopDesugar,1821                ))1822            }1823            // `match into_async_iter(<head>) { ref mut iter => match unsafe { Pin::new_unchecked(iter) } { ... } }`1824            ForLoopKind::ForAwait => {1825                let iter_ident = iter;1826                let (async_iter_pat, async_iter_pat_id) =1827                    self.pat_ident_binding_mode(head_span, iter_ident, hir::BindingMode::REF_MUT);1828                let iter = self.expr_ident_mut(head_span, iter_ident, async_iter_pat_id);1829                // `Pin::new_unchecked(...)`1830                let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(1831                    head_span,1832                    LangItem::PinNewUnchecked,1833                    arena_vec![self; iter],1834                ));1835                // `unsafe { ... }`1836                let iter = self.arena.alloc(self.expr_unsafe(head_span, iter));1837                let inner_match_expr = self.arena.alloc(self.expr_match(1838                    for_span,1839                    iter,1840                    arena_vec![self; iter_arm],1841                    hir::MatchSource::ForLoopDesugar,1842                ));18431844                // `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)`1845                let iter = self.expr_call_lang_item_fn(1846                    head_span,1847                    LangItem::IntoAsyncIterIntoIter,1848                    arena_vec![self; head],1849                );1850                let iter_arm = self.arm(async_iter_pat, inner_match_expr, for_span);1851                self.arena.alloc(self.expr_match(1852                    for_span,1853                    iter,1854                    arena_vec![self; iter_arm],1855                    hir::MatchSource::ForLoopDesugar,1856                ))1857            }1858        };18591860        // This is effectively `{ let _result = ...; _result }`.1861        // The construct was introduced in #21984 and is necessary to make sure that1862        // temporaries in the `head` expression are dropped and do not leak to the1863        // surrounding scope of the `match` since the `match` is not a terminating scope.1864        //1865        // Also, add the attributes to the outer returned expr node.1866        let expr = self.expr_drop_temps_mut(for_span, match_expr);1867        self.lower_attrs(expr.hir_id, &e.attrs, e.span, Target::from_expr(e));1868        expr1869    }18701871    /// Desugar `ExprKind::Try` from: `<expr>?` into:1872    /// ```ignore (pseudo-rust)1873    /// match Try::branch(<expr>) {1874    ///     ControlFlow::Continue(val) => #[allow(unreachable_code)] val,,1875    ///     ControlFlow::Break(residual) =>1876    ///         #[allow(unreachable_code)]1877    ///         // If there is an enclosing `try {...}`:1878    ///         break 'catch_target Residual::into_try_type(residual),1879    ///         // Otherwise:1880    ///         return Try::from_residual(residual),1881    /// }1882    /// ```1883    fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> {1884        let unstable_span = self.mark_span_with_reason(1885            DesugaringKind::QuestionMark,1886            span,1887            Some(Arc::clone(&self.allow_try_trait)),1888        );1889        let try_span = self.tcx.sess.source_map().end_point(span);1890        let try_span = self.mark_span_with_reason(1891            DesugaringKind::QuestionMark,1892            try_span,1893            Some(Arc::clone(&self.allow_try_trait)),1894        );18951896        // `Try::branch(<expr>)`1897        let scrutinee = {1898            // expand <expr>1899            let sub_expr = self.lower_expr_mut(sub_expr);19001901            self.expr_call_lang_item_fn(1902                unstable_span,1903                LangItem::TryTraitBranch,1904                arena_vec![self; sub_expr],1905            )1906        };19071908        let attrs: AttrVec = thin_vec![self.unreachable_code_attr(try_span)];19091910        // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`1911        let continue_arm = {1912            let val_ident = Ident::with_dummy_span(sym::val);1913            let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);1914            let val_expr = self.expr_ident(span, val_ident, val_pat_nid);1915            self.lower_attrs(val_expr.hir_id, &attrs, span, Target::Expression);1916            let continue_pat = self.pat_cf_continue(unstable_span, val_pat);1917            self.arm(continue_pat, val_expr, try_span)1918        };19191920        // `ControlFlow::Break(residual) =>1921        //     #[allow(unreachable_code)]1922        //     return Try::from_residual(residual),`1923        let break_arm = {1924            let residual_ident = Ident::with_dummy_span(sym::residual);1925            let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident);1926            let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid);19271928            let (constructor_item, target_id) = match self.try_block_scope {1929                TryBlockScope::Function => {1930                    (LangItem::TryTraitFromResidual, Err(hir::LoopIdError::OutsideLoopScope))1931                }1932                TryBlockScope::Homogeneous(block_id) => {1933                    (LangItem::ResidualIntoTryType, Ok(block_id))1934                }1935                TryBlockScope::Heterogeneous(block_id) => {1936                    (LangItem::TryTraitFromResidual, Ok(block_id))1937                }1938            };1939            let from_residual_expr = self.wrap_in_try_constructor(1940                constructor_item,1941                try_span,1942                self.arena.alloc(residual_expr),1943                unstable_span,1944            );1945            let ret_expr = if target_id.is_ok() {1946                self.arena.alloc(self.expr(1947                    try_span,1948                    hir::ExprKind::Break(1949                        hir::Destination { label: None, target_id },1950                        Some(from_residual_expr),1951                    ),1952                ))1953            } else {1954                let ret_expr = self.checked_return(Some(from_residual_expr));1955                self.arena.alloc(self.expr(try_span, ret_expr))1956            };1957            self.lower_attrs(ret_expr.hir_id, &attrs, span, Target::Expression);19581959            let break_pat = self.pat_cf_break(try_span, residual_local);1960            self.arm(break_pat, ret_expr, try_span)1961        };19621963        hir::ExprKind::Match(1964            scrutinee,1965            arena_vec![self; break_arm, continue_arm],1966            hir::MatchSource::TryDesugar(scrutinee.hir_id),1967        )1968    }19691970    /// Desugar `ExprKind::Yeet` from: `do yeet <expr>` into:1971    /// ```ignore(illustrative)1972    /// // If there is an enclosing `try {...}`:1973    /// break 'catch_target FromResidual::from_residual(Yeet(residual));1974    /// // Otherwise:1975    /// return FromResidual::from_residual(Yeet(residual));1976    /// ```1977    /// But to simplify this, there's a `from_yeet` lang item function which1978    /// handles the combined `FromResidual::from_residual(Yeet(residual))`.1979    fn lower_expr_yeet(&mut self, span: Span, sub_expr: Option<&Expr>) -> hir::ExprKind<'hir> {1980        // The expression (if present) or `()` otherwise.1981        let (yeeted_span, yeeted_expr) = if let Some(sub_expr) = sub_expr {1982            (sub_expr.span, self.lower_expr(sub_expr))1983        } else {1984            (self.mark_span_with_reason(DesugaringKind::YeetExpr, span, None), self.expr_unit(span))1985        };19861987        let unstable_span = self.mark_span_with_reason(1988            DesugaringKind::YeetExpr,1989            span,1990            Some(Arc::clone(&self.allow_try_trait)),1991        );19921993        let from_yeet_expr = self.wrap_in_try_constructor(1994            LangItem::TryTraitFromYeet,1995            unstable_span,1996            yeeted_expr,1997            yeeted_span,1998        );19992000        match self.try_block_scope {

Findings

✓ No findings reported for this file.

Get this view in your editor

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