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