rustc_mir_build/thir/cx/
expr.rs

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