rustc_hir_typeck/
expr_use_visitor.rs

1//! A different sort of visitor for walking fn bodies. Unlike the
2//! normal visitor, which just walks the entire body in one shot, the
3//! `ExprUseVisitor` determines how expressions are being used.
4
5use std::cell::{Ref, RefCell};
6use std::ops::Deref;
7use std::slice::from_ref;
8
9use hir::Expr;
10use hir::def::DefKind;
11use hir::pat_util::EnumerateAndAdjustIterator as _;
12use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
13use rustc_data_structures::fx::FxIndexMap;
14use rustc_hir::def::{CtorOf, Res};
15use rustc_hir::def_id::LocalDefId;
16use rustc_hir::{self as hir, HirId, PatExpr, PatExprKind, PatKind};
17use rustc_lint::LateContext;
18use rustc_middle::hir::place::ProjectionKind;
19// Export these here so that Clippy can use them.
20pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
21use rustc_middle::mir::FakeReadCause;
22use rustc_middle::ty::{
23    self, BorrowKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, adjustment,
24};
25use rustc_middle::{bug, span_bug};
26use rustc_span::{ErrorGuaranteed, Span};
27use rustc_trait_selection::infer::InferCtxtExt;
28use tracing::{debug, trace};
29
30use crate::fn_ctxt::FnCtxt;
31
32/// This trait defines the callbacks you can expect to receive when
33/// employing the ExprUseVisitor.
34pub trait Delegate<'tcx> {
35    /// The value found at `place` is moved, depending
36    /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
37    ///
38    /// Use of a `Copy` type in a ByValue context is considered a use
39    /// by `ImmBorrow` and `borrow` is called instead. This is because
40    /// a shared borrow is the "minimum access" that would be needed
41    /// to perform a copy.
42    ///
43    ///
44    /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
45    /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
46    /// id will be the id of the expression `expr` but the place itself will have
47    /// the id of the binding in the pattern `pat`.
48    fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
49
50    /// The value found at `place` is used, depending
51    /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
52    ///
53    /// Use of a `Copy` type in a ByUse context is considered a use
54    /// by `ImmBorrow` and `borrow` is called instead. This is because
55    /// a shared borrow is the "minimum access" that would be needed
56    /// to perform a copy.
57    ///
58    ///
59    /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
60    /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
61    /// id will be the id of the expression `expr` but the place itself will have
62    /// the id of the binding in the pattern `pat`.
63    fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
64
65    /// The value found at `place` is being borrowed with kind `bk`.
66    /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
67    fn borrow(
68        &mut self,
69        place_with_id: &PlaceWithHirId<'tcx>,
70        diag_expr_id: HirId,
71        bk: ty::BorrowKind,
72    );
73
74    /// The value found at `place` is being copied.
75    /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
76    fn copy(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
77        // In most cases, copying data from `x` is equivalent to doing `*&x`, so by default
78        // we treat a copy of `x` as a borrow of `x`.
79        self.borrow(place_with_id, diag_expr_id, ty::BorrowKind::Immutable)
80    }
81
82    /// The path at `assignee_place` is being assigned to.
83    /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
84    fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
85
86    /// The path at `binding_place` is a binding that is being initialized.
87    ///
88    /// This covers cases such as `let x = 42;`
89    fn bind(&mut self, binding_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
90        // Bindings can normally be treated as a regular assignment, so by default we
91        // forward this to the mutate callback.
92        self.mutate(binding_place, diag_expr_id)
93    }
94
95    /// The `place` should be a fake read because of specified `cause`.
96    fn fake_read(
97        &mut self,
98        place_with_id: &PlaceWithHirId<'tcx>,
99        cause: FakeReadCause,
100        diag_expr_id: HirId,
101    );
102}
103
104impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D {
105    fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
106        (**self).consume(place_with_id, diag_expr_id)
107    }
108
109    fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
110        (**self).use_cloned(place_with_id, diag_expr_id)
111    }
112
113    fn borrow(
114        &mut self,
115        place_with_id: &PlaceWithHirId<'tcx>,
116        diag_expr_id: HirId,
117        bk: ty::BorrowKind,
118    ) {
119        (**self).borrow(place_with_id, diag_expr_id, bk)
120    }
121
122    fn copy(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
123        (**self).copy(place_with_id, diag_expr_id)
124    }
125
126    fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
127        (**self).mutate(assignee_place, diag_expr_id)
128    }
129
130    fn bind(&mut self, binding_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
131        (**self).bind(binding_place, diag_expr_id)
132    }
133
134    fn fake_read(
135        &mut self,
136        place_with_id: &PlaceWithHirId<'tcx>,
137        cause: FakeReadCause,
138        diag_expr_id: HirId,
139    ) {
140        (**self).fake_read(place_with_id, cause, diag_expr_id)
141    }
142}
143
144pub trait TypeInformationCtxt<'tcx> {
145    type TypeckResults<'a>: Deref<Target = ty::TypeckResults<'tcx>>
146    where
147        Self: 'a;
148
149    type Error;
150
151    fn typeck_results(&self) -> Self::TypeckResults<'_>;
152
153    fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T;
154
155    fn try_structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
156
157    fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error;
158
159    fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error>;
160
161    fn tainted_by_errors(&self) -> Result<(), Self::Error>;
162
163    fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
164
165    fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
166
167    fn body_owner_def_id(&self) -> LocalDefId;
168
169    fn tcx(&self) -> TyCtxt<'tcx>;
170}
171
172impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
173    type TypeckResults<'a>
174        = Ref<'a, ty::TypeckResults<'tcx>>
175    where
176        Self: 'a;
177
178    type Error = ErrorGuaranteed;
179
180    fn typeck_results(&self) -> Self::TypeckResults<'_> {
181        self.typeck_results.borrow()
182    }
183
184    fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
185        self.infcx.resolve_vars_if_possible(t)
186    }
187
188    fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
189        (**self).try_structurally_resolve_type(sp, ty)
190    }
191
192    fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error {
193        self.dcx().span_delayed_bug(span, msg.to_string())
194    }
195
196    fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error> {
197        ty.error_reported()
198    }
199
200    fn tainted_by_errors(&self) -> Result<(), ErrorGuaranteed> {
201        if let Some(guar) = self.infcx.tainted_by_errors() { Err(guar) } else { Ok(()) }
202    }
203
204    fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
205        self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
206    }
207
208    fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
209        self.infcx.type_is_use_cloned_modulo_regions(self.param_env, ty)
210    }
211
212    fn body_owner_def_id(&self) -> LocalDefId {
213        self.body_id
214    }
215
216    fn tcx(&self) -> TyCtxt<'tcx> {
217        self.tcx
218    }
219}
220
221impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
222    type TypeckResults<'a>
223        = &'tcx ty::TypeckResults<'tcx>
224    where
225        Self: 'a;
226
227    type Error = !;
228
229    fn typeck_results(&self) -> Self::TypeckResults<'_> {
230        self.0.maybe_typeck_results().expect("expected typeck results")
231    }
232
233    fn try_structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
234        // FIXME: Maybe need to normalize here.
235        ty
236    }
237
238    fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
239        t
240    }
241
242    fn report_error(&self, span: Span, msg: impl ToString) -> ! {
243        span_bug!(span, "{}", msg.to_string())
244    }
245
246    fn error_reported_in_ty(&self, _ty: Ty<'tcx>) -> Result<(), !> {
247        Ok(())
248    }
249
250    fn tainted_by_errors(&self) -> Result<(), !> {
251        Ok(())
252    }
253
254    fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
255        self.0.type_is_copy_modulo_regions(ty)
256    }
257
258    fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
259        self.0.type_is_use_cloned_modulo_regions(ty)
260    }
261
262    fn body_owner_def_id(&self) -> LocalDefId {
263        self.1
264    }
265
266    fn tcx(&self) -> TyCtxt<'tcx> {
267        self.0.tcx
268    }
269}
270
271/// The ExprUseVisitor type
272///
273/// This is the code that actually walks the tree.
274pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> {
275    cx: Cx,
276    /// We use a `RefCell` here so that delegates can mutate themselves, but we can
277    /// still have calls to our own helper functions.
278    delegate: RefCell<D>,
279    upvars: Option<&'tcx FxIndexMap<HirId, hir::Upvar>>,
280}
281
282impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'tcx, (&'a LateContext<'tcx>, LocalDefId), D> {
283    pub fn for_clippy(cx: &'a LateContext<'tcx>, body_def_id: LocalDefId, delegate: D) -> Self {
284        Self::new((cx, body_def_id), delegate)
285    }
286}
287
288impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> {
289    /// Creates the ExprUseVisitor, configuring it with the various options provided:
290    ///
291    /// - `delegate` -- who receives the callbacks
292    /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`)
293    /// - `typeck_results` --- typeck results for the code being analyzed
294    pub(crate) fn new(cx: Cx, delegate: D) -> Self {
295        ExprUseVisitor {
296            delegate: RefCell::new(delegate),
297            upvars: cx.tcx().upvars_mentioned(cx.body_owner_def_id()),
298            cx,
299        }
300    }
301
302    pub fn consume_body(&self, body: &hir::Body<'_>) -> Result<(), Cx::Error> {
303        for param in body.params {
304            let param_ty = self.pat_ty_adjusted(param.pat)?;
305            debug!("consume_body: param_ty = {:?}", param_ty);
306
307            let param_place = self.cat_rvalue(param.hir_id, param_ty);
308
309            self.walk_irrefutable_pat(&param_place, param.pat)?;
310        }
311
312        self.consume_expr(body.value)?;
313
314        Ok(())
315    }
316
317    fn consume_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
318        debug!("delegate_consume(place_with_id={:?})", place_with_id);
319
320        if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
321            self.delegate.borrow_mut().copy(place_with_id, diag_expr_id);
322        } else {
323            self.delegate.borrow_mut().consume(place_with_id, diag_expr_id);
324        }
325    }
326
327    pub fn consume_clone_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
328        debug!("delegate_consume_or_clone(place_with_id={:?})", place_with_id);
329
330        // `x.use` will do one of the following
331        // * if it implements `Copy`, it will be a copy
332        // * if it implements `UseCloned`, it will be a call to `clone`
333        // * otherwise, it is a move
334        //
335        // we do a conservative approximation of this, treating it as a move unless we know that it implements copy or `UseCloned`
336        if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
337            self.delegate.borrow_mut().copy(place_with_id, diag_expr_id);
338        } else if self.cx.type_is_use_cloned_modulo_regions(place_with_id.place.ty()) {
339            self.delegate.borrow_mut().use_cloned(place_with_id, diag_expr_id);
340        } else {
341            self.delegate.borrow_mut().consume(place_with_id, diag_expr_id);
342        }
343    }
344
345    fn consume_exprs(&self, exprs: &[hir::Expr<'_>]) -> Result<(), Cx::Error> {
346        for expr in exprs {
347            self.consume_expr(expr)?;
348        }
349
350        Ok(())
351    }
352
353    // FIXME: It's suspicious that this is public; clippy should probably use `walk_expr`.
354    pub fn consume_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
355        debug!("consume_expr(expr={:?})", expr);
356
357        let place_with_id = self.cat_expr(expr)?;
358        self.consume_or_copy(&place_with_id, place_with_id.hir_id);
359        self.walk_expr(expr)?;
360        Ok(())
361    }
362
363    pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
364        debug!("consume_or_clone_expr(expr={:?})", expr);
365
366        let place_with_id = self.cat_expr(expr)?;
367        self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id);
368        self.walk_expr(expr)?;
369        Ok(())
370    }
371
372    fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
373        let place_with_id = self.cat_expr(expr)?;
374        self.delegate.borrow_mut().mutate(&place_with_id, place_with_id.hir_id);
375        self.walk_expr(expr)?;
376        Ok(())
377    }
378
379    fn borrow_expr(&self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) -> Result<(), Cx::Error> {
380        debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk);
381
382        let place_with_id = self.cat_expr(expr)?;
383        self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
384        self.walk_expr(expr)
385    }
386
387    pub fn walk_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
388        debug!("walk_expr(expr={:?})", expr);
389
390        self.walk_adjustment(expr)?;
391
392        match expr.kind {
393            hir::ExprKind::Path(_) => {}
394
395            hir::ExprKind::Type(subexpr, _) => {
396                self.walk_expr(subexpr)?;
397            }
398
399            hir::ExprKind::UnsafeBinderCast(_, subexpr, _) => {
400                self.walk_expr(subexpr)?;
401            }
402
403            hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
404                // *base
405                self.walk_expr(base)?;
406            }
407
408            hir::ExprKind::Field(base, _) => {
409                // base.f
410                self.walk_expr(base)?;
411            }
412
413            hir::ExprKind::Index(lhs, rhs, _) => {
414                // lhs[rhs]
415                self.walk_expr(lhs)?;
416                self.consume_expr(rhs)?;
417            }
418
419            hir::ExprKind::Call(callee, args) => {
420                // callee(args)
421                self.consume_expr(callee)?;
422                self.consume_exprs(args)?;
423            }
424
425            hir::ExprKind::Use(expr, _) => {
426                self.consume_or_clone_expr(expr)?;
427            }
428
429            hir::ExprKind::MethodCall(.., receiver, args, _) => {
430                // callee.m(args)
431                self.consume_expr(receiver)?;
432                self.consume_exprs(args)?;
433            }
434
435            hir::ExprKind::Struct(_, fields, ref opt_with) => {
436                self.walk_struct_expr(fields, opt_with)?;
437            }
438
439            hir::ExprKind::Tup(exprs) => {
440                self.consume_exprs(exprs)?;
441            }
442
443            hir::ExprKind::If(cond_expr, then_expr, ref opt_else_expr) => {
444                self.consume_expr(cond_expr)?;
445                self.consume_expr(then_expr)?;
446                if let Some(else_expr) = *opt_else_expr {
447                    self.consume_expr(else_expr)?;
448                }
449            }
450
451            hir::ExprKind::Let(hir::LetExpr { pat, init, .. }) => {
452                self.walk_local(init, pat, None, || self.borrow_expr(init, BorrowKind::Immutable))?;
453            }
454
455            hir::ExprKind::Match(discr, arms, _) => {
456                let discr_place = self.cat_expr(discr)?;
457                self.maybe_read_scrutinee(
458                    discr,
459                    discr_place.clone(),
460                    arms.iter().map(|arm| arm.pat),
461                )?;
462
463                // treatment of the discriminant is handled while walking the arms.
464                for arm in arms {
465                    self.walk_arm(&discr_place, arm)?;
466                }
467            }
468
469            hir::ExprKind::Array(exprs) => {
470                self.consume_exprs(exprs)?;
471            }
472
473            hir::ExprKind::AddrOf(_, m, base) => {
474                // &base
475                // make sure that the thing we are pointing out stays valid
476                // for the lifetime `scope_r` of the resulting ptr:
477                let bk = ty::BorrowKind::from_mutbl(m);
478                self.borrow_expr(base, bk)?;
479            }
480
481            hir::ExprKind::InlineAsm(asm) => {
482                for (op, _op_sp) in asm.operands {
483                    match op {
484                        hir::InlineAsmOperand::In { expr, .. } => {
485                            self.consume_expr(expr)?;
486                        }
487                        hir::InlineAsmOperand::Out { expr: Some(expr), .. }
488                        | hir::InlineAsmOperand::InOut { expr, .. } => {
489                            self.mutate_expr(expr)?;
490                        }
491                        hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
492                            self.consume_expr(in_expr)?;
493                            if let Some(out_expr) = out_expr {
494                                self.mutate_expr(out_expr)?;
495                            }
496                        }
497                        hir::InlineAsmOperand::Out { expr: None, .. }
498                        | hir::InlineAsmOperand::Const { .. }
499                        | hir::InlineAsmOperand::SymFn { .. }
500                        | hir::InlineAsmOperand::SymStatic { .. } => {}
501                        hir::InlineAsmOperand::Label { block } => {
502                            self.walk_block(block)?;
503                        }
504                    }
505                }
506            }
507
508            hir::ExprKind::Continue(..)
509            | hir::ExprKind::Lit(..)
510            | hir::ExprKind::ConstBlock(..)
511            | hir::ExprKind::OffsetOf(..)
512            | hir::ExprKind::Err(_) => {}
513
514            hir::ExprKind::Loop(blk, ..) => {
515                self.walk_block(blk)?;
516            }
517
518            hir::ExprKind::Unary(_, lhs) => {
519                self.consume_expr(lhs)?;
520            }
521
522            hir::ExprKind::Binary(_, lhs, rhs) => {
523                self.consume_expr(lhs)?;
524                self.consume_expr(rhs)?;
525            }
526
527            hir::ExprKind::Block(blk, _) => {
528                self.walk_block(blk)?;
529            }
530
531            hir::ExprKind::Break(_, ref opt_expr) | hir::ExprKind::Ret(ref opt_expr) => {
532                if let Some(expr) = *opt_expr {
533                    self.consume_expr(expr)?;
534                }
535            }
536
537            hir::ExprKind::Become(call) => {
538                self.consume_expr(call)?;
539            }
540
541            hir::ExprKind::Assign(lhs, rhs, _) => {
542                self.mutate_expr(lhs)?;
543                self.consume_expr(rhs)?;
544            }
545
546            hir::ExprKind::Cast(base, _) => {
547                self.consume_expr(base)?;
548            }
549
550            hir::ExprKind::DropTemps(expr) => {
551                self.consume_expr(expr)?;
552            }
553
554            hir::ExprKind::AssignOp(_, lhs, rhs) => {
555                if self.cx.typeck_results().is_method_call(expr) {
556                    self.consume_expr(lhs)?;
557                } else {
558                    self.mutate_expr(lhs)?;
559                }
560                self.consume_expr(rhs)?;
561            }
562
563            hir::ExprKind::Repeat(base, _) => {
564                self.consume_expr(base)?;
565            }
566
567            hir::ExprKind::Closure(closure) => {
568                self.walk_captures(closure)?;
569            }
570
571            hir::ExprKind::Yield(value, _) => {
572                self.consume_expr(value)?;
573            }
574        }
575
576        Ok(())
577    }
578
579    fn walk_stmt(&self, stmt: &hir::Stmt<'_>) -> Result<(), Cx::Error> {
580        match stmt.kind {
581            hir::StmtKind::Let(hir::LetStmt { pat, init: Some(expr), els, .. }) => {
582                self.walk_local(expr, pat, *els, || Ok(()))?;
583            }
584
585            hir::StmtKind::Let(_) => {}
586
587            hir::StmtKind::Item(_) => {
588                // We don't visit nested items in this visitor,
589                // only the fn body we were given.
590            }
591
592            hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => {
593                self.consume_expr(expr)?;
594            }
595        }
596
597        Ok(())
598    }
599
600    fn maybe_read_scrutinee<'t>(
601        &self,
602        discr: &Expr<'_>,
603        discr_place: PlaceWithHirId<'tcx>,
604        pats: impl Iterator<Item = &'t hir::Pat<'t>>,
605    ) -> Result<(), Cx::Error> {
606        // Matching should not always be considered a use of the place, hence
607        // discr does not necessarily need to be borrowed.
608        // We only want to borrow discr if the pattern contain something other
609        // than wildcards.
610        let mut needs_to_be_read = false;
611        for pat in pats {
612            self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
613                match &pat.kind {
614                    PatKind::Binding(.., opt_sub_pat) => {
615                        // If the opt_sub_pat is None, then the binding does not count as
616                        // a wildcard for the purpose of borrowing discr.
617                        if opt_sub_pat.is_none() {
618                            needs_to_be_read = true;
619                        }
620                    }
621                    PatKind::Never => {
622                        // A never pattern reads the value.
623                        // FIXME(never_patterns): does this do what I expect?
624                        needs_to_be_read = true;
625                    }
626                    PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
627                        // A `Path` pattern is just a name like `Foo`. This is either a
628                        // named constant or else it refers to an ADT variant
629
630                        let res = self.cx.typeck_results().qpath_res(qpath, *hir_id);
631                        match res {
632                            Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
633                                // Named constants have to be equated with the value
634                                // being matched, so that's a read of the value being matched.
635                                //
636                                // FIXME: We don't actually reads for ZSTs.
637                                needs_to_be_read = true;
638                            }
639                            _ => {
640                                // Otherwise, this is a struct/enum variant, and so it's
641                                // only a read if we need to read the discriminant.
642                                needs_to_be_read |=
643                                    self.is_multivariant_adt(place.place.ty(), *span);
644                            }
645                        }
646                    }
647                    PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
648                        // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
649                        // against a multivariant enum or struct. In that case, we have to read
650                        // the discriminant. Otherwise this kind of pattern doesn't actually
651                        // read anything (we'll get invoked for the `...`, which may indeed
652                        // perform some reads).
653
654                        let place_ty = place.place.ty();
655                        needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span);
656                    }
657                    PatKind::Expr(_) | PatKind::Range(..) => {
658                        // If the PatKind is a Lit or a Range then we want
659                        // to borrow discr.
660                        needs_to_be_read = true;
661                    }
662                    PatKind::Slice(lhs, wild, rhs) => {
663                        // We don't need to test the length if the pattern is `[..]`
664                        if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
665                            // Arrays have a statically known size, so
666                            // there is no need to read their length
667                            || place.place.ty().peel_refs().is_array()
668                        {
669                        } else {
670                            needs_to_be_read = true;
671                        }
672                    }
673                    PatKind::Or(_)
674                    | PatKind::Box(_)
675                    | PatKind::Deref(_)
676                    | PatKind::Ref(..)
677                    | PatKind::Guard(..)
678                    | PatKind::Wild
679                    | PatKind::Err(_) => {
680                        // If the PatKind is Or, Box, or Ref, the decision is made later
681                        // as these patterns contains subpatterns
682                        // If the PatKind is Wild or Err, the decision is made based on the other patterns
683                        // being examined
684                    }
685                }
686
687                Ok(())
688            })?
689        }
690
691        if needs_to_be_read {
692            self.borrow_expr(discr, BorrowKind::Immutable)?;
693        } else {
694            let closure_def_id = match discr_place.place.base {
695                PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
696                _ => None,
697            };
698
699            self.delegate.borrow_mut().fake_read(
700                &discr_place,
701                FakeReadCause::ForMatchedPlace(closure_def_id),
702                discr_place.hir_id,
703            );
704
705            // We always want to walk the discriminant. We want to make sure, for instance,
706            // that the discriminant has been initialized.
707            self.walk_expr(discr)?;
708        }
709        Ok(())
710    }
711
712    fn walk_local<F>(
713        &self,
714        expr: &hir::Expr<'_>,
715        pat: &hir::Pat<'_>,
716        els: Option<&hir::Block<'_>>,
717        mut f: F,
718    ) -> Result<(), Cx::Error>
719    where
720        F: FnMut() -> Result<(), Cx::Error>,
721    {
722        self.walk_expr(expr)?;
723        let expr_place = self.cat_expr(expr)?;
724        f()?;
725        if let Some(els) = els {
726            // borrowing because we need to test the discriminant
727            self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter())?;
728            self.walk_block(els)?;
729        }
730        self.walk_irrefutable_pat(&expr_place, pat)?;
731        Ok(())
732    }
733
734    /// Indicates that the value of `blk` will be consumed, meaning either copied or moved
735    /// depending on its type.
736    fn walk_block(&self, blk: &hir::Block<'_>) -> Result<(), Cx::Error> {
737        debug!("walk_block(blk.hir_id={})", blk.hir_id);
738
739        for stmt in blk.stmts {
740            self.walk_stmt(stmt)?;
741        }
742
743        if let Some(tail_expr) = blk.expr {
744            self.consume_expr(tail_expr)?;
745        }
746
747        Ok(())
748    }
749
750    fn walk_struct_expr<'hir>(
751        &self,
752        fields: &[hir::ExprField<'_>],
753        opt_with: &hir::StructTailExpr<'hir>,
754    ) -> Result<(), Cx::Error> {
755        // Consume the expressions supplying values for each field.
756        for field in fields {
757            self.consume_expr(field.expr)?;
758
759            // The struct path probably didn't resolve
760            if self.cx.typeck_results().opt_field_index(field.hir_id).is_none() {
761                self.cx
762                    .tcx()
763                    .dcx()
764                    .span_delayed_bug(field.span, "couldn't resolve index for field");
765            }
766        }
767
768        let with_expr = match *opt_with {
769            hir::StructTailExpr::Base(w) => &*w,
770            hir::StructTailExpr::DefaultFields(_) | hir::StructTailExpr::None => {
771                return Ok(());
772            }
773        };
774
775        let with_place = self.cat_expr(with_expr)?;
776
777        // Select just those fields of the `with`
778        // expression that will actually be used
779        match self.cx.try_structurally_resolve_type(with_expr.span, with_place.place.ty()).kind() {
780            ty::Adt(adt, args) if adt.is_struct() => {
781                // Consume those fields of the with expression that are needed.
782                for (f_index, with_field) in adt.non_enum_variant().fields.iter_enumerated() {
783                    let is_mentioned = fields.iter().any(|f| {
784                        self.cx.typeck_results().opt_field_index(f.hir_id) == Some(f_index)
785                    });
786                    if !is_mentioned {
787                        let field_place = self.cat_projection(
788                            with_expr.hir_id,
789                            with_place.clone(),
790                            with_field.ty(self.cx.tcx(), args),
791                            ProjectionKind::Field(f_index, FIRST_VARIANT),
792                        );
793                        self.consume_or_copy(&field_place, field_place.hir_id);
794                    }
795                }
796            }
797            _ => {
798                // the base expression should always evaluate to a
799                // struct; however, when EUV is run during typeck, it
800                // may not. This will generate an error earlier in typeck,
801                // so we can just ignore it.
802                if self.cx.tainted_by_errors().is_ok() {
803                    span_bug!(with_expr.span, "with expression doesn't evaluate to a struct");
804                }
805            }
806        }
807
808        // walk the with expression so that complex expressions
809        // are properly handled.
810        self.walk_expr(with_expr)?;
811
812        Ok(())
813    }
814
815    /// Invoke the appropriate delegate calls for anything that gets
816    /// consumed or borrowed as part of the automatic adjustment
817    /// process.
818    fn walk_adjustment(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
819        let typeck_results = self.cx.typeck_results();
820        let adjustments = typeck_results.expr_adjustments(expr);
821        let mut place_with_id = self.cat_expr_unadjusted(expr)?;
822        for adjustment in adjustments {
823            debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
824            match adjustment.kind {
825                adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
826                    // Creating a closure/fn-pointer or unsizing consumes
827                    // the input and stores it into the resulting rvalue.
828                    self.consume_or_copy(&place_with_id, place_with_id.hir_id);
829                }
830
831                adjustment::Adjust::Deref(None) => {}
832
833                // Autoderefs for overloaded Deref calls in fact reference
834                // their receiver. That is, if we have `(*x)` where `x`
835                // is of type `Rc<T>`, then this in fact is equivalent to
836                // `x.deref()`. Since `deref()` is declared with `&self`,
837                // this is an autoref of `x`.
838                adjustment::Adjust::Deref(Some(ref deref)) => {
839                    let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
840                    self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
841                }
842
843                adjustment::Adjust::Borrow(ref autoref) => {
844                    self.walk_autoref(expr, &place_with_id, autoref);
845                }
846
847                adjustment::Adjust::ReborrowPin(mutbl) => {
848                    // Reborrowing a Pin is like a combinations of a deref and a borrow, so we do
849                    // both.
850                    let bk = match mutbl {
851                        ty::Mutability::Not => ty::BorrowKind::Immutable,
852                        ty::Mutability::Mut => ty::BorrowKind::Mutable,
853                    };
854                    self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
855                }
856            }
857            place_with_id = self.cat_expr_adjusted(expr, place_with_id, adjustment)?;
858        }
859
860        Ok(())
861    }
862
863    /// Walks the autoref `autoref` applied to the autoderef'd
864    /// `expr`. `base_place` is the mem-categorized form of `expr`
865    /// after all relevant autoderefs have occurred.
866    fn walk_autoref(
867        &self,
868        expr: &hir::Expr<'_>,
869        base_place: &PlaceWithHirId<'tcx>,
870        autoref: &adjustment::AutoBorrow,
871    ) {
872        debug!(
873            "walk_autoref(expr.hir_id={} base_place={:?} autoref={:?})",
874            expr.hir_id, base_place, autoref
875        );
876
877        match *autoref {
878            adjustment::AutoBorrow::Ref(m) => {
879                self.delegate.borrow_mut().borrow(
880                    base_place,
881                    base_place.hir_id,
882                    ty::BorrowKind::from_mutbl(m.into()),
883                );
884            }
885
886            adjustment::AutoBorrow::RawPtr(m) => {
887                debug!("walk_autoref: expr.hir_id={} base_place={:?}", expr.hir_id, base_place);
888
889                self.delegate.borrow_mut().borrow(
890                    base_place,
891                    base_place.hir_id,
892                    ty::BorrowKind::from_mutbl(m),
893                );
894            }
895        }
896    }
897
898    fn walk_arm(
899        &self,
900        discr_place: &PlaceWithHirId<'tcx>,
901        arm: &hir::Arm<'_>,
902    ) -> Result<(), Cx::Error> {
903        let closure_def_id = match discr_place.place.base {
904            PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
905            _ => None,
906        };
907
908        self.delegate.borrow_mut().fake_read(
909            discr_place,
910            FakeReadCause::ForMatchedPlace(closure_def_id),
911            discr_place.hir_id,
912        );
913        self.walk_pat(discr_place, arm.pat, arm.guard.is_some())?;
914
915        if let Some(ref e) = arm.guard {
916            self.consume_expr(e)?;
917        }
918
919        self.consume_expr(arm.body)?;
920        Ok(())
921    }
922
923    /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
924    /// let binding, and *not* a match arm or nested pat.)
925    fn walk_irrefutable_pat(
926        &self,
927        discr_place: &PlaceWithHirId<'tcx>,
928        pat: &hir::Pat<'_>,
929    ) -> Result<(), Cx::Error> {
930        let closure_def_id = match discr_place.place.base {
931            PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
932            _ => None,
933        };
934
935        self.delegate.borrow_mut().fake_read(
936            discr_place,
937            FakeReadCause::ForLet(closure_def_id),
938            discr_place.hir_id,
939        );
940        self.walk_pat(discr_place, pat, false)?;
941        Ok(())
942    }
943
944    /// The core driver for walking a pattern
945    fn walk_pat(
946        &self,
947        discr_place: &PlaceWithHirId<'tcx>,
948        pat: &hir::Pat<'_>,
949        has_guard: bool,
950    ) -> Result<(), Cx::Error> {
951        debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard);
952
953        let tcx = self.cx.tcx();
954        self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
955            match pat.kind {
956                PatKind::Binding(_, canonical_id, ..) => {
957                    debug!("walk_pat: binding place={:?} pat={:?}", place, pat);
958                    let bm = self
959                        .cx
960                        .typeck_results()
961                        .extract_binding_mode(tcx.sess, pat.hir_id, pat.span);
962                    debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
963
964                    // pat_ty: the type of the binding being produced.
965                    let pat_ty = self.node_ty(pat.hir_id)?;
966                    debug!("walk_pat: pat_ty={:?}", pat_ty);
967
968                    let def = Res::Local(canonical_id);
969                    if let Ok(ref binding_place) = self.cat_res(pat.hir_id, pat.span, pat_ty, def) {
970                        self.delegate.borrow_mut().bind(binding_place, binding_place.hir_id);
971                    }
972
973                    // Subtle: MIR desugaring introduces immutable borrows for each pattern
974                    // binding when lowering pattern guards to ensure that the guard does not
975                    // modify the scrutinee.
976                    if has_guard {
977                        self.delegate.borrow_mut().borrow(
978                            place,
979                            discr_place.hir_id,
980                            BorrowKind::Immutable,
981                        );
982                    }
983
984                    // It is also a borrow or copy/move of the value being matched.
985                    // In a cases of pattern like `let pat = upvar`, don't use the span
986                    // of the pattern, as this just looks confusing, instead use the span
987                    // of the discriminant.
988                    match bm.0 {
989                        hir::ByRef::Yes(m) => {
990                            let bk = ty::BorrowKind::from_mutbl(m);
991                            self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
992                        }
993                        hir::ByRef::No => {
994                            debug!("walk_pat binding consuming pat");
995                            self.consume_or_copy(place, discr_place.hir_id);
996                        }
997                    }
998                }
999                PatKind::Deref(subpattern) => {
1000                    // A deref pattern is a bit special: the binding mode of its inner bindings
1001                    // determines whether to borrow *at the level of the deref pattern* rather than
1002                    // borrowing the bound place (since that inner place is inside the temporary that
1003                    // stores the result of calling `deref()`/`deref_mut()` so can't be captured).
1004                    let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern);
1005                    let mutability =
1006                        if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
1007                    let bk = ty::BorrowKind::from_mutbl(mutability);
1008                    self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
1009                }
1010                PatKind::Never => {
1011                    // A `!` pattern always counts as an immutable read of the discriminant,
1012                    // even in an irrefutable pattern.
1013                    self.delegate.borrow_mut().borrow(
1014                        place,
1015                        discr_place.hir_id,
1016                        BorrowKind::Immutable,
1017                    );
1018                }
1019                _ => {}
1020            }
1021
1022            Ok(())
1023        })
1024    }
1025
1026    /// Handle the case where the current body contains a closure.
1027    ///
1028    /// When the current body being handled is a closure, then we must make sure that
1029    /// - The parent closure only captures Places from the nested closure that are not local to it.
1030    ///
1031    /// In the following example the closures `c` only captures `p.x` even though `incr`
1032    /// is a capture of the nested closure
1033    ///
1034    /// ```
1035    /// struct P { x: i32 }
1036    /// let mut p = P { x: 4 };
1037    /// let c = || {
1038    ///    let incr = 10;
1039    ///    let nested = || p.x += incr;
1040    /// };
1041    /// ```
1042    ///
1043    /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
1044    /// closure as the DefId.
1045    fn walk_captures(&self, closure_expr: &hir::Closure<'_>) -> Result<(), Cx::Error> {
1046        fn upvar_is_local_variable(
1047            upvars: Option<&FxIndexMap<HirId, hir::Upvar>>,
1048            upvar_id: HirId,
1049            body_owner_is_closure: bool,
1050        ) -> bool {
1051            upvars.map(|upvars| !upvars.contains_key(&upvar_id)).unwrap_or(body_owner_is_closure)
1052        }
1053
1054        debug!("walk_captures({:?})", closure_expr);
1055
1056        let tcx = self.cx.tcx();
1057        let closure_def_id = closure_expr.def_id;
1058        // For purposes of this function, coroutine and closures are equivalent.
1059        let body_owner_is_closure = matches!(
1060            tcx.hir_body_owner_kind(self.cx.body_owner_def_id()),
1061            hir::BodyOwnerKind::Closure
1062        );
1063
1064        // If we have a nested closure, we want to include the fake reads present in the nested
1065        // closure.
1066        if let Some(fake_reads) = self.cx.typeck_results().closure_fake_reads.get(&closure_def_id) {
1067            for (fake_read, cause, hir_id) in fake_reads.iter() {
1068                match fake_read.base {
1069                    PlaceBase::Upvar(upvar_id) => {
1070                        if upvar_is_local_variable(
1071                            self.upvars,
1072                            upvar_id.var_path.hir_id,
1073                            body_owner_is_closure,
1074                        ) {
1075                            // The nested closure might be fake reading the current (enclosing) closure's local variables.
1076                            // The only places we want to fake read before creating the parent closure are the ones that
1077                            // are not local to it/ defined by it.
1078                            //
1079                            // ```rust,ignore(cannot-test-this-because-pseudo-code)
1080                            // let v1 = (0, 1);
1081                            // let c = || { // fake reads: v1
1082                            //    let v2 = (0, 1);
1083                            //    let e = || { // fake reads: v1, v2
1084                            //       let (_, t1) = v1;
1085                            //       let (_, t2) = v2;
1086                            //    }
1087                            // }
1088                            // ```
1089                            // This check is performed when visiting the body of the outermost closure (`c`) and ensures
1090                            // that we don't add a fake read of v2 in c.
1091                            continue;
1092                        }
1093                    }
1094                    _ => {
1095                        bug!(
1096                            "Do not know how to get HirId out of Rvalue and StaticItem {:?}",
1097                            fake_read.base
1098                        );
1099                    }
1100                };
1101                self.delegate.borrow_mut().fake_read(
1102                    &PlaceWithHirId { place: fake_read.clone(), hir_id: *hir_id },
1103                    *cause,
1104                    *hir_id,
1105                );
1106            }
1107        }
1108
1109        if let Some(min_captures) =
1110            self.cx.typeck_results().closure_min_captures.get(&closure_def_id)
1111        {
1112            for (var_hir_id, min_list) in min_captures.iter() {
1113                if self
1114                    .upvars
1115                    .map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id))
1116                {
1117                    // The nested closure might be capturing the current (enclosing) closure's local variables.
1118                    // We check if the root variable is ever mentioned within the enclosing closure, if not
1119                    // then for the current body (if it's a closure) these aren't captures, we will ignore them.
1120                    continue;
1121                }
1122                for captured_place in min_list {
1123                    let place = &captured_place.place;
1124                    let capture_info = captured_place.info;
1125
1126                    let place_base = if body_owner_is_closure {
1127                        // Mark the place to be captured by the enclosing closure
1128                        PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.cx.body_owner_def_id()))
1129                    } else {
1130                        // If the body owner isn't a closure then the variable must
1131                        // be a local variable
1132                        PlaceBase::Local(*var_hir_id)
1133                    };
1134                    let closure_hir_id = tcx.local_def_id_to_hir_id(closure_def_id);
1135                    let place_with_id = PlaceWithHirId::new(
1136                        capture_info
1137                            .path_expr_id
1138                            .unwrap_or(capture_info.capture_kind_expr_id.unwrap_or(closure_hir_id)),
1139                        place.base_ty,
1140                        place_base,
1141                        place.projections.clone(),
1142                    );
1143
1144                    match capture_info.capture_kind {
1145                        ty::UpvarCapture::ByValue => {
1146                            self.consume_or_copy(&place_with_id, place_with_id.hir_id);
1147                        }
1148                        ty::UpvarCapture::ByUse => {
1149                            self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id);
1150                        }
1151                        ty::UpvarCapture::ByRef(upvar_borrow) => {
1152                            self.delegate.borrow_mut().borrow(
1153                                &place_with_id,
1154                                place_with_id.hir_id,
1155                                upvar_borrow,
1156                            );
1157                        }
1158                    }
1159                }
1160            }
1161        }
1162
1163        Ok(())
1164    }
1165}
1166
1167/// The job of the categorization methods is to analyze an expression to
1168/// determine what kind of memory is used in evaluating it (for example,
1169/// where dereferences occur and what kind of pointer is dereferenced;
1170/// whether the memory is mutable, etc.).
1171///
1172/// Categorization effectively transforms all of our expressions into
1173/// expressions of the following forms (the actual enum has many more
1174/// possibilities, naturally, but they are all variants of these base
1175/// forms):
1176/// ```ignore (not-rust)
1177/// E = rvalue    // some computed rvalue
1178///   | x         // address of a local variable or argument
1179///   | *E        // deref of a ptr
1180///   | E.comp    // access to an interior component
1181/// ```
1182/// Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
1183/// address where the result is to be found. If Expr is a place, then this
1184/// is the address of the place. If `Expr` is an rvalue, this is the address of
1185/// some temporary spot in memory where the result is stored.
1186///
1187/// Now, `cat_expr()` classifies the expression `Expr` and the address `A = ToAddr(Expr)`
1188/// as follows:
1189///
1190/// - `cat`: what kind of expression was this? This is a subset of the
1191///   full expression forms which only includes those that we care about
1192///   for the purpose of the analysis.
1193/// - `mutbl`: mutability of the address `A`.
1194/// - `ty`: the type of data found at the address `A`.
1195///
1196/// The resulting categorization tree differs somewhat from the expressions
1197/// themselves. For example, auto-derefs are explicit. Also, an index `a[b]` is
1198/// decomposed into two operations: a dereference to reach the array data and
1199/// then an index to jump forward to the relevant item.
1200///
1201/// ## By-reference upvars
1202///
1203/// One part of the codegen which may be non-obvious is that we translate
1204/// closure upvars into the dereference of a borrowed pointer; this more closely
1205/// resembles the runtime codegen. So, for example, if we had:
1206///
1207///     let mut x = 3;
1208///     let y = 5;
1209///     let inc = || x += y;
1210///
1211/// Then when we categorize `x` (*within* the closure) we would yield a
1212/// result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference
1213/// tied to `x`. The type of `x'` will be a borrowed pointer.
1214impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> {
1215    fn resolve_type_vars_or_error(
1216        &self,
1217        id: HirId,
1218        ty: Option<Ty<'tcx>>,
1219    ) -> Result<Ty<'tcx>, Cx::Error> {
1220        match ty {
1221            Some(ty) => {
1222                let ty = self.cx.resolve_vars_if_possible(ty);
1223                self.cx.error_reported_in_ty(ty)?;
1224                if ty.is_ty_var() {
1225                    debug!("resolve_type_vars_or_error: infer var from {:?}", ty);
1226                    Err(self
1227                        .cx
1228                        .report_error(self.cx.tcx().hir().span(id), "encountered type variable"))
1229                } else {
1230                    Ok(ty)
1231                }
1232            }
1233            None => {
1234                // FIXME: We shouldn't be relying on the infcx being tainted.
1235                self.cx.tainted_by_errors()?;
1236                bug!(
1237                    "no type for node {} in mem_categorization",
1238                    self.cx.tcx().hir_id_to_string(id)
1239                );
1240            }
1241        }
1242    }
1243
1244    fn node_ty(&self, hir_id: HirId) -> Result<Ty<'tcx>, Cx::Error> {
1245        self.resolve_type_vars_or_error(hir_id, self.cx.typeck_results().node_type_opt(hir_id))
1246    }
1247
1248    fn expr_ty(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
1249        self.resolve_type_vars_or_error(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr))
1250    }
1251
1252    fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
1253        self.resolve_type_vars_or_error(
1254            expr.hir_id,
1255            self.cx.typeck_results().expr_ty_adjusted_opt(expr),
1256        )
1257    }
1258
1259    /// Returns the type of value that this pattern matches against.
1260    /// Some non-obvious cases:
1261    ///
1262    /// - a `ref x` binding matches against a value of type `T` and gives
1263    ///   `x` the type `&T`; we return `T`.
1264    /// - a pattern with implicit derefs (thanks to default binding
1265    ///   modes #42640) may look like `Some(x)` but in fact have
1266    ///   implicit deref patterns attached (e.g., it is really
1267    ///   `&Some(x)`). In that case, we return the "outermost" type
1268    ///   (e.g., `&Option<T>`).
1269    fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> Result<Ty<'tcx>, Cx::Error> {
1270        // Check for implicit `&` types wrapping the pattern; note
1271        // that these are never attached to binding patterns, so
1272        // actually this is somewhat "disjoint" from the code below
1273        // that aims to account for `ref x`.
1274        if let Some(vec) = self.cx.typeck_results().pat_adjustments().get(pat.hir_id) {
1275            if let Some(first_ty) = vec.first() {
1276                debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
1277                return Ok(*first_ty);
1278            }
1279        } else if let PatKind::Ref(subpat, _) = pat.kind
1280            && self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id)
1281        {
1282            return self.pat_ty_adjusted(subpat);
1283        }
1284
1285        self.pat_ty_unadjusted(pat)
1286    }
1287
1288    /// Like `TypeckResults::pat_ty`, but ignores implicit `&` patterns.
1289    fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> Result<Ty<'tcx>, Cx::Error> {
1290        let base_ty = self.node_ty(pat.hir_id)?;
1291        trace!(?base_ty);
1292
1293        // This code detects whether we are looking at a `ref x`,
1294        // and if so, figures out what the type *being borrowed* is.
1295        match pat.kind {
1296            PatKind::Binding(..) => {
1297                let bm = *self
1298                    .cx
1299                    .typeck_results()
1300                    .pat_binding_modes()
1301                    .get(pat.hir_id)
1302                    .expect("missing binding mode");
1303
1304                if matches!(bm.0, hir::ByRef::Yes(_)) {
1305                    // a bind-by-ref means that the base_ty will be the type of the ident itself,
1306                    // but what we want here is the type of the underlying value being borrowed.
1307                    // So peel off one-level, turning the &T into T.
1308                    match self
1309                        .cx
1310                        .try_structurally_resolve_type(pat.span, base_ty)
1311                        .builtin_deref(false)
1312                    {
1313                        Some(ty) => Ok(ty),
1314                        None => {
1315                            debug!("By-ref binding of non-derefable type");
1316                            Err(self
1317                                .cx
1318                                .report_error(pat.span, "by-ref binding of non-derefable type"))
1319                        }
1320                    }
1321                } else {
1322                    Ok(base_ty)
1323                }
1324            }
1325            _ => Ok(base_ty),
1326        }
1327    }
1328
1329    fn cat_expr(&self, expr: &hir::Expr<'_>) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1330        self.cat_expr_(expr, self.cx.typeck_results().expr_adjustments(expr))
1331    }
1332
1333    /// This recursion helper avoids going through *too many*
1334    /// adjustments, since *only* non-overloaded deref recurses.
1335    fn cat_expr_(
1336        &self,
1337        expr: &hir::Expr<'_>,
1338        adjustments: &[adjustment::Adjustment<'tcx>],
1339    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1340        match adjustments.split_last() {
1341            None => self.cat_expr_unadjusted(expr),
1342            Some((adjustment, previous)) => {
1343                self.cat_expr_adjusted_with(expr, || self.cat_expr_(expr, previous), adjustment)
1344            }
1345        }
1346    }
1347
1348    fn cat_expr_adjusted(
1349        &self,
1350        expr: &hir::Expr<'_>,
1351        previous: PlaceWithHirId<'tcx>,
1352        adjustment: &adjustment::Adjustment<'tcx>,
1353    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1354        self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
1355    }
1356
1357    fn cat_expr_adjusted_with<F>(
1358        &self,
1359        expr: &hir::Expr<'_>,
1360        previous: F,
1361        adjustment: &adjustment::Adjustment<'tcx>,
1362    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
1363    where
1364        F: FnOnce() -> Result<PlaceWithHirId<'tcx>, Cx::Error>,
1365    {
1366        let target = self.cx.resolve_vars_if_possible(adjustment.target);
1367        match adjustment.kind {
1368            adjustment::Adjust::Deref(overloaded) => {
1369                // Equivalent to *expr or something similar.
1370                let base = if let Some(deref) = overloaded {
1371                    let ref_ty = Ty::new_ref(
1372                        self.cx.tcx(),
1373                        self.cx.tcx().lifetimes.re_erased,
1374                        target,
1375                        deref.mutbl,
1376                    );
1377                    self.cat_rvalue(expr.hir_id, ref_ty)
1378                } else {
1379                    previous()?
1380                };
1381                self.cat_deref(expr.hir_id, base)
1382            }
1383
1384            adjustment::Adjust::NeverToAny
1385            | adjustment::Adjust::Pointer(_)
1386            | adjustment::Adjust::Borrow(_)
1387            | adjustment::Adjust::ReborrowPin(..) => {
1388                // Result is an rvalue.
1389                Ok(self.cat_rvalue(expr.hir_id, target))
1390            }
1391        }
1392    }
1393
1394    fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1395        let expr_ty = self.expr_ty(expr)?;
1396        match expr.kind {
1397            hir::ExprKind::Unary(hir::UnOp::Deref, e_base) => {
1398                if self.cx.typeck_results().is_method_call(expr) {
1399                    self.cat_overloaded_place(expr, e_base)
1400                } else {
1401                    let base = self.cat_expr(e_base)?;
1402                    self.cat_deref(expr.hir_id, base)
1403                }
1404            }
1405
1406            hir::ExprKind::Field(base, _) => {
1407                let base = self.cat_expr(base)?;
1408                debug!(?base);
1409
1410                let field_idx = self
1411                    .cx
1412                    .typeck_results()
1413                    .field_indices()
1414                    .get(expr.hir_id)
1415                    .cloned()
1416                    .expect("Field index not found");
1417
1418                Ok(self.cat_projection(
1419                    expr.hir_id,
1420                    base,
1421                    expr_ty,
1422                    ProjectionKind::Field(field_idx, FIRST_VARIANT),
1423                ))
1424            }
1425
1426            hir::ExprKind::Index(base, _, _) => {
1427                if self.cx.typeck_results().is_method_call(expr) {
1428                    // If this is an index implemented by a method call, then it
1429                    // will include an implicit deref of the result.
1430                    // The call to index() returns a `&T` value, which
1431                    // is an rvalue. That is what we will be
1432                    // dereferencing.
1433                    self.cat_overloaded_place(expr, base)
1434                } else {
1435                    let base = self.cat_expr(base)?;
1436                    Ok(self.cat_projection(expr.hir_id, base, expr_ty, ProjectionKind::Index))
1437                }
1438            }
1439
1440            hir::ExprKind::Path(ref qpath) => {
1441                let res = self.cx.typeck_results().qpath_res(qpath, expr.hir_id);
1442                self.cat_res(expr.hir_id, expr.span, expr_ty, res)
1443            }
1444
1445            // both type ascription and unsafe binder casts don't affect
1446            // the place-ness of the subexpression.
1447            hir::ExprKind::Type(e, _) => self.cat_expr(e),
1448            hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e),
1449
1450            hir::ExprKind::AddrOf(..)
1451            | hir::ExprKind::Call(..)
1452            | hir::ExprKind::Use(..)
1453            | hir::ExprKind::Assign(..)
1454            | hir::ExprKind::AssignOp(..)
1455            | hir::ExprKind::Closure { .. }
1456            | hir::ExprKind::Ret(..)
1457            | hir::ExprKind::Become(..)
1458            | hir::ExprKind::Unary(..)
1459            | hir::ExprKind::Yield(..)
1460            | hir::ExprKind::MethodCall(..)
1461            | hir::ExprKind::Cast(..)
1462            | hir::ExprKind::DropTemps(..)
1463            | hir::ExprKind::Array(..)
1464            | hir::ExprKind::If(..)
1465            | hir::ExprKind::Tup(..)
1466            | hir::ExprKind::Binary(..)
1467            | hir::ExprKind::Block(..)
1468            | hir::ExprKind::Let(..)
1469            | hir::ExprKind::Loop(..)
1470            | hir::ExprKind::Match(..)
1471            | hir::ExprKind::Lit(..)
1472            | hir::ExprKind::ConstBlock(..)
1473            | hir::ExprKind::Break(..)
1474            | hir::ExprKind::Continue(..)
1475            | hir::ExprKind::Struct(..)
1476            | hir::ExprKind::Repeat(..)
1477            | hir::ExprKind::InlineAsm(..)
1478            | hir::ExprKind::OffsetOf(..)
1479            | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)),
1480        }
1481    }
1482
1483    fn cat_res(
1484        &self,
1485        hir_id: HirId,
1486        span: Span,
1487        expr_ty: Ty<'tcx>,
1488        res: Res,
1489    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1490        match res {
1491            Res::Def(
1492                DefKind::Ctor(..)
1493                | DefKind::Const
1494                | DefKind::ConstParam
1495                | DefKind::AssocConst
1496                | DefKind::Fn
1497                | DefKind::AssocFn,
1498                _,
1499            )
1500            | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, expr_ty)),
1501
1502            Res::Def(DefKind::Static { .. }, _) => {
1503                Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
1504            }
1505
1506            Res::Local(var_id) => {
1507                if self.upvars.is_some_and(|upvars| upvars.contains_key(&var_id)) {
1508                    self.cat_upvar(hir_id, var_id)
1509                } else {
1510                    Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new()))
1511                }
1512            }
1513
1514            def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def),
1515        }
1516    }
1517
1518    /// Categorize an upvar.
1519    ///
1520    /// Note: the actual upvar access contains invisible derefs of closure
1521    /// environment and upvar reference as appropriate. Only regionck cares
1522    /// about these dereferences, so we let it compute them as needed.
1523    fn cat_upvar(&self, hir_id: HirId, var_id: HirId) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1524        let closure_expr_def_id = self.cx.body_owner_def_id();
1525
1526        let upvar_id = ty::UpvarId {
1527            var_path: ty::UpvarPath { hir_id: var_id },
1528            closure_expr_id: closure_expr_def_id,
1529        };
1530        let var_ty = self.node_ty(var_id)?;
1531
1532        Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()))
1533    }
1534
1535    fn cat_rvalue(&self, hir_id: HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx> {
1536        PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
1537    }
1538
1539    fn cat_projection(
1540        &self,
1541        node: HirId,
1542        base_place: PlaceWithHirId<'tcx>,
1543        ty: Ty<'tcx>,
1544        kind: ProjectionKind,
1545    ) -> PlaceWithHirId<'tcx> {
1546        let place_ty = base_place.place.ty();
1547        let mut projections = base_place.place.projections;
1548
1549        let node_ty = self.cx.typeck_results().node_type(node);
1550        // Opaque types can't have field projections, but we can instead convert
1551        // the current place in-place (heh) to the hidden type, and then apply all
1552        // follow up projections on that.
1553        if node_ty != place_ty
1554            && self
1555                .cx
1556                .try_structurally_resolve_type(
1557                    self.cx.tcx().hir().span(base_place.hir_id),
1558                    place_ty,
1559                )
1560                .is_impl_trait()
1561        {
1562            projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
1563        }
1564        projections.push(Projection { kind, ty });
1565        PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections)
1566    }
1567
1568    fn cat_overloaded_place(
1569        &self,
1570        expr: &hir::Expr<'_>,
1571        base: &hir::Expr<'_>,
1572    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1573        // Reconstruct the output assuming it's a reference with the
1574        // same region and mutability as the receiver. This holds for
1575        // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
1576        let place_ty = self.expr_ty(expr)?;
1577        let base_ty = self.expr_ty_adjusted(base)?;
1578
1579        let ty::Ref(region, _, mutbl) =
1580            *self.cx.try_structurally_resolve_type(base.span, base_ty).kind()
1581        else {
1582            span_bug!(expr.span, "cat_overloaded_place: base is not a reference");
1583        };
1584        let ref_ty = Ty::new_ref(self.cx.tcx(), region, place_ty, mutbl);
1585
1586        let base = self.cat_rvalue(expr.hir_id, ref_ty);
1587        self.cat_deref(expr.hir_id, base)
1588    }
1589
1590    fn cat_deref(
1591        &self,
1592        node: HirId,
1593        base_place: PlaceWithHirId<'tcx>,
1594    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1595        let base_curr_ty = base_place.place.ty();
1596        let deref_ty = match self
1597            .cx
1598            .try_structurally_resolve_type(
1599                self.cx.tcx().hir().span(base_place.hir_id),
1600                base_curr_ty,
1601            )
1602            .builtin_deref(true)
1603        {
1604            Some(ty) => ty,
1605            None => {
1606                debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
1607                return Err(self.cx.report_error(
1608                    self.cx.tcx().hir().span(node),
1609                    "explicit deref of non-derefable type",
1610                ));
1611            }
1612        };
1613        let mut projections = base_place.place.projections;
1614        projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });
1615
1616        Ok(PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections))
1617    }
1618
1619    /// Returns the variant index for an ADT used within a Struct or TupleStruct pattern
1620    /// Here `pat_hir_id` is the HirId of the pattern itself.
1621    fn variant_index_for_adt(
1622        &self,
1623        qpath: &hir::QPath<'_>,
1624        pat_hir_id: HirId,
1625        span: Span,
1626    ) -> Result<VariantIdx, Cx::Error> {
1627        let res = self.cx.typeck_results().qpath_res(qpath, pat_hir_id);
1628        let ty = self.cx.typeck_results().node_type(pat_hir_id);
1629        let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else {
1630            return Err(self
1631                .cx
1632                .report_error(span, "struct or tuple struct pattern not applied to an ADT"));
1633        };
1634
1635        match res {
1636            Res::Def(DefKind::Variant, variant_id) => Ok(adt_def.variant_index_with_id(variant_id)),
1637            Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
1638                Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id))
1639            }
1640            Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
1641            | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
1642            | Res::SelfCtor(..)
1643            | Res::SelfTyParam { .. }
1644            | Res::SelfTyAlias { .. } => {
1645                // Structs and Unions have only have one variant.
1646                Ok(FIRST_VARIANT)
1647            }
1648            _ => bug!("expected ADT path, found={:?}", res),
1649        }
1650    }
1651
1652    /// Returns the total number of fields in an ADT variant used within a pattern.
1653    /// Here `pat_hir_id` is the HirId of the pattern itself.
1654    fn total_fields_in_adt_variant(
1655        &self,
1656        pat_hir_id: HirId,
1657        variant_index: VariantIdx,
1658        span: Span,
1659    ) -> Result<usize, Cx::Error> {
1660        let ty = self.cx.typeck_results().node_type(pat_hir_id);
1661        match self.cx.try_structurally_resolve_type(span, ty).kind() {
1662            ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()),
1663            _ => {
1664                self.cx
1665                    .tcx()
1666                    .dcx()
1667                    .span_bug(span, "struct or tuple struct pattern not applied to an ADT");
1668            }
1669        }
1670    }
1671
1672    /// Returns the total number of fields in a tuple used within a Tuple pattern.
1673    /// Here `pat_hir_id` is the HirId of the pattern itself.
1674    fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> Result<usize, Cx::Error> {
1675        let ty = self.cx.typeck_results().node_type(pat_hir_id);
1676        match self.cx.try_structurally_resolve_type(span, ty).kind() {
1677            ty::Tuple(args) => Ok(args.len()),
1678            _ => Err(self.cx.report_error(span, "tuple pattern not applied to a tuple")),
1679        }
1680    }
1681
1682    /// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
1683    /// is being matched against.
1684    ///
1685    /// In general, the way that this works is that we walk down the pattern,
1686    /// constructing a `PlaceWithHirId` that represents the path that will be taken
1687    /// to reach the value being matched.
1688    fn cat_pattern<F>(
1689        &self,
1690        mut place_with_id: PlaceWithHirId<'tcx>,
1691        pat: &hir::Pat<'_>,
1692        op: &mut F,
1693    ) -> Result<(), Cx::Error>
1694    where
1695        F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>) -> Result<(), Cx::Error>,
1696    {
1697        // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly.
1698        // `PlaceWithHirId`s are constructed differently from patterns. For example, in
1699        //
1700        // ```
1701        // match foo {
1702        //     &&Some(x, ) => { ... },
1703        //     _ => { ... },
1704        // }
1705        // ```
1706        //
1707        // the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the
1708        // corresponding `PlaceWithHirId` we start with the `PlaceWithHirId` for `foo`, and then, by traversing the
1709        // pattern, try to answer the question: given the address of `foo`, how is `x` reached?
1710        //
1711        // `&&Some(x,)` `place_foo`
1712        //  `&Some(x,)` `deref { place_foo}`
1713        //   `Some(x,)` `deref { deref { place_foo }}`
1714        //       `(x,)` `field0 { deref { deref { place_foo }}}` <- resulting place
1715        //
1716        // The above example has no adjustments. If the code were instead the (after adjustments,
1717        // equivalent) version
1718        //
1719        // ```
1720        // match foo {
1721        //     Some(x, ) => { ... },
1722        //     _ => { ... },
1723        // }
1724        // ```
1725        //
1726        // Then we see that to get the same result, we must start with
1727        // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
1728        // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
1729        for _ in
1730            0..self.cx.typeck_results().pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len())
1731        {
1732            debug!("applying adjustment to place_with_id={:?}", place_with_id);
1733            place_with_id = self.cat_deref(pat.hir_id, place_with_id)?;
1734        }
1735        let place_with_id = place_with_id; // lose mutability
1736        debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
1737
1738        // Invoke the callback, but only now, after the `place_with_id` has adjusted.
1739        //
1740        // To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that
1741        // case, the initial `place_with_id` will be that for `&Some(3)` and the pattern is `Some(x)`. We
1742        // don't want to call `op` with these incompatible values. As written, what happens instead
1743        // is that `op` is called with the adjusted place (that for `*&Some(3)`) and the pattern
1744        // `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)`
1745        // result in the place `Downcast<Some>(*&Some(3)).0` associated to `x` and invoke `op` with
1746        // that (where the `ref` on `x` is implied).
1747        op(&place_with_id, pat)?;
1748
1749        match pat.kind {
1750            PatKind::Tuple(subpats, dots_pos) => {
1751                // (p1, ..., pN)
1752                let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?;
1753
1754                for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
1755                    let subpat_ty = self.pat_ty_adjusted(subpat)?;
1756                    let projection_kind =
1757                        ProjectionKind::Field(FieldIdx::from_usize(i), FIRST_VARIANT);
1758                    let sub_place = self.cat_projection(
1759                        pat.hir_id,
1760                        place_with_id.clone(),
1761                        subpat_ty,
1762                        projection_kind,
1763                    );
1764                    self.cat_pattern(sub_place, subpat, op)?;
1765                }
1766            }
1767
1768            PatKind::TupleStruct(ref qpath, subpats, dots_pos) => {
1769                // S(p1, ..., pN)
1770                let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
1771                let total_fields =
1772                    self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?;
1773
1774                for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
1775                    let subpat_ty = self.pat_ty_adjusted(subpat)?;
1776                    let projection_kind =
1777                        ProjectionKind::Field(FieldIdx::from_usize(i), variant_index);
1778                    let sub_place = self.cat_projection(
1779                        pat.hir_id,
1780                        place_with_id.clone(),
1781                        subpat_ty,
1782                        projection_kind,
1783                    );
1784                    self.cat_pattern(sub_place, subpat, op)?;
1785                }
1786            }
1787
1788            PatKind::Struct(ref qpath, field_pats, _) => {
1789                // S { f1: p1, ..., fN: pN }
1790
1791                let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
1792
1793                for fp in field_pats {
1794                    let field_ty = self.pat_ty_adjusted(fp.pat)?;
1795                    let field_index = self
1796                        .cx
1797                        .typeck_results()
1798                        .field_indices()
1799                        .get(fp.hir_id)
1800                        .cloned()
1801                        .expect("no index for a field");
1802
1803                    let field_place = self.cat_projection(
1804                        pat.hir_id,
1805                        place_with_id.clone(),
1806                        field_ty,
1807                        ProjectionKind::Field(field_index, variant_index),
1808                    );
1809                    self.cat_pattern(field_place, fp.pat, op)?;
1810                }
1811            }
1812
1813            PatKind::Or(pats) => {
1814                for pat in pats {
1815                    self.cat_pattern(place_with_id.clone(), pat, op)?;
1816                }
1817            }
1818
1819            PatKind::Binding(.., Some(subpat)) | PatKind::Guard(subpat, _) => {
1820                self.cat_pattern(place_with_id, subpat, op)?;
1821            }
1822
1823            PatKind::Ref(subpat, _)
1824                if self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id) =>
1825            {
1826                self.cat_pattern(place_with_id, subpat, op)?;
1827            }
1828
1829            PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
1830                // box p1, &p1, &mut p1. we can ignore the mutability of
1831                // PatKind::Ref since that information is already contained
1832                // in the type.
1833                let subplace = self.cat_deref(pat.hir_id, place_with_id)?;
1834                self.cat_pattern(subplace, subpat, op)?;
1835            }
1836            PatKind::Deref(subpat) => {
1837                let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpat);
1838                let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
1839                let re_erased = self.cx.tcx().lifetimes.re_erased;
1840                let ty = self.pat_ty_adjusted(subpat)?;
1841                let ty = Ty::new_ref(self.cx.tcx(), re_erased, ty, mutability);
1842                // A deref pattern generates a temporary.
1843                let base = self.cat_rvalue(pat.hir_id, ty);
1844                let place = self.cat_deref(pat.hir_id, base)?;
1845                self.cat_pattern(place, subpat, op)?;
1846            }
1847
1848            PatKind::Slice(before, ref slice, after) => {
1849                let Some(element_ty) = self
1850                    .cx
1851                    .try_structurally_resolve_type(pat.span, place_with_id.place.ty())
1852                    .builtin_index()
1853                else {
1854                    debug!("explicit index of non-indexable type {:?}", place_with_id);
1855                    return Err(self
1856                        .cx
1857                        .report_error(pat.span, "explicit index of non-indexable type"));
1858                };
1859                let elt_place = self.cat_projection(
1860                    pat.hir_id,
1861                    place_with_id.clone(),
1862                    element_ty,
1863                    ProjectionKind::Index,
1864                );
1865                for before_pat in before {
1866                    self.cat_pattern(elt_place.clone(), before_pat, op)?;
1867                }
1868                if let Some(slice_pat) = *slice {
1869                    let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?;
1870                    let slice_place = self.cat_projection(
1871                        pat.hir_id,
1872                        place_with_id,
1873                        slice_pat_ty,
1874                        ProjectionKind::Subslice,
1875                    );
1876                    self.cat_pattern(slice_place, slice_pat, op)?;
1877                }
1878                for after_pat in after {
1879                    self.cat_pattern(elt_place.clone(), after_pat, op)?;
1880                }
1881            }
1882
1883            PatKind::Binding(.., None)
1884            | PatKind::Expr(..)
1885            | PatKind::Range(..)
1886            | PatKind::Never
1887            | PatKind::Wild
1888            | PatKind::Err(_) => {
1889                // always ok
1890            }
1891        }
1892
1893        Ok(())
1894    }
1895
1896    fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
1897        if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() {
1898            // Note that if a non-exhaustive SingleVariant is defined in another crate, we need
1899            // to assume that more cases will be added to the variant in the future. This mean
1900            // that we should handle non-exhaustive SingleVariant the same way we would handle
1901            // a MultiVariant.
1902            def.variants().len() > 1 || def.variant_list_has_applicable_non_exhaustive()
1903        } else {
1904            false
1905        }
1906    }
1907}