1use std::mem;2use std::ops::ControlFlow;3use std::sync::Arc;45use rustc_ast::node_id::NodeMap;6use rustc_ast::*;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};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 ensure_sufficient_stack(|| {165 let mut span = self.lower_span(e.span);166 match &e.kind {167 // Parenthesis expression does not have a HirId and is handled specially.168 ExprKind::Paren(ex) => {169 let mut ex = self.lower_expr_mut(ex);170 // Include parens in span, but only if it is a super-span.171 if e.span.contains(ex.span) {172 ex.span = self.lower_span(e.span.with_ctxt(ex.span.ctxt()));173 }174 // Merge attributes into the inner expression.175 if !e.attrs.is_empty() {176 let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]);177 let new_attrs = self178 .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e))179 .into_iter()180 .chain(old_attrs.iter().cloned());181 let new_attrs = &*self.arena.alloc_from_iter(new_attrs);182 if new_attrs.is_empty() {183 return ex;184 }185 self.attrs.insert(ex.hir_id.local_id, new_attrs);186 }187 return ex;188 }189 // Desugar `ExprForLoop`190 // from: `[opt_ident]: for await? <pat> in <iter> <body>`191 //192 // This also needs special handling because the HirId of the returned `hir::Expr` will not193 // correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.194 ExprKind::ForLoop { pat, iter, body, label, kind } => {195 return self.lower_expr_for(e, pat, iter, body, *label, *kind);196 }197 ExprKind::Closure(closure) => return self.lower_expr_closure_expr(e, closure),198 _ => (),199 }200201 let expr_hir_id = self.lower_node_id(e.id);202 self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e));203204 let kind = match &e.kind {205 ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),206 ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)),207 ExprKind::Repeat(expr, count) => {208 let expr = self.lower_expr(expr);209 let count = self.lower_array_length_to_const_arg(count);210 hir::ExprKind::Repeat(expr, count)211 }212 ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),213 ExprKind::Call(f, args) => {214 if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f, self.tcx)215 {216 self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)217 } else {218 let f = self.lower_expr(f);219 hir::ExprKind::Call(f, self.lower_exprs(args))220 }221 }222 ExprKind::MethodCall(MethodCall { seg, receiver, args, span }) => {223 let hir_seg = self.arena.alloc(self.lower_path_segment(224 e.span,225 seg,226 ParamMode::Optional,227 GenericArgsMode::Err,228 ImplTraitContext::Disallowed(ImplTraitPosition::Path),229 // Method calls can't have bound modifiers230 None,231 ));232 let receiver = self.lower_expr(receiver);233 let args =234 self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x)));235 hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(*span))236 }237 ExprKind::Binary(binop, lhs, rhs) => {238 let binop = self.lower_binop(*binop);239 let lhs = self.lower_expr(lhs);240 let rhs = self.lower_expr(rhs);241 hir::ExprKind::Binary(binop, lhs, rhs)242 }243 ExprKind::Unary(op, ohs) => {244 let op = self.lower_unop(*op);245 let ohs = self.lower_expr(ohs);246 hir::ExprKind::Unary(op, ohs)247 }248 ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)),249 ExprKind::IncludedBytes(byte_sym) => {250 let lit = respan(251 self.lower_span(e.span),252 LitKind::ByteStr(*byte_sym, StrStyle::Cooked),253 );254 hir::ExprKind::Lit(lit)255 }256 ExprKind::Cast(expr, ty) => {257 let expr = self.lower_expr(expr);258 let ty = self259 .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));260 hir::ExprKind::Cast(expr, ty)261 }262 ExprKind::Type(expr, ty) => {263 let expr = self.lower_expr(expr);264 let ty = self265 .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));266 hir::ExprKind::Type(expr, ty)267 }268 ExprKind::AddrOf(k, m, ohs) => {269 let ohs = self.lower_expr(ohs);270 hir::ExprKind::AddrOf(*k, *m, ohs)271 }272 ExprKind::Let(pat, scrutinee, span, recovered) => {273 hir::ExprKind::Let(self.arena.alloc(hir::LetExpr {274 span: self.lower_span(*span),275 pat: self.lower_pat(pat),276 ty: None,277 init: self.lower_expr(scrutinee),278 recovered: *recovered,279 }))280 }281 ExprKind::If(cond, then, else_opt) => {282 self.lower_expr_if(cond, then, else_opt.as_deref())283 }284 ExprKind::While(cond, body, opt_label) => {285 self.with_loop_scope(expr_hir_id, |this| {286 let span =287 this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None);288 let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id);289 this.lower_expr_while_in_loop_scope(span, cond, body, opt_label)290 })291 }292 ExprKind::Loop(body, opt_label, span) => {293 self.with_loop_scope(expr_hir_id, |this| {294 let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id);295 hir::ExprKind::Loop(296 this.lower_block(body, false),297 opt_label,298 hir::LoopSource::Loop,299 this.lower_span(*span),300 )301 })302 }303 ExprKind::TryBlock(body, opt_ty) => {304 self.lower_expr_try_block(body, opt_ty.as_deref())305 }306 ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match(307 self.lower_expr(expr),308 self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),309 match kind {310 MatchKind::Prefix => hir::MatchSource::Normal,311 MatchKind::Postfix => hir::MatchSource::Postfix,312 },313 ),314 ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),315 ExprKind::Move(inner, move_kw_span) => {316 if !self.tcx.features().move_expr() {317 return self.expr_err(*move_kw_span, self.dcx().has_errors().unwrap());318 }319 if let Some(state) = self.move_expr_bindings.last().and_then(Option::as_ref) {320 let existing = state.bindings.get(&e.id).copied();321 let (ident, binding) = existing.unwrap_or_else(|| {322 for nested in MoveExprInitializerFinder::collect(inner) {323 self.record_move_expr(324 nested.id,325 nested.expr,326 nested.move_kw_span,327 false,328 );329 }330 self.record_move_expr(e.id, inner, *move_kw_span, true)331 });332 hir::ExprKind::Path(hir::QPath::Resolved(333 None,334 self.arena.alloc(hir::Path {335 span: self.lower_span(e.span),336 res: Res::Local(binding),337 segments: arena_vec![338 self;339 hir::PathSegment::new(340 self.lower_ident(ident),341 self.next_id(),342 Res::Local(binding),343 )344 ],345 }),346 ))347 } else {348 let guar = self349 .dcx()350 .emit_err(MoveExprOnlyInPlainClosures { span: *move_kw_span });351 hir::ExprKind::Err(guar)352 }353 }354 ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr),355 ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => {356 let desugaring_kind = match genblock_kind {357 GenBlockKind::Async => hir::CoroutineDesugaring::Async,358 GenBlockKind::Gen => hir::CoroutineDesugaring::Gen,359 GenBlockKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen,360 };361 self.make_desugared_coroutine_expr(362 *capture_clause,363 e.id,364 None,365 *decl_span,366 e.span,367 desugaring_kind,368 hir::CoroutineSource::Block,369 |this| {370 this.with_new_scopes(e.span, |this| {371 let (expr, _) = this.with_move_expr_bindings(None, |this| {372 this.lower_block_expr(block)373 });374 expr375 })376 },377 )378 }379 ExprKind::Block(blk, opt_label) => {380 // Different from loops, label of block resolves to block id rather than381 // expr node id.382 let block_hir_id = self.lower_node_id(blk.id);383 let opt_label = self.lower_label(*opt_label, blk.id, block_hir_id);384 let hir_block = self.arena.alloc(self.lower_block_noalloc(385 block_hir_id,386 blk,387 opt_label.is_some(),388 ));389 hir::ExprKind::Block(hir_block, opt_label)390 }391 ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span),392 ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp(393 self.lower_assign_op(*op),394 self.lower_expr(el),395 self.lower_expr(er),396 ),397 ExprKind::Field(el, ident) => {398 hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident))399 }400 ExprKind::Index(el, er, brackets_span) => hir::ExprKind::Index(401 self.lower_expr(el),402 self.lower_expr(er),403 self.lower_span(*brackets_span),404 ),405 ExprKind::Range(e1, e2, lims) => {406 span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None);407 self.lower_expr_range(span, e1.as_deref(), e2.as_deref(), *lims)408 }409 ExprKind::Underscore => {410 let guar = self.dcx().emit_err(UnderscoreExprLhsAssign { span: e.span });411 hir::ExprKind::Err(guar)412 }413 ExprKind::Path(qself, path) => {414 let qpath = self.lower_qpath(415 e.id,416 qself,417 path,418 ParamMode::Optional,419 AllowReturnTypeNotation::No,420 ImplTraitContext::Disallowed(ImplTraitPosition::Path),421 None,422 );423 hir::ExprKind::Path(qpath)424 }425 ExprKind::Break(opt_label, opt_expr) => {426 let opt_expr = opt_expr.as_ref().map(|x| self.lower_expr(x));427 hir::ExprKind::Break(self.lower_jump_destination(e.id, *opt_label), opt_expr)428 }429 ExprKind::Continue(opt_label) => {430 hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label))431 }432 ExprKind::Ret(e) => {433 let expr = e.as_ref().map(|x| self.lower_expr(x));434 self.checked_return(expr)435 }436 ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),437 ExprKind::Become(sub_expr) => {438 let sub_expr = self.lower_expr(sub_expr);439 hir::ExprKind::Become(sub_expr)440 }441 ExprKind::InlineAsm(asm) => {442 hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))443 }444 ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),445 ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(446 self.lower_ty_alloc(447 container,448 ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),449 ),450 self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))),451 ),452 ExprKind::Struct(se) => {453 let rest = match se.rest {454 StructRest::Base(ref e) => hir::StructTailExpr::Base(self.lower_expr(e)),455 StructRest::Rest(sp) => {456 hir::StructTailExpr::DefaultFields(self.lower_span(sp))457 }458 StructRest::None => hir::StructTailExpr::None,459 StructRest::NoneWithError(guar) => hir::StructTailExpr::NoneWithError(guar),460 };461 hir::ExprKind::Struct(462 self.arena.alloc(self.lower_qpath(463 e.id,464 &se.qself,465 &se.path,466 ParamMode::Optional,467 AllowReturnTypeNotation::No,468 ImplTraitContext::Disallowed(ImplTraitPosition::Path),469 None,470 )),471 self.arena472 .alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),473 rest,474 )475 }476 ExprKind::Yield(kind) => self.lower_expr_yield(e.span, kind.expr().map(|x| &**x)),477 ExprKind::Err(guar) => hir::ExprKind::Err(*guar),478479 ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(480 *kind,481 self.lower_expr(expr),482 ty.as_ref().map(|ty| {483 self.lower_ty_alloc(484 ty,485 ImplTraitContext::Disallowed(ImplTraitPosition::Cast),486 )487 }),488 ),489490 ExprKind::Dummy => {491 span_bug!(e.span, "lowered ExprKind::Dummy")492 }493494 ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),495496 ExprKind::Paren(_) | ExprKind::ForLoop { .. } | ExprKind::Closure(..) => {497 unreachable!("already handled")498 }499500 ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),501 };502503 hir::Expr { hir_id: expr_hir_id, kind, span }504 })505 }506507 pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {508 self.with_new_scopes(c.value.span, |this| {509 let def_id = this.local_def_id(c.id);510 let hir_id = this.lower_node_id(c.id);511 let (body, _) = this.with_move_expr_bindings(None, |this| {512 this.lower_const_body(c.value.span, Some(&c.value))513 });514 hir::ConstBlock { def_id, hir_id, body }515 })516 }517518 pub(crate) fn lower_lit(&mut self, token_lit: &token::Lit, span: Span) -> hir::Lit {519 let lit_kind = match LitKind::from_token_lit(*token_lit) {520 Ok(lit_kind) => lit_kind,521 Err(err) => {522 let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span);523 LitKind::Err(guar)524 }525 };526 respan(self.lower_span(span), lit_kind)527 }528529 fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {530 match u {531 UnOp::Deref => hir::UnOp::Deref,532 UnOp::Not => hir::UnOp::Not,533 UnOp::Neg => hir::UnOp::Neg,534 }535 }536537 fn lower_binop(&mut self, b: BinOp) -> BinOp {538 Spanned { node: b.node, span: self.lower_span(b.span) }539 }540541 fn lower_assign_op(&mut self, a: AssignOp) -> AssignOp {542 Spanned { node: a.node, span: self.lower_span(a.span) }543 }544545 fn lower_legacy_const_generics(546 &mut self,547 mut f: Expr,548 args: ThinVec<Box<Expr>>,549 legacy_args_idx: &[usize],550 ) -> hir::ExprKind<'hir> {551 let ExprKind::Path(None, path) = &mut f.kind else {552 unreachable!();553 };554555 let mut error = None;556 let mut invalid_expr_error = |tcx: TyCtxt<'_>, span| {557 // Avoid emitting the error multiple times.558 if error.is_none() {559 let sm = tcx.sess.source_map();560 let mut const_args = vec![];561 let mut other_args = vec![];562 for (idx, arg) in args.iter().enumerate() {563 if let Ok(arg) = sm.span_to_snippet(arg.span) {564 if legacy_args_idx.contains(&idx) {565 const_args.push(format!("{{ {} }}", arg));566 } else {567 other_args.push(arg);568 }569 }570 }571 let suggestion = UseConstGenericArg {572 end_of_fn: f.span.shrink_to_hi(),573 const_args: const_args.join(", "),574 other_args: other_args.join(", "),575 call_args: args[0].span.to(args.last().unwrap().span),576 };577 error = Some(tcx.dcx().emit_err(InvalidLegacyConstGenericArg { span, suggestion }));578 }579 error.unwrap()580 };581582 // Split the arguments into const generics and normal arguments583 let mut real_args = vec![];584 let mut generic_args = ThinVec::new();585 for (idx, arg) in args.iter().cloned().enumerate() {586 if legacy_args_idx.contains(&idx) {587 let node_id = self.next_node_id();588 self.create_def(node_id, None, DefKind::AnonConst, f.span);589 let const_value =590 if let ControlFlow::Break(span) = WillCreateDefIdsVisitor.visit_expr(&arg) {591 Box::new(Expr {592 id: self.next_node_id(),593 kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),594 span: f.span,595 attrs: [].into(),596 tokens: None,597 })598 } else {599 arg600 };601602 let anon_const = AnonConst {603 id: node_id,604 value: const_value,605 mgca_disambiguation: MgcaDisambiguation::AnonConst,606 };607 generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));608 } else {609 real_args.push(arg);610 }611 }612613 // Add generic args to the last element of the path.614 let last_segment = path.segments.last_mut().unwrap();615 assert!(last_segment.args.is_none());616 last_segment.args = Some(Box::new(GenericArgs::AngleBracketed(AngleBracketedArgs {617 span: DUMMY_SP,618 args: generic_args,619 })));620621 // Now lower everything as normal.622 let f = self.lower_expr(&f);623 hir::ExprKind::Call(f, self.lower_exprs(&real_args))624 }625626 fn lower_expr_if(627 &mut self,628 cond: &Expr,629 then: &Block,630 else_opt: Option<&Expr>,631 ) -> hir::ExprKind<'hir> {632 let lowered_cond = self.lower_expr(cond);633 let then_expr = self.lower_block_expr(then);634 if let Some(rslt) = else_opt {635 hir::ExprKind::If(636 lowered_cond,637 self.arena.alloc(then_expr),638 Some(self.lower_expr(rslt)),639 )640 } else {641 hir::ExprKind::If(lowered_cond, self.arena.alloc(then_expr), None)642 }643 }644645 // We desugar: `'label: while $cond $body` into:646 //647 // ```648 // 'label: loop {649 // if { let _t = $cond; _t } {650 // $body651 // }652 // else {653 // break;654 // }655 // }656 // ```657 //658 // Wrap in a construct equivalent to `{ let _t = $cond; _t }`659 // to preserve drop semantics since `while $cond { ... }` does not660 // let temporaries live outside of `cond`.661 fn lower_expr_while_in_loop_scope(662 &mut self,663 span: Span,664 cond: &Expr,665 body: &Block,666 opt_label: Option<Label>,667 ) -> hir::ExprKind<'hir> {668 let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond));669 let then = self.lower_block_expr(body);670 let expr_break = self.expr_break(span);671 let stmt_break = self.stmt_expr(span, expr_break);672 let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);673 let else_expr = self.arena.alloc(self.expr_block(else_blk));674 let if_kind = hir::ExprKind::If(lowered_cond, self.arena.alloc(then), Some(else_expr));675 let if_expr = self.expr(span, if_kind);676 let block = self.block_expr(self.arena.alloc(if_expr));677 let span = self.lower_span(span.with_hi(cond.span.hi()));678 hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span)679 }680681 /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,682 /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }`683 /// and save the block id to use it as a break target for desugaring of the `?` operator.684 fn lower_expr_try_block(&mut self, body: &Block, opt_ty: Option<&Ty>) -> hir::ExprKind<'hir> {685 let body_hir_id = self.lower_node_id(body.id);686 let new_scope = if opt_ty.is_some() {687 TryBlockScope::Heterogeneous(body_hir_id)688 } else {689 TryBlockScope::Homogeneous(body_hir_id)690 };691 let whole_block = self.with_try_block_scope(new_scope, |this| {692 let mut block = this.lower_block_noalloc(body_hir_id, body, true);693694 // Final expression of the block (if present) or `()` with span at the end of block695 let (try_span, tail_expr) = if let Some(expr) = block.expr.take() {696 (697 this.mark_span_with_reason(698 DesugaringKind::TryBlock,699 expr.span,700 Some(Arc::clone(&this.allow_try_trait)),701 ),702 expr,703 )704 } else {705 let try_span = this.mark_span_with_reason(706 DesugaringKind::TryBlock,707 this.tcx.sess.source_map().end_point(body.span),708 Some(Arc::clone(&this.allow_try_trait)),709 );710711 (try_span, this.expr_unit(try_span))712 };713714 let ok_wrapped_span =715 this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);716717 // `::std::ops::Try::from_output($tail_expr)`718 block.expr = Some(this.wrap_in_try_constructor(719 hir::LangItem::TryTraitFromOutput,720 try_span,721 tail_expr,722 ok_wrapped_span,723 ));724725 this.arena.alloc(block)726 });727728 if let Some(ty) = opt_ty {729 let ty = self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path));730 let block_expr = self.arena.alloc(self.expr_block(whole_block));731 hir::ExprKind::Type(block_expr, ty)732 } else {733 hir::ExprKind::Block(whole_block, None)734 }735 }736737 fn wrap_in_try_constructor(738 &mut self,739 lang_item: hir::LangItem,740 method_span: Span,741 expr: &'hir hir::Expr<'hir>,742 overall_span: Span,743 ) -> &'hir hir::Expr<'hir> {744 let constructor = self.arena.alloc(self.expr_lang_item_path(method_span, lang_item));745 self.expr_call(overall_span, constructor, std::slice::from_ref(expr))746 }747748 fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {749 let pat = self.lower_pat(&arm.pat);750 let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond));751 let hir_id = self.next_id();752 let span = self.lower_span(arm.span);753 self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm);754 let is_never_pattern = pat.is_never_pattern();755 // We need to lower the body even if it's unneeded for never pattern in match,756 // ensure that we can get HirId for DefId if need (issue #137708).757 let body = arm.body.as_ref().map(|x| self.lower_expr(x));758 let body = if let Some(body) = body759 && !is_never_pattern760 {761 body762 } else {763 // Either `body.is_none()` or `is_never_pattern` here.764 if !is_never_pattern {765 if self.tcx.features().never_patterns() {766 // If the feature is off we already emitted the error after parsing.767 let suggestion = span.shrink_to_hi();768 self.dcx().emit_err(MatchArmWithNoBody { span, suggestion });769 }770 } else if let Some(body) = &arm.body {771 self.dcx().emit_err(NeverPatternWithBody { span: body.span });772 } else if let Some(g) = &arm.guard {773 self.dcx().emit_err(NeverPatternWithGuard { span: g.span() });774 }775776 // We add a fake `loop {}` arm body so that it typecks to `!`. The mir lowering of never777 // patterns ensures this loop is not reachable.778 let block = self.arena.alloc(hir::Block {779 stmts: &[],780 expr: None,781 hir_id: self.next_id(),782 rules: hir::BlockCheckMode::DefaultBlock,783 span,784 targeted_by_break: false,785 });786 self.arena.alloc(hir::Expr {787 hir_id: self.next_id(),788 kind: hir::ExprKind::Loop(block, None, hir::LoopSource::Loop, span),789 span,790 })791 };792 hir::Arm { hir_id, pat, guard, body, span }793 }794795 fn lower_capture_clause(&mut self, capture_clause: CaptureBy) -> CaptureBy {796 match capture_clause {797 CaptureBy::Ref => CaptureBy::Ref,798 CaptureBy::Use { use_kw } => CaptureBy::Use { use_kw: self.lower_span(use_kw) },799 CaptureBy::Value { move_kw } => CaptureBy::Value { move_kw: self.lower_span(move_kw) },800 }801 }802803 /// Lower/desugar a coroutine construct.804 ///805 /// In particular, this creates the correct async resume argument and `_task_context`.806 ///807 /// This results in:808 ///809 /// ```text810 /// static move? |<_task_context?>| -> <return_ty> {811 /// <body>812 /// }813 /// ```814 pub(super) fn make_desugared_coroutine_expr(815 &mut self,816 capture_clause: CaptureBy,817 closure_node_id: NodeId,818 return_ty: Option<hir::FnRetTy<'hir>>,819 fn_decl_span: Span,820 span: Span,821 desugaring_kind: hir::CoroutineDesugaring,822 coroutine_source: hir::CoroutineSource,823 body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,824 ) -> hir::ExprKind<'hir> {825 let closure_def_id = self.local_def_id(closure_node_id);826 let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source);827828 // The `async` desugaring takes a resume argument and maintains a `task_context`,829 // whereas a generator does not.830 let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind {831 hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => {832 // Resume argument type: `ResumeTy`833 let unstable_span = self.mark_span_with_reason(834 DesugaringKind::Async,835 self.lower_span(span),836 Some(Arc::clone(&self.allow_gen_future)),837 );838 let resume_ty =839 self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None);840 let input_ty = hir::Ty {841 hir_id: self.next_id(),842 kind: hir::TyKind::Path(resume_ty),843 span: unstable_span,844 };845 let inputs = arena_vec![self; input_ty];846847 // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.848 let (pat, task_context_hid) = self.pat_ident_binding_mode(849 span,850 Ident::with_dummy_span(sym::_task_context),851 hir::BindingMode::MUT,852 );853 let param = hir::Param {854 hir_id: self.next_id(),855 pat,856 ty_span: self.lower_span(span),857 span: self.lower_span(span),858 };859 let params = arena_vec![self; param];860861 (inputs, params, Some(task_context_hid))862 }863 hir::CoroutineDesugaring::Gen => (&[], &[], None),864 };865866 let output =867 return_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));868869 let fn_decl = self.arena.alloc(hir::FnDecl {870 inputs,871 output,872 fn_decl_kind: hir::FnDeclFlags::default(),873 });874875 let body = self.lower_body(move |this| {876 this.coroutine_kind = Some(coroutine_kind);877878 let old_ctx = this.task_context;879 if task_context.is_some() {880 this.task_context = task_context;881 }882 let res = body(this);883 this.task_context = old_ctx;884885 (params, res)886 });887888 // `static |<_task_context?>| -> <return_ty> { <body> }`:889 hir::ExprKind::Closure(self.arena.alloc(hir::Closure {890 def_id: closure_def_id,891 binder: hir::ClosureBinder::Default,892 capture_clause: self.lower_capture_clause(capture_clause),893 bound_generic_params: &[],894 fn_decl,895 body,896 fn_decl_span: self.lower_span(fn_decl_span),897 fn_arg_span: None,898 kind: hir::ClosureKind::Coroutine(coroutine_kind),899 constness: hir::Constness::NotConst,900 explicit_captures: &[],901 }))902 }903904 /// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to905 /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.906 pub(super) fn maybe_forward_track_caller(907 &mut self,908 span: Span,909 outer_hir_id: HirId,910 inner_hir_id: HirId,911 ) {912 if self.tcx.features().async_fn_track_caller()913 && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)914 && find_attr!(*attrs, TrackCaller(_))915 {916 let unstable_span = self.mark_span_with_reason(917 DesugaringKind::Async,918 span,919 Some(Arc::clone(&self.allow_gen_future)),920 );921 self.lower_attrs(922 inner_hir_id,923 &[Attribute {924 kind: AttrKind::Normal(Box::new(NormalAttr::from_ident(Ident::new(925 sym::track_caller,926 span,927 )))),928 id: self.tcx.sess.psess.attr_id_generator.mk_attr_id(),929 style: AttrStyle::Outer,930 span: unstable_span,931 }],932 span,933 Target::Fn,934 );935 }936 }937938 /// Desugar `<expr>.await` into:939 /// ```ignore (pseudo-rust)940 /// match ::std::future::IntoFuture::into_future(<expr>) {941 /// mut __awaitee => loop {942 /// match unsafe { ::std::future::Future::poll(943 /// <::std::pin::Pin>::new_unchecked(&mut __awaitee),944 /// ::std::future::get_context(task_context),945 /// ) } {946 /// ::std::task::Poll::Ready(result) => break result,947 /// ::std::task::Poll::Pending => {}948 /// }949 /// task_context = yield ();950 /// }951 /// }952 /// ```953 fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {954 let expr = self.arena.alloc(self.lower_expr_mut(expr));955 self.make_lowered_await(await_kw_span, expr, FutureKind::Future)956 }957958 /// Takes an expr that has already been lowered and generates a desugared await loop around it959 fn make_lowered_await(960 &mut self,961 await_kw_span: Span,962 expr: &'hir hir::Expr<'hir>,963 await_kind: FutureKind,964 ) -> hir::ExprKind<'hir> {965 let full_span = expr.span.to(await_kw_span);966967 let is_async_gen = match self.coroutine_kind {968 Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false,969 Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,970 Some(hir::CoroutineKind::Coroutine(_))971 | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _))972 | None => {973 // Lower to a block `{ EXPR; <error> }` so that the awaited expr974 // is not accidentally orphaned.975 let stmt_id = self.next_id();976 let expr_err = self.expr(977 expr.span,978 hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {979 await_kw_span,980 item_span: self.current_item,981 })),982 );983 return hir::ExprKind::Block(984 self.block_all(985 expr.span,986 arena_vec![self; hir::Stmt {987 hir_id: stmt_id,988 kind: hir::StmtKind::Semi(expr),989 span: expr.span,990 }],991 Some(self.arena.alloc(expr_err)),992 ),993 None,994 );995 }996 };997998 let features = match await_kind {999 FutureKind::Future if is_async_gen => Some(Arc::clone(&self.allow_async_gen)),1000 FutureKind::Future => None,1001 FutureKind::AsyncIterator => Some(Arc::clone(&self.allow_for_await)),1002 };1003 let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features);1004 let gen_future_span = self.mark_span_with_reason(1005 DesugaringKind::Await,1006 full_span,1007 Some(Arc::clone(&self.allow_gen_future)),1008 );1009 let expr_hir_id = expr.hir_id;10101011 // Note that the name of this binding must not be changed to something else because1012 // debuggers and debugger extensions expect it to be called `__awaitee`. They use1013 // this name to identify what is being awaited by a suspended async functions.1014 let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);1015 let (awaitee_pat, awaitee_pat_hid) =1016 self.pat_ident_binding_mode(gen_future_span, awaitee_ident, hir::BindingMode::MUT);10171018 let task_context_ident = Ident::with_dummy_span(sym::_task_context);10191020 // unsafe {1021 // ::std::future::Future::poll(1022 // ::std::pin::Pin::new_unchecked(&mut __awaitee),1023 // ::std::future::get_context(task_context),1024 // )1025 // }1026 let poll_expr = {1027 let awaitee = self.expr_ident(span, awaitee_ident, awaitee_pat_hid);1028 let ref_mut_awaitee = self.expr_mut_addr_of(span, awaitee);10291030 let Some(task_context_hid) = self.task_context else {1031 unreachable!("use of `await` outside of an async context.");1032 };10331034 let task_context = self.expr_ident_mut(span, task_context_ident, task_context_hid);10351036 let new_unchecked = self.expr_call_lang_item_fn_mut(1037 span,1038 hir::LangItem::PinNewUnchecked,1039 arena_vec![self; ref_mut_awaitee],1040 );1041 let get_context = self.expr_call_lang_item_fn_mut(1042 gen_future_span,1043 hir::LangItem::GetContext,1044 arena_vec![self; task_context],1045 );1046 let call = match await_kind {1047 FutureKind::Future => self.expr_call_lang_item_fn(1048 span,1049 hir::LangItem::FuturePoll,1050 arena_vec![self; new_unchecked, get_context],1051 ),1052 FutureKind::AsyncIterator => self.expr_call_lang_item_fn(1053 span,1054 hir::LangItem::AsyncIteratorPollNext,1055 arena_vec![self; new_unchecked, get_context],1056 ),1057 };1058 self.arena.alloc(self.expr_unsafe(span, call))1059 };10601061 // `::std::task::Poll::Ready(result) => break result`1062 let loop_node_id = self.next_node_id();1063 let loop_hir_id = self.lower_node_id(loop_node_id);1064 let ready_arm = {1065 let x_ident = Ident::with_dummy_span(sym::result);1066 let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident);1067 let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);1068 let ready_field = self.single_pat_field(gen_future_span, x_pat);1069 let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);1070 let break_x = self.with_loop_scope(loop_hir_id, move |this| {1071 let expr_break =1072 hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));1073 this.arena.alloc(this.expr(gen_future_span, expr_break))1074 });1075 self.arm(ready_pat, break_x, span)1076 };10771078 // `::std::task::Poll::Pending => {}`1079 let pending_arm = {1080 let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);1081 let empty_block = self.expr_block_empty(span);1082 self.arm(pending_pat, empty_block, span)1083 };10841085 let inner_match_stmt = {1086 let match_expr = self.expr_match(1087 span,1088 poll_expr,1089 arena_vec![self; ready_arm, pending_arm],1090 hir::MatchSource::AwaitDesugar,1091 );1092 self.stmt_expr(span, match_expr)1093 };10941095 // Depending on `async` of `async gen`:1096 // async - task_context = yield ();1097 // async gen - task_context = yield ASYNC_GEN_PENDING;1098 let yield_stmt = {1099 let yielded = if is_async_gen {1100 self.arena.alloc(self.expr_lang_item_path(span, hir::LangItem::AsyncGenPending))1101 } else {1102 self.expr_unit(span)1103 };11041105 let yield_expr = self.expr(1106 span,1107 hir::ExprKind::Yield(yielded, hir::YieldSource::Await { expr: Some(expr_hir_id) }),1108 );1109 let yield_expr = self.arena.alloc(yield_expr);11101111 let Some(task_context_hid) = self.task_context else {1112 unreachable!("use of `await` outside of an async context.");1113 };11141115 let lhs = self.expr_ident(span, task_context_ident, task_context_hid);1116 let assign =1117 self.expr(span, hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span)));1118 self.stmt_expr(span, assign)1119 };11201121 let loop_block = self.block_all(span, arena_vec![self; inner_match_stmt, yield_stmt], None);11221123 // loop { .. }1124 let loop_expr = self.arena.alloc(hir::Expr {1125 hir_id: loop_hir_id,1126 kind: hir::ExprKind::Loop(1127 loop_block,1128 None,1129 hir::LoopSource::Loop,1130 self.lower_span(span),1131 ),1132 span: self.lower_span(span),1133 });11341135 // mut __awaitee => loop { ... }1136 let awaitee_arm = self.arm(awaitee_pat, loop_expr, span);11371138 // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`1139 let into_future_expr = match await_kind {1140 FutureKind::Future => self.expr_call_lang_item_fn(1141 span,1142 hir::LangItem::IntoFutureIntoFuture,1143 arena_vec![self; *expr],1144 ),1145 // Not needed for `for await` because we expect to have already called1146 // `IntoAsyncIterator::into_async_iter` on it.1147 FutureKind::AsyncIterator => expr,1148 };11491150 // match <into_future_expr> {1151 // mut __awaitee => loop { .. }1152 // }1153 hir::ExprKind::Match(1154 into_future_expr,1155 arena_vec![self; awaitee_arm],1156 hir::MatchSource::AwaitDesugar,1157 )1158 }11591160 fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {1161 hir::ExprKind::Use(self.lower_expr(expr), self.lower_span(use_kw_span))1162 }11631164 /// Destructure the LHS of complex assignments.1165 /// For instance, lower `(a, b) = t` to `{ let (lhs1, lhs2) = t; a = lhs1; b = lhs2; }`.1166 fn lower_expr_assign(1167 &mut self,1168 lhs: &Expr,1169 rhs: &Expr,1170 eq_sign_span: Span,1171 whole_span: Span,1172 ) -> hir::ExprKind<'hir> {1173 // Return early in case of an ordinary assignment.1174 fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {1175 match &lhs.kind {1176 ExprKind::Array(..)1177 | ExprKind::Struct(..)1178 | ExprKind::Tup(..)1179 | ExprKind::Underscore => false,1180 // Check for unit struct constructor.1181 ExprKind::Path(..) => lower_ctx.extract_unit_struct_path(lhs).is_none(),1182 // Check for tuple struct constructor.1183 ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(),1184 ExprKind::Paren(e) => {1185 match e.kind {1186 // We special-case `(..)` for consistency with patterns.1187 ExprKind::Range(None, None, RangeLimits::HalfOpen) => false,1188 _ => is_ordinary(lower_ctx, e),1189 }1190 }1191 _ => true,1192 }1193 }1194 if is_ordinary(self, lhs) {1195 return hir::ExprKind::Assign(1196 self.lower_expr(lhs),1197 self.lower_expr(rhs),1198 self.lower_span(eq_sign_span),1199 );1200 }12011202 let mut assignments = vec![];12031204 // The LHS becomes a pattern: `(lhs1, lhs2)`.1205 let pat = self.destructure_assign(lhs, eq_sign_span, &mut assignments);1206 let rhs = self.lower_expr(rhs);12071208 // Introduce a `let` for destructuring: `let (lhs1, lhs2) = t`.1209 let destructure_let =1210 self.stmt_let_pat(None, whole_span, Some(rhs), pat, hir::LocalSource::AssignDesugar);12111212 // `a = lhs1; b = lhs2;`.1213 let stmts = self.arena.alloc_from_iter(std::iter::once(destructure_let).chain(assignments));12141215 // Wrap everything in a block.1216 hir::ExprKind::Block(self.block_all(whole_span, stmts, None), None)1217 }12181219 /// If the given expression is a path to a tuple struct, returns that path.1220 /// It is not a complete check, but just tries to reject most paths early1221 /// if they are not tuple structs.1222 /// Type checking will take care of the full validation later.1223 fn extract_tuple_struct_path<'a>(1224 &mut self,1225 expr: &'a Expr,1226 ) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> {1227 if let ExprKind::Path(qself, path) = &expr.kind {1228 // Does the path resolve to something disallowed in a tuple struct/variant pattern?1229 if let Some(partial_res) = self.get_partial_res(expr.id) {1230 if let Some(res) = partial_res.full_res()1231 && !res.expected_in_tuple_struct_pat()1232 {1233 return None;1234 }1235 }1236 return Some((qself, path));1237 }1238 None1239 }12401241 /// If the given expression is a path to a unit struct, returns that path.1242 /// It is not a complete check, but just tries to reject most paths early1243 /// if they are not unit structs.1244 /// Type checking will take care of the full validation later.1245 fn extract_unit_struct_path<'a>(1246 &mut self,1247 expr: &'a Expr,1248 ) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> {1249 if let ExprKind::Path(qself, path) = &expr.kind {1250 // Does the path resolve to something disallowed in a unit struct/variant pattern?1251 if let Some(partial_res) = self.get_partial_res(expr.id) {1252 if let Some(res) = partial_res.full_res()1253 && !res.expected_in_unit_struct_pat()1254 {1255 return None;1256 }1257 }1258 return Some((qself, path));1259 }1260 None1261 }12621263 /// Convert the LHS of a destructuring assignment to a pattern.1264 /// Each sub-assignment is recorded in `assignments`.1265 fn destructure_assign(1266 &mut self,1267 lhs: &Expr,1268 eq_sign_span: Span,1269 assignments: &mut Vec<hir::Stmt<'hir>>,1270 ) -> &'hir hir::Pat<'hir> {1271 self.arena.alloc(self.destructure_assign_mut(lhs, eq_sign_span, assignments))1272 }12731274 fn destructure_assign_mut(1275 &mut self,1276 lhs: &Expr,1277 eq_sign_span: Span,1278 assignments: &mut Vec<hir::Stmt<'hir>>,1279 ) -> hir::Pat<'hir> {1280 match &lhs.kind {1281 // Underscore pattern.1282 ExprKind::Underscore => {1283 return self.pat_without_dbm(lhs.span, hir::PatKind::Wild);1284 }1285 // Slice patterns.1286 ExprKind::Array(elements) => {1287 let (pats, rest) =1288 self.destructure_sequence(elements, "slice", eq_sign_span, assignments);1289 let slice_pat = if let Some((i, span)) = rest {1290 let (before, after) = pats.split_at(i);1291 hir::PatKind::Slice(1292 before,1293 Some(self.arena.alloc(self.pat_without_dbm(span, hir::PatKind::Wild))),1294 after,1295 )1296 } else {1297 hir::PatKind::Slice(pats, None, &[])1298 };1299 return self.pat_without_dbm(lhs.span, slice_pat);1300 }1301 // Tuple structs.1302 ExprKind::Call(callee, args) => {1303 if let Some((qself, path)) = self.extract_tuple_struct_path(callee) {1304 let (pats, rest) = self.destructure_sequence(1305 args,1306 "tuple struct or variant",1307 eq_sign_span,1308 assignments,1309 );1310 let qpath = self.lower_qpath(1311 callee.id,1312 qself,1313 path,1314 ParamMode::Optional,1315 AllowReturnTypeNotation::No,1316 ImplTraitContext::Disallowed(ImplTraitPosition::Path),1317 None,1318 );1319 // Destructure like a tuple struct.1320 let tuple_struct_pat = hir::PatKind::TupleStruct(1321 qpath,1322 pats,1323 hir::DotDotPos::new(rest.map(|r| r.0)),1324 );1325 return self.pat_without_dbm(lhs.span, tuple_struct_pat);1326 }1327 }1328 // Unit structs and enum variants.1329 ExprKind::Path(..) => {1330 if let Some((qself, path)) = self.extract_unit_struct_path(lhs) {1331 let qpath = self.lower_qpath(1332 lhs.id,1333 qself,1334 path,1335 ParamMode::Optional,1336 AllowReturnTypeNotation::No,1337 ImplTraitContext::Disallowed(ImplTraitPosition::Path),1338 None,1339 );1340 // Destructure like a unit struct.1341 let unit_struct_pat = hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {1342 kind: hir::PatExprKind::Path(qpath),1343 hir_id: self.next_id(),1344 span: self.lower_span(lhs.span),1345 }));1346 return self.pat_without_dbm(lhs.span, unit_struct_pat);1347 }1348 }1349 // Structs.1350 ExprKind::Struct(se) => {1351 let field_pats = self.arena.alloc_from_iter(se.fields.iter().map(|f| {1352 let pat = self.destructure_assign(&f.expr, eq_sign_span, assignments);1353 hir::PatField {1354 hir_id: self.next_id(),1355 ident: self.lower_ident(f.ident),1356 pat,1357 is_shorthand: f.is_shorthand,1358 span: self.lower_span(f.span),1359 }1360 }));1361 let qpath = self.lower_qpath(1362 lhs.id,1363 &se.qself,1364 &se.path,1365 ParamMode::Optional,1366 AllowReturnTypeNotation::No,1367 ImplTraitContext::Disallowed(ImplTraitPosition::Path),1368 None,1369 );1370 let fields_omitted = match &se.rest {1371 StructRest::Base(e) => {1372 self.dcx().emit_err(FunctionalRecordUpdateDestructuringAssignment {1373 span: e.span,1374 });1375 Some(self.lower_span(e.span))1376 }1377 StructRest::Rest(span) => Some(self.lower_span(*span)),1378 StructRest::None | StructRest::NoneWithError(_) => None,1379 };1380 let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted);1381 return self.pat_without_dbm(lhs.span, struct_pat);1382 }1383 // Tuples.1384 ExprKind::Tup(elements) => {1385 let (pats, rest) =1386 self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);1387 let tuple_pat = hir::PatKind::Tuple(pats, hir::DotDotPos::new(rest.map(|r| r.0)));1388 return self.pat_without_dbm(lhs.span, tuple_pat);1389 }1390 ExprKind::Paren(e) => {1391 // We special-case `(..)` for consistency with patterns.1392 if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {1393 let tuple_pat = hir::PatKind::Tuple(&[], hir::DotDotPos::new(Some(0)));1394 return self.pat_without_dbm(lhs.span, tuple_pat);1395 } else {1396 return self.destructure_assign_mut(e, eq_sign_span, assignments);1397 }1398 }1399 _ => {}1400 }1401 // Treat all other cases as normal lvalue.1402 let ident = Ident::new(sym::lhs, self.lower_span(lhs.span));1403 let (pat, binding) = self.pat_ident_mut(lhs.span, ident);1404 let ident = self.expr_ident(lhs.span, ident, binding);1405 let assign =1406 hir::ExprKind::Assign(self.lower_expr(lhs), ident, self.lower_span(eq_sign_span));1407 let expr = self.expr(lhs.span, assign);1408 assignments.push(self.stmt_expr(lhs.span, expr));1409 pat1410 }14111412 /// Destructure a sequence of expressions occurring on the LHS of an assignment.1413 /// Such a sequence occurs in a tuple (struct)/slice.1414 /// Return a sequence of corresponding patterns, and the index and the span of `..` if it1415 /// exists.1416 /// Each sub-assignment is recorded in `assignments`.1417 fn destructure_sequence(1418 &mut self,1419 elements: &[Box<Expr>],1420 ctx: &str,1421 eq_sign_span: Span,1422 assignments: &mut Vec<hir::Stmt<'hir>>,1423 ) -> (&'hir [hir::Pat<'hir>], Option<(usize, Span)>) {1424 let mut rest = None;1425 let elements =1426 self.arena.alloc_from_iter(elements.iter().enumerate().filter_map(|(i, e)| {1427 // Check for `..` pattern.1428 if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {1429 if let Some((_, prev_span)) = rest {1430 self.ban_extra_rest_pat(e.span, prev_span, ctx);1431 } else {1432 rest = Some((i, e.span));1433 }1434 None1435 } else {1436 Some(self.destructure_assign_mut(e, eq_sign_span, assignments))1437 }1438 }));1439 (elements, rest)1440 }14411442 /// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.1443 fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {1444 let e1 = self.lower_expr_mut(e1);1445 let e2 = self.lower_expr_mut(e2);1446 let fn_path = self.make_lang_item_qpath(hir::LangItem::RangeInclusiveNew, span, None);1447 let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path)));1448 hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])1449 }14501451 fn lower_expr_range(1452 &mut self,1453 span: Span,1454 e1: Option<&Expr>,1455 e2: Option<&Expr>,1456 lims: RangeLimits,1457 ) -> hir::ExprKind<'hir> {1458 use rustc_ast::RangeLimits::*;14591460 let lang_item = match (e1, e2, lims) {1461 (None, None, HalfOpen) => hir::LangItem::RangeFull,1462 (Some(..), None, HalfOpen) => {1463 if self.tcx.features().new_range() {1464 hir::LangItem::RangeFromCopy1465 } else {1466 hir::LangItem::RangeFrom1467 }1468 }1469 (None, Some(..), HalfOpen) => hir::LangItem::RangeTo,1470 (Some(..), Some(..), HalfOpen) => {1471 if self.tcx.features().new_range() {1472 hir::LangItem::RangeCopy1473 } else {1474 hir::LangItem::Range1475 }1476 }1477 (None, Some(..), Closed) => {1478 if self.tcx.features().new_range() {1479 hir::LangItem::RangeToInclusiveCopy1480 } else {1481 hir::LangItem::RangeToInclusive1482 }1483 }1484 (Some(e1), Some(e2), Closed) => {1485 if self.tcx.features().new_range() {1486 hir::LangItem::RangeInclusiveCopy1487 } else {1488 return self.lower_expr_range_closed(span, e1, e2);1489 }1490 }1491 (start, None, Closed) => {1492 self.dcx().emit_err(InclusiveRangeWithNoEnd { span });1493 match start {1494 Some(..) => {1495 if self.tcx.features().new_range() {1496 hir::LangItem::RangeFromCopy1497 } else {1498 hir::LangItem::RangeFrom1499 }1500 }1501 None => hir::LangItem::RangeFull,1502 }1503 }1504 };15051506 let fields = self.arena.alloc_from_iter(1507 e1.iter()1508 .map(|e| (sym::start, e))1509 .chain(e2.iter().map(|e| {1510 (1511 if matches!(1512 lang_item,1513 hir::LangItem::RangeInclusiveCopy | hir::LangItem::RangeToInclusiveCopy1514 ) {1515 sym::last1516 } else {1517 sym::end1518 },1519 e,1520 )1521 }))1522 .map(|(s, e)| {1523 let span = self.lower_span(e.span);1524 let span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None);1525 let expr = self.lower_expr(e);1526 let ident = Ident::new(s, span);1527 self.expr_field(ident, expr, span)1528 }),1529 );15301531 hir::ExprKind::Struct(1532 self.arena.alloc(self.make_lang_item_qpath(lang_item, span, None)),1533 fields,1534 hir::StructTailExpr::None,1535 )1536 }15371538 // Record labelled expr's HirId so that we can retrieve it in `lower_jump_destination` without1539 // lowering node id again.1540 fn lower_label(1541 &mut self,1542 opt_label: Option<Label>,1543 dest_id: NodeId,1544 dest_hir_id: hir::HirId,1545 ) -> Option<Label> {1546 let label = opt_label?;1547 self.ident_and_label_to_local_id.insert(dest_id, dest_hir_id.local_id);1548 Some(Label { ident: self.lower_ident(label.ident) })1549 }15501551 fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {1552 let target_id = match destination {1553 Some((id, _)) => {1554 if let Some(loop_id) = self.owner.get_label_res(id) {1555 let local_id = self.ident_and_label_to_local_id[&loop_id];1556 let loop_hir_id = HirId { owner: self.current_hir_id_owner, local_id };1557 Ok(loop_hir_id)1558 } else {1559 Err(hir::LoopIdError::UnresolvedLabel)1560 }1561 }1562 None => {1563 self.loop_scope.map(|id| Ok(id)).unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))1564 }1565 };1566 let label = destination1567 .map(|(_, label)| label)1568 .map(|label| Label { ident: self.lower_ident(label.ident) });1569 hir::Destination { label, target_id }1570 }15711572 fn lower_jump_destination(&mut self, id: NodeId, opt_label: Option<Label>) -> hir::Destination {1573 if self.is_in_loop_condition && opt_label.is_none() {1574 hir::Destination {1575 label: None,1576 target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition),1577 }1578 } else {1579 self.lower_loop_destination(opt_label.map(|label| (id, label)))1580 }1581 }15821583 fn with_try_block_scope<T>(1584 &mut self,1585 scope: TryBlockScope,1586 f: impl FnOnce(&mut Self) -> T,1587 ) -> T {1588 let old_scope = mem::replace(&mut self.try_block_scope, scope);1589 let result = f(self);1590 self.try_block_scope = old_scope;1591 result1592 }15931594 fn with_loop_scope<T>(&mut self, loop_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T {1595 // We're no longer in the base loop's condition; we're in another loop.1596 let was_in_loop_condition = self.is_in_loop_condition;1597 self.is_in_loop_condition = false;15981599 let old_scope = self.loop_scope.replace(loop_id);1600 let result = f(self);1601 self.loop_scope = old_scope;16021603 self.is_in_loop_condition = was_in_loop_condition;16041605 result1606 }16071608 fn with_loop_condition_scope<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {1609 let was_in_loop_condition = self.is_in_loop_condition;1610 self.is_in_loop_condition = true;16111612 let result = f(self);16131614 self.is_in_loop_condition = was_in_loop_condition;16151616 result1617 }16181619 fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {1620 let hir_id = self.lower_node_id(f.id);1621 self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField);1622 hir::ExprField {1623 hir_id,1624 ident: self.lower_ident(f.ident),1625 expr: self.lower_expr(&f.expr),1626 span: self.lower_span(f.span),1627 is_shorthand: f.is_shorthand,1628 }1629 }16301631 fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {1632 let yielded =1633 opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));16341635 if !self.tcx.features().yield_expr()1636 && !self.tcx.features().coroutines()1637 && !self.tcx.features().gen_blocks()1638 {1639 rustc_session::errors::feature_err(1640 &self.tcx.sess,1641 sym::yield_expr,1642 span,1643 msg!("yield syntax is experimental"),1644 )1645 .emit();1646 }16471648 let is_async_gen = match self.coroutine_kind {1649 Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false,1650 Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,1651 Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {1652 // Lower to a block `{ EXPR; <error> }` so that the awaited expr1653 // is not accidentally orphaned.1654 let stmt_id = self.next_id();1655 let expr_err = self.expr(1656 yielded.span,1657 hir::ExprKind::Err(self.dcx().emit_err(AsyncCoroutinesNotSupported { span })),1658 );1659 return hir::ExprKind::Block(1660 self.block_all(1661 yielded.span,1662 arena_vec![self; hir::Stmt {1663 hir_id: stmt_id,1664 kind: hir::StmtKind::Semi(yielded),1665 span: yielded.span,1666 }],1667 Some(self.arena.alloc(expr_err)),1668 ),1669 None,1670 );1671 }1672 Some(hir::CoroutineKind::Coroutine(_)) => false,1673 None => {1674 let suggestion = self.current_item.map(|s| s.shrink_to_lo());1675 self.dcx().emit_err(YieldInClosure { span, suggestion });1676 self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable));16771678 false1679 }1680 };16811682 if is_async_gen {1683 // `yield $expr` is transformed into `task_context = yield async_gen_ready($expr)`.1684 // This ensures that we store our resumed `ResumeContext` correctly, and also that1685 // the apparent value of the `yield` expression is `()`.1686 let desugar_span = self.mark_span_with_reason(1687 DesugaringKind::Async,1688 span,1689 Some(Arc::clone(&self.allow_async_gen)),1690 );1691 let wrapped_yielded = self.expr_call_lang_item_fn(1692 desugar_span,1693 hir::LangItem::AsyncGenReady,1694 std::slice::from_ref(yielded),1695 );1696 let yield_expr = self.arena.alloc(1697 self.expr(span, hir::ExprKind::Yield(wrapped_yielded, hir::YieldSource::Yield)),1698 );16991700 let Some(task_context_hid) = self.task_context else {1701 unreachable!("use of `await` outside of an async context.");1702 };1703 let task_context_ident = Ident::with_dummy_span(sym::_task_context);1704 let lhs = self.expr_ident(desugar_span, task_context_ident, task_context_hid);17051706 hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span))1707 } else {1708 hir::ExprKind::Yield(yielded, hir::YieldSource::Yield)1709 }1710 }17111712 /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:1713 /// ```ignore (pseudo-rust)1714 /// {1715 /// let result = match IntoIterator::into_iter(<head>) {1716 /// mut iter => {1717 /// [opt_ident]: loop {1718 /// match Iterator::next(&mut iter) {1719 /// None => break,1720 /// Some(<pat>) => <body>,1721 /// };1722 /// }1723 /// }1724 /// };1725 /// result1726 /// }1727 /// ```1728 fn lower_expr_for(1729 &mut self,1730 e: &Expr,1731 pat: &Pat,1732 head: &Expr,1733 body: &Block,1734 opt_label: Option<Label>,1735 loop_kind: ForLoopKind,1736 ) -> hir::Expr<'hir> {1737 let head = self.lower_expr_mut(head);1738 let pat = self.lower_pat(pat);1739 let for_span =1740 self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None);1741 let for_ctxt = for_span.ctxt();17421743 // Try to point both the head and pat spans to their position in the for loop1744 // rather than inside a macro.1745 let head_span =1746 head.span.find_ancestor_in_same_ctxt(e.span).unwrap_or(head.span).with_ctxt(for_ctxt);1747 let pat_span =1748 pat.span.find_ancestor_in_same_ctxt(e.span).unwrap_or(pat.span).with_ctxt(for_ctxt);17491750 let loop_hir_id = self.lower_node_id(e.id);1751 let label = self.lower_label(opt_label, e.id, loop_hir_id);17521753 // `None => break`1754 let none_arm = {1755 let break_expr =1756 self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span));1757 let pat = self.pat_none(for_span);1758 self.arm(pat, break_expr, for_span)1759 };17601761 // Some(<pat>) => <body>,1762 let some_arm = {1763 let some_pat = self.pat_some(pat_span, pat);1764 let body_block =1765 self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false));1766 let body_expr = self.arena.alloc(self.expr_block(body_block));1767 self.arm(some_pat, body_expr, for_span)1768 };17691770 // `mut iter`1771 let iter = Ident::with_dummy_span(sym::iter);1772 let (iter_pat, iter_pat_nid) =1773 self.pat_ident_binding_mode(head_span, iter, hir::BindingMode::MUT);17741775 let match_expr = {1776 let iter = self.expr_ident(head_span, iter, iter_pat_nid);1777 let next_expr = match loop_kind {1778 ForLoopKind::For => {1779 // `Iterator::next(&mut iter)`1780 let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);1781 self.expr_call_lang_item_fn(1782 head_span,1783 hir::LangItem::IteratorNext,1784 arena_vec![self; ref_mut_iter],1785 )1786 }1787 ForLoopKind::ForAwait => {1788 // we'll generate `unsafe { Pin::new_unchecked(&mut iter) })` and then pass this1789 // to make_lowered_await with `FutureKind::AsyncIterator` which will generator1790 // calls to `poll_next`. In user code, this would probably be a call to1791 // `Pin::as_mut` but here it's easy enough to do `new_unchecked`.17921793 // `&mut iter`1794 let iter = self.expr_mut_addr_of(head_span, iter);1795 // `Pin::new_unchecked(...)`1796 let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(1797 head_span,1798 hir::LangItem::PinNewUnchecked,1799 arena_vec![self; iter],1800 ));1801 // `unsafe { ... }`1802 let iter = self.arena.alloc(self.expr_unsafe(head_span, iter));1803 let kind = self.make_lowered_await(head_span, iter, FutureKind::AsyncIterator);1804 self.arena.alloc(hir::Expr { hir_id: self.next_id(), kind, span: head_span })1805 }1806 };1807 let arms = arena_vec![self; none_arm, some_arm];18081809 // `match $next_expr { ... }`1810 self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)1811 };1812 let match_stmt = self.stmt_expr(for_span, match_expr);18131814 let loop_block = self.block_all(for_span, arena_vec![self; match_stmt], None);18151816 // `[opt_ident]: loop { ... }`1817 let kind = hir::ExprKind::Loop(1818 loop_block,1819 label,1820 hir::LoopSource::ForLoop,1821 self.lower_span(for_span.with_hi(head.span.hi())),1822 );1823 let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span });18241825 // `mut iter => { ... }`1826 let iter_arm = self.arm(iter_pat, loop_expr, for_span);18271828 let match_expr = match loop_kind {1829 ForLoopKind::For => {1830 // `::std::iter::IntoIterator::into_iter(<head>)`1831 let into_iter_expr = self.expr_call_lang_item_fn(1832 head_span,1833 hir::LangItem::IntoIterIntoIter,1834 arena_vec![self; head],1835 );18361837 self.arena.alloc(self.expr_match(1838 for_span,1839 into_iter_expr,1840 arena_vec![self; iter_arm],1841 hir::MatchSource::ForLoopDesugar,1842 ))1843 }1844 // `match into_async_iter(<head>) { ref mut iter => match unsafe { Pin::new_unchecked(iter) } { ... } }`1845 ForLoopKind::ForAwait => {1846 let iter_ident = iter;1847 let (async_iter_pat, async_iter_pat_id) =1848 self.pat_ident_binding_mode(head_span, iter_ident, hir::BindingMode::REF_MUT);1849 let iter = self.expr_ident_mut(head_span, iter_ident, async_iter_pat_id);1850 // `Pin::new_unchecked(...)`1851 let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(1852 head_span,1853 hir::LangItem::PinNewUnchecked,1854 arena_vec![self; iter],1855 ));1856 // `unsafe { ... }`1857 let iter = self.arena.alloc(self.expr_unsafe(head_span, iter));1858 let inner_match_expr = self.arena.alloc(self.expr_match(1859 for_span,1860 iter,1861 arena_vec![self; iter_arm],1862 hir::MatchSource::ForLoopDesugar,1863 ));18641865 // `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)`1866 let iter = self.expr_call_lang_item_fn(1867 head_span,1868 hir::LangItem::IntoAsyncIterIntoIter,1869 arena_vec![self; head],1870 );1871 let iter_arm = self.arm(async_iter_pat, inner_match_expr, for_span);1872 self.arena.alloc(self.expr_match(1873 for_span,1874 iter,1875 arena_vec![self; iter_arm],1876 hir::MatchSource::ForLoopDesugar,1877 ))1878 }1879 };18801881 // This is effectively `{ let _result = ...; _result }`.1882 // The construct was introduced in #21984 and is necessary to make sure that1883 // temporaries in the `head` expression are dropped and do not leak to the1884 // surrounding scope of the `match` since the `match` is not a terminating scope.1885 //1886 // Also, add the attributes to the outer returned expr node.1887 let expr = self.expr_drop_temps_mut(for_span, match_expr);1888 self.lower_attrs(expr.hir_id, &e.attrs, e.span, Target::from_expr(e));1889 expr1890 }18911892 /// Desugar `ExprKind::Try` from: `<expr>?` into:1893 /// ```ignore (pseudo-rust)1894 /// match Try::branch(<expr>) {1895 /// ControlFlow::Continue(val) => #[allow(unreachable_code)] val,,1896 /// ControlFlow::Break(residual) =>1897 /// #[allow(unreachable_code)]1898 /// // If there is an enclosing `try {...}`:1899 /// break 'catch_target Residual::into_try_type(residual),1900 /// // Otherwise:1901 /// return Try::from_residual(residual),1902 /// }1903 /// ```1904 fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> {1905 let unstable_span = self.mark_span_with_reason(1906 DesugaringKind::QuestionMark,1907 span,1908 Some(Arc::clone(&self.allow_try_trait)),1909 );1910 let try_span = self.tcx.sess.source_map().end_point(span);1911 let try_span = self.mark_span_with_reason(1912 DesugaringKind::QuestionMark,1913 try_span,1914 Some(Arc::clone(&self.allow_try_trait)),1915 );19161917 // `Try::branch(<expr>)`1918 let scrutinee = {1919 // expand <expr>1920 let sub_expr = self.lower_expr_mut(sub_expr);19211922 self.expr_call_lang_item_fn(1923 unstable_span,1924 hir::LangItem::TryTraitBranch,1925 arena_vec![self; sub_expr],1926 )1927 };19281929 let attrs: AttrVec = thin_vec![self.unreachable_code_attr(try_span)];19301931 // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`1932 let continue_arm = {1933 let val_ident = Ident::with_dummy_span(sym::val);1934 let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);1935 let val_expr = self.expr_ident(span, val_ident, val_pat_nid);1936 self.lower_attrs(val_expr.hir_id, &attrs, span, Target::Expression);1937 let continue_pat = self.pat_cf_continue(unstable_span, val_pat);1938 self.arm(continue_pat, val_expr, try_span)1939 };19401941 // `ControlFlow::Break(residual) =>1942 // #[allow(unreachable_code)]1943 // return Try::from_residual(residual),`1944 let break_arm = {1945 let residual_ident = Ident::with_dummy_span(sym::residual);1946 let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident);1947 let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid);19481949 let (constructor_item, target_id) = match self.try_block_scope {1950 TryBlockScope::Function => {1951 (hir::LangItem::TryTraitFromResidual, Err(hir::LoopIdError::OutsideLoopScope))1952 }1953 TryBlockScope::Homogeneous(block_id) => {1954 (hir::LangItem::ResidualIntoTryType, Ok(block_id))1955 }1956 TryBlockScope::Heterogeneous(block_id) => {1957 (hir::LangItem::TryTraitFromResidual, Ok(block_id))1958 }1959 };1960 let from_residual_expr = self.wrap_in_try_constructor(1961 constructor_item,1962 try_span,1963 self.arena.alloc(residual_expr),1964 unstable_span,1965 );1966 let ret_expr = if target_id.is_ok() {1967 self.arena.alloc(self.expr(1968 try_span,1969 hir::ExprKind::Break(1970 hir::Destination { label: None, target_id },1971 Some(from_residual_expr),1972 ),1973 ))1974 } else {1975 let ret_expr = self.checked_return(Some(from_residual_expr));1976 self.arena.alloc(self.expr(try_span, ret_expr))1977 };1978 self.lower_attrs(ret_expr.hir_id, &attrs, span, Target::Expression);19791980 let break_pat = self.pat_cf_break(try_span, residual_local);1981 self.arm(break_pat, ret_expr, try_span)1982 };19831984 hir::ExprKind::Match(1985 scrutinee,1986 arena_vec![self; break_arm, continue_arm],1987 hir::MatchSource::TryDesugar(scrutinee.hir_id),1988 )1989 }19901991 /// Desugar `ExprKind::Yeet` from: `do yeet <expr>` into:1992 /// ```ignore(illustrative)1993 /// // If there is an enclosing `try {...}`:1994 /// break 'catch_target FromResidual::from_residual(Yeet(residual));1995 /// // Otherwise:1996 /// return FromResidual::from_residual(Yeet(residual));1997 /// ```1998 /// But to simplify this, there's a `from_yeet` lang item function which1999 /// handles the combined `FromResidual::from_residual(Yeet(residual))`.2000 fn lower_expr_yeet(&mut self, span: Span, sub_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
Findings
✓ No findings reported for this file.