rustc_mir_build/thir/cx/
expr.rs

1use itertools::Itertools;
2use rustc_abi::{FIRST_VARIANT, FieldIdx};
3use rustc_ast::UnsafeBinderCastKind;
4use rustc_attr_data_structures::{AttributeKind, find_attr};
5use rustc_data_structures::stack::ensure_sufficient_stack;
6use rustc_hir as hir;
7use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
8use rustc_index::Idx;
9use rustc_middle::hir::place::{
10    Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
11};
12use rustc_middle::middle::region;
13use rustc_middle::mir::{self, AssignOp, BinOp, BorrowKind, UnOp};
14use rustc_middle::thir::*;
15use rustc_middle::ty::adjustment::{
16    Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCoercion,
17};
18use rustc_middle::ty::{
19    self, AdtKind, GenericArgs, InlineConstArgs, InlineConstArgsParts, ScalarInt, Ty, UpvarArgs,
20};
21use rustc_middle::{bug, span_bug};
22use rustc_span::{Span, sym};
23use tracing::{debug, info, instrument, trace};
24
25use crate::errors::*;
26use crate::thir::cx::ThirBuildCx;
27
28impl<'tcx> ThirBuildCx<'tcx> {
29    /// Create a THIR expression for the given HIR expression. This expands all
30    /// adjustments and directly adds the type information from the
31    /// `typeck_results`. See the [dev-guide] for more details.
32    ///
33    /// (The term "mirror" in this case does not refer to "flipped" or
34    /// "reversed".)
35    ///
36    /// [dev-guide]: https://rustc-dev-guide.rust-lang.org/thir.html
37    pub(crate) fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId {
38        // `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow.
39        ensure_sufficient_stack(|| self.mirror_expr_inner(expr))
40    }
41
42    pub(crate) fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> {
43        // `mirror_exprs` may also recurse deeply, so it needs protection from stack overflow.
44        // Note that we *could* forward to `mirror_expr` for that, but we can consolidate the
45        // overhead of stack growth by doing it outside the iteration.
46        ensure_sufficient_stack(|| exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect())
47    }
48
49    #[instrument(level = "trace", skip(self, hir_expr))]
50    pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId {
51        let expr_scope =
52            region::Scope { local_id: hir_expr.hir_id.local_id, data: region::ScopeData::Node };
53
54        trace!(?hir_expr.hir_id, ?hir_expr.span);
55
56        let mut expr = self.make_mirror_unadjusted(hir_expr);
57
58        trace!(?expr.ty);
59
60        // Now apply adjustments, if any.
61        if self.apply_adjustments {
62            for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
63                trace!(?expr, ?adjustment);
64                let span = expr.span;
65                expr = self.apply_adjustment(hir_expr, expr, adjustment, span);
66            }
67        }
68
69        trace!(?expr.ty, "after adjustments");
70
71        // Finally, wrap this up in the expr's scope.
72        expr = Expr {
73            temp_lifetime: expr.temp_lifetime,
74            ty: expr.ty,
75            span: hir_expr.span,
76            kind: ExprKind::Scope {
77                region_scope: expr_scope,
78                value: self.thir.exprs.push(expr),
79                lint_level: LintLevel::Explicit(hir_expr.hir_id),
80            },
81        };
82
83        // OK, all done!
84        self.thir.exprs.push(expr)
85    }
86
87    #[instrument(level = "trace", skip(self, expr, span))]
88    fn apply_adjustment(
89        &mut self,
90        hir_expr: &'tcx hir::Expr<'tcx>,
91        mut expr: Expr<'tcx>,
92        adjustment: &Adjustment<'tcx>,
93        mut span: Span,
94    ) -> Expr<'tcx> {
95        let Expr { temp_lifetime, .. } = expr;
96
97        // Adjust the span from the block, to the last expression of the
98        // block. This is a better span when returning a mutable reference
99        // with too short a lifetime. The error message will use the span
100        // from the assignment to the return place, which should only point
101        // at the returned value, not the entire function body.
102        //
103        // fn return_short_lived<'a>(x: &'a mut i32) -> &'static mut i32 {
104        //      x
105        //   // ^ error message points at this expression.
106        // }
107        let mut adjust_span = |expr: &mut Expr<'tcx>| {
108            if let ExprKind::Block { block } = expr.kind {
109                if let Some(last_expr) = self.thir[block].expr {
110                    span = self.thir[last_expr].span;
111                    expr.span = span;
112                }
113            }
114        };
115
116        let kind = match adjustment.kind {
117            Adjust::Pointer(cast) => {
118                if cast == PointerCoercion::Unsize {
119                    adjust_span(&mut expr);
120                }
121
122                let is_from_as_cast = if let hir::Node::Expr(hir::Expr {
123                    kind: hir::ExprKind::Cast(..),
124                    span: cast_span,
125                    ..
126                }) = self.tcx.parent_hir_node(hir_expr.hir_id)
127                {
128                    // Use the whole span of the `x as T` expression for the coercion.
129                    span = *cast_span;
130                    true
131                } else {
132                    false
133                };
134                ExprKind::PointerCoercion {
135                    cast,
136                    source: self.thir.exprs.push(expr),
137                    is_from_as_cast,
138                }
139            }
140            Adjust::NeverToAny if adjustment.target.is_never() => return expr,
141            Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) },
142            Adjust::Deref(None) => {
143                adjust_span(&mut expr);
144                ExprKind::Deref { arg: self.thir.exprs.push(expr) }
145            }
146            Adjust::Deref(Some(deref)) => {
147                // We don't need to do call adjust_span here since
148                // deref coercions always start with a built-in deref.
149                let call_def_id = deref.method_call(self.tcx);
150                let overloaded_callee =
151                    Ty::new_fn_def(self.tcx, call_def_id, self.tcx.mk_args(&[expr.ty.into()]));
152
153                expr = Expr {
154                    temp_lifetime,
155                    ty: Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, expr.ty, deref.mutbl),
156                    span,
157                    kind: ExprKind::Borrow {
158                        borrow_kind: deref.mutbl.to_borrow_kind(),
159                        arg: self.thir.exprs.push(expr),
160                    },
161                };
162
163                let expr = Box::new([self.thir.exprs.push(expr)]);
164
165                self.overloaded_place(
166                    hir_expr,
167                    adjustment.target,
168                    Some(overloaded_callee),
169                    expr,
170                    deref.span,
171                )
172            }
173            Adjust::Borrow(AutoBorrow::Ref(m)) => ExprKind::Borrow {
174                borrow_kind: m.to_borrow_kind(),
175                arg: self.thir.exprs.push(expr),
176            },
177            Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
178                ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) }
179            }
180            Adjust::ReborrowPin(mutbl) => {
181                debug!("apply ReborrowPin adjustment");
182                // Rewrite `$expr` as `Pin { __pointer: &(mut)? *($expr).__pointer }`
183
184                // We'll need these types later on
185                let pin_ty_args = match expr.ty.kind() {
186                    ty::Adt(_, args) => args,
187                    _ => bug!("ReborrowPin with non-Pin type"),
188                };
189                let pin_ty = pin_ty_args.iter().next().unwrap().expect_ty();
190                let ptr_target_ty = match pin_ty.kind() {
191                    ty::Ref(_, ty, _) => *ty,
192                    _ => bug!("ReborrowPin with non-Ref type"),
193                };
194
195                // pointer = ($expr).__pointer
196                let pointer_target = ExprKind::Field {
197                    lhs: self.thir.exprs.push(expr),
198                    variant_index: FIRST_VARIANT,
199                    name: FieldIdx::ZERO,
200                };
201                let arg = Expr { temp_lifetime, ty: pin_ty, span, kind: pointer_target };
202                let arg = self.thir.exprs.push(arg);
203
204                // arg = *pointer
205                let expr = ExprKind::Deref { arg };
206                let arg = self.thir.exprs.push(Expr {
207                    temp_lifetime,
208                    ty: ptr_target_ty,
209                    span,
210                    kind: expr,
211                });
212
213                // expr = &mut target
214                let borrow_kind = match mutbl {
215                    hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
216                    hir::Mutability::Not => BorrowKind::Shared,
217                };
218                let new_pin_target =
219                    Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, ptr_target_ty, mutbl);
220                let expr = self.thir.exprs.push(Expr {
221                    temp_lifetime,
222                    ty: new_pin_target,
223                    span,
224                    kind: ExprKind::Borrow { borrow_kind, arg },
225                });
226
227                // kind = Pin { __pointer: pointer }
228                let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, span);
229                let args = self.tcx.mk_args(&[new_pin_target.into()]);
230                let kind = ExprKind::Adt(Box::new(AdtExpr {
231                    adt_def: self.tcx.adt_def(pin_did),
232                    variant_index: FIRST_VARIANT,
233                    args,
234                    fields: Box::new([FieldExpr { name: FieldIdx::ZERO, expr }]),
235                    user_ty: None,
236                    base: AdtExprBase::None,
237                }));
238
239                debug!(?kind);
240                kind
241            }
242        };
243
244        Expr { temp_lifetime, ty: adjustment.target, span, kind }
245    }
246
247    /// Lowers a cast expression.
248    ///
249    /// Dealing with user type annotations is left to the caller.
250    fn mirror_expr_cast(
251        &mut self,
252        source: &'tcx hir::Expr<'tcx>,
253        temp_lifetime: TempLifetime,
254        span: Span,
255    ) -> ExprKind<'tcx> {
256        let tcx = self.tcx;
257
258        // Check to see if this cast is a "coercion cast", where the cast is actually done
259        // using a coercion (or is a no-op).
260        if self.typeck_results.is_coercion_cast(source.hir_id) {
261            // Convert the lexpr to a vexpr.
262            ExprKind::Use { source: self.mirror_expr(source) }
263        } else if self.typeck_results.expr_ty(source).is_ref() {
264            // Special cased so that we can type check that the element
265            // type of the source matches the pointed to type of the
266            // destination.
267            ExprKind::PointerCoercion {
268                source: self.mirror_expr(source),
269                cast: PointerCoercion::ArrayToPointer,
270                is_from_as_cast: true,
271            }
272        } else if let hir::ExprKind::Path(ref qpath) = source.kind
273            && let res = self.typeck_results.qpath_res(qpath, source.hir_id)
274            && let ty = self.typeck_results.node_type(source.hir_id)
275            && let ty::Adt(adt_def, args) = ty.kind()
276            && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res
277        {
278            // Check whether this is casting an enum variant discriminant.
279            // To prevent cycles, we refer to the discriminant initializer,
280            // which is always an integer and thus doesn't need to know the
281            // enum's layout (or its tag type) to compute it during const eval.
282            // Example:
283            // enum Foo {
284            //     A,
285            //     B = A as isize + 4,
286            // }
287            // The correct solution would be to add symbolic computations to miri,
288            // so we wouldn't have to compute and store the actual value
289
290            let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id);
291            let (discr_did, discr_offset) = adt_def.discriminant_def_for_variant(idx);
292
293            use rustc_middle::ty::util::IntTypeExt;
294            let ty = adt_def.repr().discr_type();
295            let discr_ty = ty.to_ty(tcx);
296
297            let size = tcx
298                .layout_of(self.typing_env.as_query_input(discr_ty))
299                .unwrap_or_else(|e| panic!("could not compute layout for {discr_ty:?}: {e:?}"))
300                .size;
301
302            let (lit, overflowing) = ScalarInt::truncate_from_uint(discr_offset as u128, size);
303            if overflowing {
304                // An erroneous enum with too many variants for its repr will emit E0081 and E0370
305                self.tcx.dcx().span_delayed_bug(
306                    source.span,
307                    "overflowing enum wasn't rejected by hir analysis",
308                );
309            }
310            let kind = ExprKind::NonHirLiteral { lit, user_ty: None };
311            let offset = self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind });
312
313            let source = match discr_did {
314                // in case we are offsetting from a computed discriminant
315                // and not the beginning of discriminants (which is always `0`)
316                Some(did) => {
317                    let kind = ExprKind::NamedConst { def_id: did, args, user_ty: None };
318                    let lhs =
319                        self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind });
320                    let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset };
321                    self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind: bin })
322                }
323                None => offset,
324            };
325
326            ExprKind::Cast { source }
327        } else {
328            // Default to `ExprKind::Cast` for all explicit casts.
329            // MIR building then picks the right MIR casts based on the types.
330            ExprKind::Cast { source: self.mirror_expr(source) }
331        }
332    }
333
334    #[instrument(level = "debug", skip(self), ret)]
335    fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
336        let tcx = self.tcx;
337        let expr_ty = self.typeck_results.expr_ty(expr);
338        let (temp_lifetime, backwards_incompatible) =
339            self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
340
341        let kind = match expr.kind {
342            // Here comes the interesting stuff:
343            hir::ExprKind::MethodCall(segment, receiver, args, fn_span) => {
344                // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
345                let expr = self.method_callee(expr, segment.ident.span, None);
346                info!("Using method span: {:?}", expr.span);
347                let args = std::iter::once(receiver)
348                    .chain(args.iter())
349                    .map(|expr| self.mirror_expr(expr))
350                    .collect();
351                ExprKind::Call {
352                    ty: expr.ty,
353                    fun: self.thir.exprs.push(expr),
354                    args,
355                    from_hir_call: true,
356                    fn_span,
357                }
358            }
359
360            hir::ExprKind::Call(fun, ref args) => {
361                if self.typeck_results.is_method_call(expr) {
362                    // The callee is something implementing Fn, FnMut, or FnOnce.
363                    // Find the actual method implementation being called and
364                    // build the appropriate UFCS call expression with the
365                    // callee-object as expr parameter.
366
367                    // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
368
369                    let method = self.method_callee(expr, fun.span, None);
370
371                    let arg_tys = args.iter().map(|e| self.typeck_results.expr_ty_adjusted(e));
372                    let tupled_args = Expr {
373                        ty: Ty::new_tup_from_iter(tcx, arg_tys),
374                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
375                        span: expr.span,
376                        kind: ExprKind::Tuple { fields: self.mirror_exprs(args) },
377                    };
378                    let tupled_args = self.thir.exprs.push(tupled_args);
379
380                    ExprKind::Call {
381                        ty: method.ty,
382                        fun: self.thir.exprs.push(method),
383                        args: Box::new([self.mirror_expr(fun), tupled_args]),
384                        from_hir_call: true,
385                        fn_span: expr.span,
386                    }
387                } else if let ty::FnDef(def_id, _) = self.typeck_results.expr_ty(fun).kind()
388                    && let Some(intrinsic) = self.tcx.intrinsic(def_id)
389                    && intrinsic.name == sym::box_new
390                {
391                    // We don't actually evaluate `fun` here, so make sure that doesn't miss any side-effects.
392                    if !matches!(fun.kind, hir::ExprKind::Path(_)) {
393                        span_bug!(
394                            expr.span,
395                            "`box_new` intrinsic can only be called via path expression"
396                        );
397                    }
398                    let value = &args[0];
399                    return Expr {
400                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
401                        ty: expr_ty,
402                        span: expr.span,
403                        kind: ExprKind::Box { value: self.mirror_expr(value) },
404                    };
405                } else {
406                    // Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
407                    let adt_data = if let hir::ExprKind::Path(ref qpath) = fun.kind
408                        && let Some(adt_def) = expr_ty.ty_adt_def()
409                    {
410                        match qpath {
411                            hir::QPath::Resolved(_, path) => match path.res {
412                                Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => {
413                                    Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id)))
414                                }
415                                Res::SelfCtor(..) => Some((adt_def, FIRST_VARIANT)),
416                                _ => None,
417                            },
418                            hir::QPath::TypeRelative(_ty, _) => {
419                                if let Some((DefKind::Ctor(_, CtorKind::Fn), ctor_id)) =
420                                    self.typeck_results.type_dependent_def(fun.hir_id)
421                                {
422                                    Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id)))
423                                } else {
424                                    None
425                                }
426                            }
427                            _ => None,
428                        }
429                    } else {
430                        None
431                    };
432                    if let Some((adt_def, index)) = adt_data {
433                        let node_args = self.typeck_results.node_args(fun.hir_id);
434                        let user_provided_types = self.typeck_results.user_provided_types();
435                        let user_ty =
436                            user_provided_types.get(fun.hir_id).copied().map(|mut u_ty| {
437                                if let ty::UserTypeKind::TypeOf(did, _) = &mut u_ty.value.kind {
438                                    *did = adt_def.did();
439                                }
440                                Box::new(u_ty)
441                            });
442                        debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty);
443
444                        let field_refs = args
445                            .iter()
446                            .enumerate()
447                            .map(|(idx, e)| FieldExpr {
448                                name: FieldIdx::new(idx),
449                                expr: self.mirror_expr(e),
450                            })
451                            .collect();
452                        ExprKind::Adt(Box::new(AdtExpr {
453                            adt_def,
454                            args: node_args,
455                            variant_index: index,
456                            fields: field_refs,
457                            user_ty,
458                            base: AdtExprBase::None,
459                        }))
460                    } else {
461                        ExprKind::Call {
462                            ty: self.typeck_results.node_type(fun.hir_id),
463                            fun: self.mirror_expr(fun),
464                            args: self.mirror_exprs(args),
465                            from_hir_call: true,
466                            fn_span: expr.span,
467                        }
468                    }
469                }
470            }
471
472            hir::ExprKind::Use(expr, span) => {
473                ExprKind::ByUse { expr: self.mirror_expr(expr), span }
474            }
475
476            hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, arg) => {
477                ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: self.mirror_expr(arg) }
478            }
479
480            hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutability, arg) => {
481                ExprKind::RawBorrow { mutability, arg: self.mirror_expr(arg) }
482            }
483
484            // Make `&pin mut $expr` and `&pin const $expr` into
485            // `Pin { __pointer: &mut { $expr } }` and `Pin { __pointer: &$expr }`.
486            hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg_expr) => match expr_ty.kind() {
487                &ty::Adt(adt_def, args) if tcx.is_lang_item(adt_def.did(), hir::LangItem::Pin) => {
488                    let ty = args.type_at(0);
489                    let arg_ty = self.typeck_results.expr_ty(arg_expr);
490                    let mut arg = self.mirror_expr(arg_expr);
491                    // For `&pin mut $place` where `$place` is not `Unpin`, move the place
492                    // `$place` to ensure it will not be used afterwards.
493                    if mutbl.is_mut() && !arg_ty.is_unpin(self.tcx, self.typing_env) {
494                        let block = self.thir.blocks.push(Block {
495                            targeted_by_break: false,
496                            region_scope: region::Scope {
497                                local_id: arg_expr.hir_id.local_id,
498                                data: region::ScopeData::Node,
499                            },
500                            span: arg_expr.span,
501                            stmts: Box::new([]),
502                            expr: Some(arg),
503                            safety_mode: BlockSafety::Safe,
504                        });
505                        let (temp_lifetime, backwards_incompatible) = self
506                            .rvalue_scopes
507                            .temporary_scope(self.region_scope_tree, arg_expr.hir_id.local_id);
508                        arg = self.thir.exprs.push(Expr {
509                            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
510                            ty: arg_ty,
511                            span: arg_expr.span,
512                            kind: ExprKind::Block { block },
513                        });
514                    }
515                    let expr = self.thir.exprs.push(Expr {
516                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
517                        ty,
518                        span: expr.span,
519                        kind: ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg },
520                    });
521                    ExprKind::Adt(Box::new(AdtExpr {
522                        adt_def,
523                        variant_index: FIRST_VARIANT,
524                        args,
525                        fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
526                        user_ty: None,
527                        base: AdtExprBase::None,
528                    }))
529                }
530                _ => span_bug!(expr.span, "unexpected type for pinned borrow: {:?}", expr_ty),
531            },
532
533            hir::ExprKind::Block(blk, _) => ExprKind::Block { block: self.mirror_block(blk) },
534
535            hir::ExprKind::Assign(lhs, rhs, _) => {
536                ExprKind::Assign { lhs: self.mirror_expr(lhs), rhs: self.mirror_expr(rhs) }
537            }
538
539            hir::ExprKind::AssignOp(op, lhs, rhs) => {
540                if self.typeck_results.is_method_call(expr) {
541                    let lhs = self.mirror_expr(lhs);
542                    let rhs = self.mirror_expr(rhs);
543                    self.overloaded_operator(expr, Box::new([lhs, rhs]))
544                } else {
545                    ExprKind::AssignOp {
546                        op: assign_op(op.node),
547                        lhs: self.mirror_expr(lhs),
548                        rhs: self.mirror_expr(rhs),
549                    }
550                }
551            }
552
553            hir::ExprKind::Lit(lit) => ExprKind::Literal { lit, neg: false },
554
555            hir::ExprKind::Binary(op, lhs, rhs) => {
556                if self.typeck_results.is_method_call(expr) {
557                    let lhs = self.mirror_expr(lhs);
558                    let rhs = self.mirror_expr(rhs);
559                    self.overloaded_operator(expr, Box::new([lhs, rhs]))
560                } else {
561                    match op.node {
562                        hir::BinOpKind::And => ExprKind::LogicalOp {
563                            op: LogicalOp::And,
564                            lhs: self.mirror_expr(lhs),
565                            rhs: self.mirror_expr(rhs),
566                        },
567                        hir::BinOpKind::Or => ExprKind::LogicalOp {
568                            op: LogicalOp::Or,
569                            lhs: self.mirror_expr(lhs),
570                            rhs: self.mirror_expr(rhs),
571                        },
572                        _ => {
573                            let op = bin_op(op.node);
574                            ExprKind::Binary {
575                                op,
576                                lhs: self.mirror_expr(lhs),
577                                rhs: self.mirror_expr(rhs),
578                            }
579                        }
580                    }
581                }
582            }
583
584            hir::ExprKind::Index(lhs, index, brackets_span) => {
585                if self.typeck_results.is_method_call(expr) {
586                    let lhs = self.mirror_expr(lhs);
587                    let index = self.mirror_expr(index);
588                    self.overloaded_place(
589                        expr,
590                        expr_ty,
591                        None,
592                        Box::new([lhs, index]),
593                        brackets_span,
594                    )
595                } else {
596                    ExprKind::Index { lhs: self.mirror_expr(lhs), index: self.mirror_expr(index) }
597                }
598            }
599
600            hir::ExprKind::Unary(hir::UnOp::Deref, arg) => {
601                if self.typeck_results.is_method_call(expr) {
602                    let arg = self.mirror_expr(arg);
603                    self.overloaded_place(expr, expr_ty, None, Box::new([arg]), expr.span)
604                } else {
605                    ExprKind::Deref { arg: self.mirror_expr(arg) }
606                }
607            }
608
609            hir::ExprKind::Unary(hir::UnOp::Not, arg) => {
610                if self.typeck_results.is_method_call(expr) {
611                    let arg = self.mirror_expr(arg);
612                    self.overloaded_operator(expr, Box::new([arg]))
613                } else {
614                    ExprKind::Unary { op: UnOp::Not, arg: self.mirror_expr(arg) }
615                }
616            }
617
618            hir::ExprKind::Unary(hir::UnOp::Neg, arg) => {
619                if self.typeck_results.is_method_call(expr) {
620                    let arg = self.mirror_expr(arg);
621                    self.overloaded_operator(expr, Box::new([arg]))
622                } else if let hir::ExprKind::Lit(lit) = arg.kind {
623                    ExprKind::Literal { lit, neg: true }
624                } else {
625                    ExprKind::Unary { op: UnOp::Neg, arg: self.mirror_expr(arg) }
626                }
627            }
628
629            hir::ExprKind::Struct(qpath, fields, ref base) => match expr_ty.kind() {
630                ty::Adt(adt, args) => match adt.adt_kind() {
631                    AdtKind::Struct | AdtKind::Union => {
632                        let user_provided_types = self.typeck_results.user_provided_types();
633                        let user_ty = user_provided_types.get(expr.hir_id).copied().map(Box::new);
634                        debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
635                        ExprKind::Adt(Box::new(AdtExpr {
636                            adt_def: *adt,
637                            variant_index: FIRST_VARIANT,
638                            args,
639                            user_ty,
640                            fields: self.field_refs(fields),
641                            base: match base {
642                                hir::StructTailExpr::Base(base) => AdtExprBase::Base(FruInfo {
643                                    base: self.mirror_expr(base),
644                                    field_types: self.typeck_results.fru_field_types()[expr.hir_id]
645                                        .iter()
646                                        .copied()
647                                        .collect(),
648                                }),
649                                hir::StructTailExpr::DefaultFields(_) => {
650                                    AdtExprBase::DefaultFields(
651                                        self.typeck_results.fru_field_types()[expr.hir_id]
652                                            .iter()
653                                            .copied()
654                                            .collect(),
655                                    )
656                                }
657                                hir::StructTailExpr::None => AdtExprBase::None,
658                            },
659                        }))
660                    }
661                    AdtKind::Enum => {
662                        let res = self.typeck_results.qpath_res(qpath, expr.hir_id);
663                        match res {
664                            Res::Def(DefKind::Variant, variant_id) => {
665                                assert!(matches!(
666                                    base,
667                                    hir::StructTailExpr::None
668                                        | hir::StructTailExpr::DefaultFields(_)
669                                ));
670
671                                let index = adt.variant_index_with_id(variant_id);
672                                let user_provided_types = self.typeck_results.user_provided_types();
673                                let user_ty =
674                                    user_provided_types.get(expr.hir_id).copied().map(Box::new);
675                                debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty);
676                                ExprKind::Adt(Box::new(AdtExpr {
677                                    adt_def: *adt,
678                                    variant_index: index,
679                                    args,
680                                    user_ty,
681                                    fields: self.field_refs(fields),
682                                    base: match base {
683                                        hir::StructTailExpr::DefaultFields(_) => {
684                                            AdtExprBase::DefaultFields(
685                                                self.typeck_results.fru_field_types()[expr.hir_id]
686                                                    .iter()
687                                                    .copied()
688                                                    .collect(),
689                                            )
690                                        }
691                                        hir::StructTailExpr::Base(base) => {
692                                            span_bug!(base.span, "unexpected res: {:?}", res);
693                                        }
694                                        hir::StructTailExpr::None => AdtExprBase::None,
695                                    },
696                                }))
697                            }
698                            _ => {
699                                span_bug!(expr.span, "unexpected res: {:?}", res);
700                            }
701                        }
702                    }
703                },
704                _ => {
705                    span_bug!(expr.span, "unexpected type for struct literal: {:?}", expr_ty);
706                }
707            },
708
709            hir::ExprKind::Closure(hir::Closure { .. }) => {
710                let closure_ty = self.typeck_results.expr_ty(expr);
711                let (def_id, args, movability) = match *closure_ty.kind() {
712                    ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args), None),
713                    ty::Coroutine(def_id, args) => {
714                        (def_id, UpvarArgs::Coroutine(args), Some(tcx.coroutine_movability(def_id)))
715                    }
716                    ty::CoroutineClosure(def_id, args) => {
717                        (def_id, UpvarArgs::CoroutineClosure(args), None)
718                    }
719                    _ => {
720                        span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
721                    }
722                };
723                let def_id = def_id.expect_local();
724
725                let upvars = self
726                    .tcx
727                    .closure_captures(def_id)
728                    .iter()
729                    .zip_eq(args.upvar_tys())
730                    .map(|(captured_place, ty)| {
731                        let upvars = self.capture_upvar(expr, captured_place, ty);
732                        self.thir.exprs.push(upvars)
733                    })
734                    .collect();
735
736                // Convert the closure fake reads, if any, from hir `Place` to ExprRef
737                let fake_reads = match self.typeck_results.closure_fake_reads.get(&def_id) {
738                    Some(fake_reads) => fake_reads
739                        .iter()
740                        .map(|(place, cause, hir_id)| {
741                            let expr = self.convert_captured_hir_place(expr, place.clone());
742                            (self.thir.exprs.push(expr), *cause, *hir_id)
743                        })
744                        .collect(),
745                    None => Vec::new(),
746                };
747
748                ExprKind::Closure(Box::new(ClosureExpr {
749                    closure_id: def_id,
750                    args,
751                    upvars,
752                    movability,
753                    fake_reads,
754                }))
755            }
756
757            hir::ExprKind::Path(ref qpath) => {
758                let res = self.typeck_results.qpath_res(qpath, expr.hir_id);
759                self.convert_path_expr(expr, res)
760            }
761
762            hir::ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(Box::new(InlineAsmExpr {
763                asm_macro: asm.asm_macro,
764                template: asm.template,
765                operands: asm
766                    .operands
767                    .iter()
768                    .map(|(op, _op_sp)| match *op {
769                        hir::InlineAsmOperand::In { reg, expr } => {
770                            InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) }
771                        }
772                        hir::InlineAsmOperand::Out { reg, late, ref expr } => {
773                            InlineAsmOperand::Out {
774                                reg,
775                                late,
776                                expr: expr.map(|expr| self.mirror_expr(expr)),
777                            }
778                        }
779                        hir::InlineAsmOperand::InOut { reg, late, expr } => {
780                            InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) }
781                        }
782                        hir::InlineAsmOperand::SplitInOut { reg, late, in_expr, ref out_expr } => {
783                            InlineAsmOperand::SplitInOut {
784                                reg,
785                                late,
786                                in_expr: self.mirror_expr(in_expr),
787                                out_expr: out_expr.map(|expr| self.mirror_expr(expr)),
788                            }
789                        }
790                        hir::InlineAsmOperand::Const { ref anon_const } => {
791                            let ty = self.typeck_results.node_type(anon_const.hir_id);
792                            let did = anon_const.def_id.to_def_id();
793                            let typeck_root_def_id = tcx.typeck_root_def_id(did);
794                            let parent_args = tcx.erase_regions(GenericArgs::identity_for_item(
795                                tcx,
796                                typeck_root_def_id,
797                            ));
798                            let args =
799                                InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty })
800                                    .args;
801
802                            let uneval = mir::UnevaluatedConst::new(did, args);
803                            let value = mir::Const::Unevaluated(uneval, ty);
804                            InlineAsmOperand::Const { value, span: tcx.def_span(did) }
805                        }
806                        hir::InlineAsmOperand::SymFn { expr } => {
807                            InlineAsmOperand::SymFn { value: self.mirror_expr(expr) }
808                        }
809                        hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
810                            InlineAsmOperand::SymStatic { def_id }
811                        }
812                        hir::InlineAsmOperand::Label { block } => {
813                            InlineAsmOperand::Label { block: self.mirror_block(block) }
814                        }
815                    })
816                    .collect(),
817                options: asm.options,
818                line_spans: asm.line_spans,
819            })),
820
821            hir::ExprKind::OffsetOf(_, _) => {
822                let data = self.typeck_results.offset_of_data();
823                let &(container, ref indices) = data.get(expr.hir_id).unwrap();
824                let fields = tcx.mk_offset_of_from_iter(indices.iter().copied());
825
826                ExprKind::OffsetOf { container, fields }
827            }
828
829            hir::ExprKind::ConstBlock(ref anon_const) => {
830                let ty = self.typeck_results.node_type(anon_const.hir_id);
831                let did = anon_const.def_id.to_def_id();
832                let typeck_root_def_id = tcx.typeck_root_def_id(did);
833                let parent_args =
834                    tcx.erase_regions(GenericArgs::identity_for_item(tcx, typeck_root_def_id));
835                let args = InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty }).args;
836
837                ExprKind::ConstBlock { did, args }
838            }
839            // Now comes the rote stuff:
840            hir::ExprKind::Repeat(v, _) => {
841                let ty = self.typeck_results.expr_ty(expr);
842                let ty::Array(_, count) = ty.kind() else {
843                    span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty);
844                };
845
846                ExprKind::Repeat { value: self.mirror_expr(v), count: *count }
847            }
848            hir::ExprKind::Ret(v) => ExprKind::Return { value: v.map(|v| self.mirror_expr(v)) },
849            hir::ExprKind::Become(call) => ExprKind::Become { value: self.mirror_expr(call) },
850            hir::ExprKind::Break(dest, ref value) => {
851                if find_attr!(self.tcx.hir_attrs(expr.hir_id), AttributeKind::ConstContinue(_)) {
852                    match dest.target_id {
853                        Ok(target_id) => {
854                            let Some(value) = value else {
855                                let span = expr.span;
856                                self.tcx.dcx().emit_fatal(ConstContinueMissingValue { span })
857                            };
858
859                            ExprKind::ConstContinue {
860                                label: region::Scope {
861                                    local_id: target_id.local_id,
862                                    data: region::ScopeData::Node,
863                                },
864                                value: self.mirror_expr(value),
865                            }
866                        }
867                        Err(err) => bug!("invalid loop id for break: {}", err),
868                    }
869                } else {
870                    match dest.target_id {
871                        Ok(target_id) => ExprKind::Break {
872                            label: region::Scope {
873                                local_id: target_id.local_id,
874                                data: region::ScopeData::Node,
875                            },
876                            value: value.map(|value| self.mirror_expr(value)),
877                        },
878                        Err(err) => bug!("invalid loop id for break: {}", err),
879                    }
880                }
881            }
882            hir::ExprKind::Continue(dest) => match dest.target_id {
883                Ok(loop_id) => ExprKind::Continue {
884                    label: region::Scope {
885                        local_id: loop_id.local_id,
886                        data: region::ScopeData::Node,
887                    },
888                },
889                Err(err) => bug!("invalid loop id for continue: {}", err),
890            },
891            hir::ExprKind::Let(let_expr) => ExprKind::Let {
892                expr: self.mirror_expr(let_expr.init),
893                pat: self.pattern_from_hir(let_expr.pat),
894            },
895            hir::ExprKind::If(cond, then, else_opt) => ExprKind::If {
896                if_then_scope: region::Scope {
897                    local_id: then.hir_id.local_id,
898                    data: {
899                        if expr.span.at_least_rust_2024() {
900                            region::ScopeData::IfThenRescope
901                        } else {
902                            region::ScopeData::IfThen
903                        }
904                    },
905                },
906                cond: self.mirror_expr(cond),
907                then: self.mirror_expr(then),
908                else_opt: else_opt.map(|el| self.mirror_expr(el)),
909            },
910            hir::ExprKind::Match(discr, arms, match_source) => ExprKind::Match {
911                scrutinee: self.mirror_expr(discr),
912                arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
913                match_source,
914            },
915            hir::ExprKind::Loop(body, ..) => {
916                if find_attr!(self.tcx.hir_attrs(expr.hir_id), AttributeKind::LoopMatch(_)) {
917                    let dcx = self.tcx.dcx();
918
919                    // Accept either `state = expr` or `state = expr;`.
920                    let loop_body_expr = match body.stmts {
921                        [] => match body.expr {
922                            Some(expr) => expr,
923                            None => dcx.emit_fatal(LoopMatchMissingAssignment { span: body.span }),
924                        },
925                        [single] if body.expr.is_none() => match single.kind {
926                            hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => expr,
927                            _ => dcx.emit_fatal(LoopMatchMissingAssignment { span: body.span }),
928                        },
929                        [first @ last] | [first, .., last] => dcx
930                            .emit_fatal(LoopMatchBadStatements { span: first.span.to(last.span) }),
931                    };
932
933                    let hir::ExprKind::Assign(state, rhs_expr, _) = loop_body_expr.kind else {
934                        dcx.emit_fatal(LoopMatchMissingAssignment { span: loop_body_expr.span })
935                    };
936
937                    let hir::ExprKind::Block(block_body, _) = rhs_expr.kind else {
938                        dcx.emit_fatal(LoopMatchBadRhs { span: rhs_expr.span })
939                    };
940
941                    // The labeled block should contain one match expression, but defining items is
942                    // allowed.
943                    for stmt in block_body.stmts {
944                        if !matches!(stmt.kind, rustc_hir::StmtKind::Item(_)) {
945                            dcx.emit_fatal(LoopMatchBadStatements { span: stmt.span })
946                        }
947                    }
948
949                    let Some(block_body_expr) = block_body.expr else {
950                        dcx.emit_fatal(LoopMatchBadRhs { span: block_body.span })
951                    };
952
953                    let hir::ExprKind::Match(scrutinee, arms, _match_source) = block_body_expr.kind
954                    else {
955                        dcx.emit_fatal(LoopMatchBadRhs { span: block_body_expr.span })
956                    };
957
958                    fn local(expr: &rustc_hir::Expr<'_>) -> Option<hir::HirId> {
959                        if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind {
960                            if let Res::Local(hir_id) = path.res {
961                                return Some(hir_id);
962                            }
963                        }
964
965                        None
966                    }
967
968                    let Some(scrutinee_hir_id) = local(scrutinee) else {
969                        dcx.emit_fatal(LoopMatchInvalidMatch { span: scrutinee.span })
970                    };
971
972                    if local(state) != Some(scrutinee_hir_id) {
973                        dcx.emit_fatal(LoopMatchInvalidUpdate {
974                            scrutinee: scrutinee.span,
975                            lhs: state.span,
976                        })
977                    }
978
979                    ExprKind::LoopMatch {
980                        state: self.mirror_expr(state),
981                        region_scope: region::Scope {
982                            local_id: block_body.hir_id.local_id,
983                            data: region::ScopeData::Node,
984                        },
985
986                        arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
987                        match_span: block_body_expr.span,
988                    }
989                } else {
990                    let block_ty = self.typeck_results.node_type(body.hir_id);
991                    let (temp_lifetime, backwards_incompatible) = self
992                        .rvalue_scopes
993                        .temporary_scope(self.region_scope_tree, body.hir_id.local_id);
994                    let block = self.mirror_block(body);
995                    let body = self.thir.exprs.push(Expr {
996                        ty: block_ty,
997                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
998                        span: self.thir[block].span,
999                        kind: ExprKind::Block { block },
1000                    });
1001                    ExprKind::Loop { body }
1002                }
1003            }
1004            hir::ExprKind::Field(source, ..) => ExprKind::Field {
1005                lhs: self.mirror_expr(source),
1006                variant_index: FIRST_VARIANT,
1007                name: self.typeck_results.field_index(expr.hir_id),
1008            },
1009            hir::ExprKind::Cast(source, cast_ty) => {
1010                // Check for a user-given type annotation on this `cast`
1011                let user_provided_types = self.typeck_results.user_provided_types();
1012                let user_ty = user_provided_types.get(cast_ty.hir_id);
1013
1014                debug!(
1015                    "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}",
1016                    expr, cast_ty.hir_id, user_ty,
1017                );
1018
1019                let cast = self.mirror_expr_cast(
1020                    source,
1021                    TempLifetime { temp_lifetime, backwards_incompatible },
1022                    expr.span,
1023                );
1024
1025                if let Some(user_ty) = user_ty {
1026                    // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
1027                    //       inefficient, revisit this when performance becomes an issue.
1028                    let cast_expr = self.thir.exprs.push(Expr {
1029                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
1030                        ty: expr_ty,
1031                        span: expr.span,
1032                        kind: cast,
1033                    });
1034                    debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty);
1035
1036                    ExprKind::ValueTypeAscription {
1037                        source: cast_expr,
1038                        user_ty: Some(Box::new(*user_ty)),
1039                        user_ty_span: cast_ty.span,
1040                    }
1041                } else {
1042                    cast
1043                }
1044            }
1045            hir::ExprKind::Type(source, ty) => {
1046                let user_provided_types = self.typeck_results.user_provided_types();
1047                let user_ty = user_provided_types.get(ty.hir_id).copied().map(Box::new);
1048                debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
1049                let mirrored = self.mirror_expr(source);
1050                if source.is_syntactic_place_expr() {
1051                    ExprKind::PlaceTypeAscription {
1052                        source: mirrored,
1053                        user_ty,
1054                        user_ty_span: ty.span,
1055                    }
1056                } else {
1057                    ExprKind::ValueTypeAscription {
1058                        source: mirrored,
1059                        user_ty,
1060                        user_ty_span: ty.span,
1061                    }
1062                }
1063            }
1064
1065            hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Unwrap, source, _ty) => {
1066                // FIXME(unsafe_binders): Take into account the ascribed type, too.
1067                let mirrored = self.mirror_expr(source);
1068                if source.is_syntactic_place_expr() {
1069                    ExprKind::PlaceUnwrapUnsafeBinder { source: mirrored }
1070                } else {
1071                    ExprKind::ValueUnwrapUnsafeBinder { source: mirrored }
1072                }
1073            }
1074            hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Wrap, source, _ty) => {
1075                // FIXME(unsafe_binders): Take into account the ascribed type, too.
1076                let mirrored = self.mirror_expr(source);
1077                ExprKind::WrapUnsafeBinder { source: mirrored }
1078            }
1079
1080            hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },
1081            hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) },
1082            hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) },
1083
1084            hir::ExprKind::Yield(v, _) => ExprKind::Yield { value: self.mirror_expr(v) },
1085            hir::ExprKind::Err(_) => unreachable!("cannot lower a `hir::ExprKind::Err` to THIR"),
1086        };
1087
1088        Expr {
1089            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
1090            ty: expr_ty,
1091            span: expr.span,
1092            kind,
1093        }
1094    }
1095
1096    fn user_args_applied_to_res(
1097        &mut self,
1098        hir_id: hir::HirId,
1099        res: Res,
1100    ) -> Option<Box<ty::CanonicalUserType<'tcx>>> {
1101        debug!("user_args_applied_to_res: res={:?}", res);
1102        let user_provided_type = match res {
1103            // A reference to something callable -- e.g., a fn, method, or
1104            // a tuple-struct or tuple-variant. This has the type of a
1105            // `Fn` but with the user-given generic parameters.
1106            Res::Def(DefKind::Fn, _)
1107            | Res::Def(DefKind::AssocFn, _)
1108            | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
1109            | Res::Def(DefKind::Const, _)
1110            | Res::Def(DefKind::AssocConst, _) => {
1111                self.typeck_results.user_provided_types().get(hir_id).copied().map(Box::new)
1112            }
1113
1114            // A unit struct/variant which is used as a value (e.g.,
1115            // `None`). This has the type of the enum/struct that defines
1116            // this variant -- but with the generic parameters given by the
1117            // user.
1118            Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => {
1119                self.user_args_applied_to_ty_of_hir_id(hir_id).map(Box::new)
1120            }
1121
1122            // `Self` is used in expression as a tuple struct constructor or a unit struct constructor
1123            Res::SelfCtor(_) => self.user_args_applied_to_ty_of_hir_id(hir_id).map(Box::new),
1124
1125            _ => bug!("user_args_applied_to_res: unexpected res {:?} at {:?}", res, hir_id),
1126        };
1127        debug!("user_args_applied_to_res: user_provided_type={:?}", user_provided_type);
1128        user_provided_type
1129    }
1130
1131    fn method_callee(
1132        &mut self,
1133        expr: &hir::Expr<'_>,
1134        span: Span,
1135        overloaded_callee: Option<Ty<'tcx>>,
1136    ) -> Expr<'tcx> {
1137        let (temp_lifetime, backwards_incompatible) =
1138            self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
1139        let (ty, user_ty) = match overloaded_callee {
1140            Some(fn_def) => (fn_def, None),
1141            None => {
1142                let (kind, def_id) =
1143                    self.typeck_results.type_dependent_def(expr.hir_id).unwrap_or_else(|| {
1144                        span_bug!(expr.span, "no type-dependent def for method callee")
1145                    });
1146                let user_ty = self.user_args_applied_to_res(expr.hir_id, Res::Def(kind, def_id));
1147                debug!("method_callee: user_ty={:?}", user_ty);
1148                (
1149                    Ty::new_fn_def(self.tcx, def_id, self.typeck_results.node_args(expr.hir_id)),
1150                    user_ty,
1151                )
1152            }
1153        };
1154        Expr {
1155            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
1156            ty,
1157            span,
1158            kind: ExprKind::ZstLiteral { user_ty },
1159        }
1160    }
1161
1162    fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId {
1163        let arm = Arm {
1164            pattern: self.pattern_from_hir(&arm.pat),
1165            guard: arm.guard.as_ref().map(|g| self.mirror_expr(g)),
1166            body: self.mirror_expr(arm.body),
1167            lint_level: LintLevel::Explicit(arm.hir_id),
1168            scope: region::Scope { local_id: arm.hir_id.local_id, data: region::ScopeData::Node },
1169            span: arm.span,
1170        };
1171        self.thir.arms.push(arm)
1172    }
1173
1174    fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKind<'tcx> {
1175        let args = self.typeck_results.node_args(expr.hir_id);
1176        match res {
1177            // A regular function, constructor function or a constant.
1178            Res::Def(DefKind::Fn, _)
1179            | Res::Def(DefKind::AssocFn, _)
1180            | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
1181            | Res::SelfCtor(_) => {
1182                let user_ty = self.user_args_applied_to_res(expr.hir_id, res);
1183                ExprKind::ZstLiteral { user_ty }
1184            }
1185
1186            Res::Def(DefKind::ConstParam, def_id) => {
1187                let hir_id = self.tcx.local_def_id_to_hir_id(def_id.expect_local());
1188                let generics = self.tcx.generics_of(hir_id.owner);
1189                let Some(&index) = generics.param_def_id_to_index.get(&def_id) else {
1190                    span_bug!(
1191                        expr.span,
1192                        "Should have already errored about late bound consts: {def_id:?}"
1193                    );
1194                };
1195                let name = self.tcx.hir_name(hir_id);
1196                let param = ty::ParamConst::new(index, name);
1197
1198                ExprKind::ConstParam { param, def_id }
1199            }
1200
1201            Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
1202                let user_ty = self.user_args_applied_to_res(expr.hir_id, res);
1203                ExprKind::NamedConst { def_id, args, user_ty }
1204            }
1205
1206            Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => {
1207                let user_provided_types = self.typeck_results.user_provided_types();
1208                let user_ty = user_provided_types.get(expr.hir_id).copied().map(Box::new);
1209                debug!("convert_path_expr: user_ty={:?}", user_ty);
1210                let ty = self.typeck_results.node_type(expr.hir_id);
1211                match ty.kind() {
1212                    // A unit struct/variant which is used as a value.
1213                    // We return a completely different ExprKind here to account for this special case.
1214                    ty::Adt(adt_def, args) => ExprKind::Adt(Box::new(AdtExpr {
1215                        adt_def: *adt_def,
1216                        variant_index: adt_def.variant_index_with_ctor_id(def_id),
1217                        args,
1218                        user_ty,
1219                        fields: Box::new([]),
1220                        base: AdtExprBase::None,
1221                    })),
1222                    _ => bug!("unexpected ty: {:?}", ty),
1223                }
1224            }
1225
1226            // A source Rust `path::to::STATIC` is a place expr like *&ident is.
1227            // In THIR, we make them exactly equivalent by inserting the implied *& or *&raw,
1228            // but distinguish between &STATIC and &THREAD_LOCAL as they have different semantics
1229            Res::Def(DefKind::Static { .. }, id) => {
1230                // this is &raw for extern static or static mut, and & for other statics
1231                let ty = self.tcx.static_ptr_ty(id, self.typing_env);
1232                let (temp_lifetime, backwards_incompatible) = self
1233                    .rvalue_scopes
1234                    .temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
1235                let kind = if self.tcx.is_thread_local_static(id) {
1236                    ExprKind::ThreadLocalRef(id)
1237                } else {
1238                    let alloc_id = self.tcx.reserve_and_set_static_alloc(id);
1239                    ExprKind::StaticRef { alloc_id, ty, def_id: id }
1240                };
1241                ExprKind::Deref {
1242                    arg: self.thir.exprs.push(Expr {
1243                        ty,
1244                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
1245                        span: expr.span,
1246                        kind,
1247                    }),
1248                }
1249            }
1250
1251            Res::Local(var_hir_id) => self.convert_var(var_hir_id),
1252
1253            _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res),
1254        }
1255    }
1256
1257    fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'tcx> {
1258        // We want upvars here not captures.
1259        // Captures will be handled in MIR.
1260        let is_upvar = self
1261            .tcx
1262            .upvars_mentioned(self.body_owner)
1263            .is_some_and(|upvars| upvars.contains_key(&var_hir_id));
1264
1265        debug!(
1266            "convert_var({:?}): is_upvar={}, body_owner={:?}",
1267            var_hir_id, is_upvar, self.body_owner
1268        );
1269
1270        if is_upvar {
1271            ExprKind::UpvarRef {
1272                closure_def_id: self.body_owner,
1273                var_hir_id: LocalVarId(var_hir_id),
1274            }
1275        } else {
1276            ExprKind::VarRef { id: LocalVarId(var_hir_id) }
1277        }
1278    }
1279
1280    fn overloaded_operator(
1281        &mut self,
1282        expr: &'tcx hir::Expr<'tcx>,
1283        args: Box<[ExprId]>,
1284    ) -> ExprKind<'tcx> {
1285        let fun = self.method_callee(expr, expr.span, None);
1286        let fun = self.thir.exprs.push(fun);
1287        ExprKind::Call {
1288            ty: self.thir[fun].ty,
1289            fun,
1290            args,
1291            from_hir_call: false,
1292            fn_span: expr.span,
1293        }
1294    }
1295
1296    fn overloaded_place(
1297        &mut self,
1298        expr: &'tcx hir::Expr<'tcx>,
1299        place_ty: Ty<'tcx>,
1300        overloaded_callee: Option<Ty<'tcx>>,
1301        args: Box<[ExprId]>,
1302        span: Span,
1303    ) -> ExprKind<'tcx> {
1304        // For an overloaded *x or x[y] expression of type T, the method
1305        // call returns an &T and we must add the deref so that the types
1306        // line up (this is because `*x` and `x[y]` represent places):
1307
1308        // Reconstruct the output assuming it's a reference with the
1309        // same region and mutability as the receiver. This holds for
1310        // `Deref(Mut)::deref(_mut)` and `Index(Mut)::index(_mut)`.
1311        let ty::Ref(region, _, mutbl) = *self.thir[args[0]].ty.kind() else {
1312            span_bug!(span, "overloaded_place: receiver is not a reference");
1313        };
1314        let ref_ty = Ty::new_ref(self.tcx, region, place_ty, mutbl);
1315
1316        // construct the complete expression `foo()` for the overloaded call,
1317        // which will yield the &T type
1318        let (temp_lifetime, backwards_incompatible) =
1319            self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
1320        let fun = self.method_callee(expr, span, overloaded_callee);
1321        let fun = self.thir.exprs.push(fun);
1322        let fun_ty = self.thir[fun].ty;
1323        let ref_expr = self.thir.exprs.push(Expr {
1324            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
1325            ty: ref_ty,
1326            span,
1327            kind: ExprKind::Call { ty: fun_ty, fun, args, from_hir_call: false, fn_span: span },
1328        });
1329
1330        // construct and return a deref wrapper `*foo()`
1331        ExprKind::Deref { arg: ref_expr }
1332    }
1333
1334    fn convert_captured_hir_place(
1335        &mut self,
1336        closure_expr: &'tcx hir::Expr<'tcx>,
1337        place: HirPlace<'tcx>,
1338    ) -> Expr<'tcx> {
1339        let (temp_lifetime, backwards_incompatible) = self
1340            .rvalue_scopes
1341            .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
1342        let var_ty = place.base_ty;
1343
1344        // The result of capture analysis in `rustc_hir_typeck/src/upvar.rs` represents a captured path
1345        // as it's seen for use within the closure and not at the time of closure creation.
1346        //
1347        // That is we see expect to see it start from a captured upvar and not something that is local
1348        // to the closure's parent.
1349        let var_hir_id = match place.base {
1350            HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
1351            base => bug!("Expected an upvar, found {:?}", base),
1352        };
1353
1354        let mut captured_place_expr = Expr {
1355            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
1356            ty: var_ty,
1357            span: closure_expr.span,
1358            kind: self.convert_var(var_hir_id),
1359        };
1360
1361        for proj in place.projections.iter() {
1362            let kind = match proj.kind {
1363                HirProjectionKind::Deref => {
1364                    ExprKind::Deref { arg: self.thir.exprs.push(captured_place_expr) }
1365                }
1366                HirProjectionKind::Field(field, variant_index) => ExprKind::Field {
1367                    lhs: self.thir.exprs.push(captured_place_expr),
1368                    variant_index,
1369                    name: field,
1370                },
1371                HirProjectionKind::OpaqueCast => {
1372                    ExprKind::Use { source: self.thir.exprs.push(captured_place_expr) }
1373                }
1374                HirProjectionKind::UnwrapUnsafeBinder => ExprKind::PlaceUnwrapUnsafeBinder {
1375                    source: self.thir.exprs.push(captured_place_expr),
1376                },
1377                HirProjectionKind::Index | HirProjectionKind::Subslice => {
1378                    // We don't capture these projections, so we can ignore them here
1379                    continue;
1380                }
1381            };
1382
1383            captured_place_expr = Expr {
1384                temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
1385                ty: proj.ty,
1386                span: closure_expr.span,
1387                kind,
1388            };
1389        }
1390
1391        captured_place_expr
1392    }
1393
1394    fn capture_upvar(
1395        &mut self,
1396        closure_expr: &'tcx hir::Expr<'tcx>,
1397        captured_place: &'tcx ty::CapturedPlace<'tcx>,
1398        upvar_ty: Ty<'tcx>,
1399    ) -> Expr<'tcx> {
1400        let upvar_capture = captured_place.info.capture_kind;
1401        let captured_place_expr =
1402            self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
1403        let (temp_lifetime, backwards_incompatible) = self
1404            .rvalue_scopes
1405            .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
1406
1407        match upvar_capture {
1408            ty::UpvarCapture::ByValue => captured_place_expr,
1409            ty::UpvarCapture::ByUse => {
1410                let span = captured_place_expr.span;
1411                let expr_id = self.thir.exprs.push(captured_place_expr);
1412
1413                Expr {
1414                    temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
1415                    ty: upvar_ty,
1416                    span: closure_expr.span,
1417                    kind: ExprKind::ByUse { expr: expr_id, span },
1418                }
1419            }
1420            ty::UpvarCapture::ByRef(upvar_borrow) => {
1421                let borrow_kind = match upvar_borrow {
1422                    ty::BorrowKind::Immutable => BorrowKind::Shared,
1423                    ty::BorrowKind::UniqueImmutable => {
1424                        BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture }
1425                    }
1426                    ty::BorrowKind::Mutable => {
1427                        BorrowKind::Mut { kind: mir::MutBorrowKind::Default }
1428                    }
1429                };
1430                Expr {
1431                    temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
1432                    ty: upvar_ty,
1433                    span: closure_expr.span,
1434                    kind: ExprKind::Borrow {
1435                        borrow_kind,
1436                        arg: self.thir.exprs.push(captured_place_expr),
1437                    },
1438                }
1439            }
1440        }
1441    }
1442
1443    /// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExpr.
1444    fn field_refs(&mut self, fields: &'tcx [hir::ExprField<'tcx>]) -> Box<[FieldExpr]> {
1445        fields
1446            .iter()
1447            .map(|field| FieldExpr {
1448                name: self.typeck_results.field_index(field.hir_id),
1449                expr: self.mirror_expr(field.expr),
1450            })
1451            .collect()
1452    }
1453}
1454
1455trait ToBorrowKind {
1456    fn to_borrow_kind(&self) -> BorrowKind;
1457}
1458
1459impl ToBorrowKind for AutoBorrowMutability {
1460    fn to_borrow_kind(&self) -> BorrowKind {
1461        use rustc_middle::ty::adjustment::AllowTwoPhase;
1462        match *self {
1463            AutoBorrowMutability::Mut { allow_two_phase_borrow } => BorrowKind::Mut {
1464                kind: match allow_two_phase_borrow {
1465                    AllowTwoPhase::Yes => mir::MutBorrowKind::TwoPhaseBorrow,
1466                    AllowTwoPhase::No => mir::MutBorrowKind::Default,
1467                },
1468            },
1469            AutoBorrowMutability::Not => BorrowKind::Shared,
1470        }
1471    }
1472}
1473
1474impl ToBorrowKind for hir::Mutability {
1475    fn to_borrow_kind(&self) -> BorrowKind {
1476        match *self {
1477            hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
1478            hir::Mutability::Not => BorrowKind::Shared,
1479        }
1480    }
1481}
1482
1483fn bin_op(op: hir::BinOpKind) -> BinOp {
1484    match op {
1485        hir::BinOpKind::Add => BinOp::Add,
1486        hir::BinOpKind::Sub => BinOp::Sub,
1487        hir::BinOpKind::Mul => BinOp::Mul,
1488        hir::BinOpKind::Div => BinOp::Div,
1489        hir::BinOpKind::Rem => BinOp::Rem,
1490        hir::BinOpKind::BitXor => BinOp::BitXor,
1491        hir::BinOpKind::BitAnd => BinOp::BitAnd,
1492        hir::BinOpKind::BitOr => BinOp::BitOr,
1493        hir::BinOpKind::Shl => BinOp::Shl,
1494        hir::BinOpKind::Shr => BinOp::Shr,
1495        hir::BinOpKind::Eq => BinOp::Eq,
1496        hir::BinOpKind::Lt => BinOp::Lt,
1497        hir::BinOpKind::Le => BinOp::Le,
1498        hir::BinOpKind::Ne => BinOp::Ne,
1499        hir::BinOpKind::Ge => BinOp::Ge,
1500        hir::BinOpKind::Gt => BinOp::Gt,
1501        _ => bug!("no equivalent for ast binop {:?}", op),
1502    }
1503}
1504
1505fn assign_op(op: hir::AssignOpKind) -> AssignOp {
1506    match op {
1507        hir::AssignOpKind::AddAssign => AssignOp::AddAssign,
1508        hir::AssignOpKind::SubAssign => AssignOp::SubAssign,
1509        hir::AssignOpKind::MulAssign => AssignOp::MulAssign,
1510        hir::AssignOpKind::DivAssign => AssignOp::DivAssign,
1511        hir::AssignOpKind::RemAssign => AssignOp::RemAssign,
1512        hir::AssignOpKind::BitXorAssign => AssignOp::BitXorAssign,
1513        hir::AssignOpKind::BitAndAssign => AssignOp::BitAndAssign,
1514        hir::AssignOpKind::BitOrAssign => AssignOp::BitOrAssign,
1515        hir::AssignOpKind::ShlAssign => AssignOp::ShlAssign,
1516        hir::AssignOpKind::ShrAssign => AssignOp::ShrAssign,
1517    }
1518}