rustc_mir_build/thir/cx/
expr.rs

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