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//!
5//! In the compiler, this is only used for upvar inference, but there
6//! are many uses within clippy.
7
8use std::cell::{Ref, RefCell};
9use std::ops::Deref;
10use std::slice::from_ref;
11
12use hir::Expr;
13use hir::def::DefKind;
14use hir::pat_util::EnumerateAndAdjustIterator as _;
15use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
16use rustc_data_structures::fx::FxIndexMap;
17use rustc_hir::def::{CtorOf, Res};
18use rustc_hir::def_id::LocalDefId;
19use rustc_hir::{self as hir, HirId, PatExpr, PatExprKind, PatKind};
20use rustc_lint::LateContext;
21use rustc_middle::hir::place::ProjectionKind;
22// Export these here so that Clippy can use them.
23pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
24use rustc_middle::mir::FakeReadCause;
25use rustc_middle::ty::{
26    self, BorrowKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, adjustment,
27};
28use rustc_middle::{bug, span_bug};
29use rustc_span::{ErrorGuaranteed, Span};
30use rustc_trait_selection::infer::InferCtxtExt;
31use tracing::{debug, instrument, trace};
32
33use crate::fn_ctxt::FnCtxt;
34
35/// This trait defines the callbacks you can expect to receive when
36/// employing the ExprUseVisitor.
37pub trait Delegate<'tcx> {
38    /// The value found at `place` is moved, depending
39    /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
40    ///
41    /// If the value is `Copy`, [`copy`][Self::copy] is called instead, which
42    /// by default falls back to [`borrow`][Self::borrow].
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    ///
77    /// If an implementation is not provided, use of a `Copy` type in a ByValue context is instead
78    /// considered a use by `ImmBorrow` and `borrow` is called instead. This is because a shared
79    /// borrow is the "minimum access" that would be needed to perform a copy.
80    fn copy(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
81        // In most cases, copying data from `x` is equivalent to doing `*&x`, so by default
82        // we treat a copy of `x` as a borrow of `x`.
83        self.borrow(place_with_id, diag_expr_id, ty::BorrowKind::Immutable)
84    }
85
86    /// The path at `assignee_place` is being assigned to.
87    /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
88    fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
89
90    /// The path at `binding_place` is a binding that is being initialized.
91    ///
92    /// This covers cases such as `let x = 42;`
93    fn bind(&mut self, binding_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
94        // Bindings can normally be treated as a regular assignment, so by default we
95        // forward this to the mutate callback.
96        self.mutate(binding_place, diag_expr_id)
97    }
98
99    /// The `place` should be a fake read because of specified `cause`.
100    fn fake_read(
101        &mut self,
102        place_with_id: &PlaceWithHirId<'tcx>,
103        cause: FakeReadCause,
104        diag_expr_id: HirId,
105    );
106}
107
108impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D {
109    fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
110        (**self).consume(place_with_id, diag_expr_id)
111    }
112
113    fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
114        (**self).use_cloned(place_with_id, diag_expr_id)
115    }
116
117    fn borrow(
118        &mut self,
119        place_with_id: &PlaceWithHirId<'tcx>,
120        diag_expr_id: HirId,
121        bk: ty::BorrowKind,
122    ) {
123        (**self).borrow(place_with_id, diag_expr_id, bk)
124    }
125
126    fn copy(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
127        (**self).copy(place_with_id, diag_expr_id)
128    }
129
130    fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
131        (**self).mutate(assignee_place, diag_expr_id)
132    }
133
134    fn bind(&mut self, binding_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
135        (**self).bind(binding_place, diag_expr_id)
136    }
137
138    fn fake_read(
139        &mut self,
140        place_with_id: &PlaceWithHirId<'tcx>,
141        cause: FakeReadCause,
142        diag_expr_id: HirId,
143    ) {
144        (**self).fake_read(place_with_id, cause, diag_expr_id)
145    }
146}
147
148/// This trait makes `ExprUseVisitor` usable with both [`FnCtxt`]
149/// and [`LateContext`], depending on where in the compiler it is used.
150pub trait TypeInformationCtxt<'tcx> {
151    type TypeckResults<'a>: Deref<Target = ty::TypeckResults<'tcx>>
152    where
153        Self: 'a;
154
155    type Error;
156
157    fn typeck_results(&self) -> Self::TypeckResults<'_>;
158
159    fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T;
160
161    fn structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
162
163    fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error;
164
165    fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error>;
166
167    fn tainted_by_errors(&self) -> Result<(), Self::Error>;
168
169    fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
170
171    fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
172
173    fn body_owner_def_id(&self) -> LocalDefId;
174
175    fn tcx(&self) -> TyCtxt<'tcx>;
176}
177
178impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
179    type TypeckResults<'a>
180        = Ref<'a, ty::TypeckResults<'tcx>>
181    where
182        Self: 'a;
183
184    type Error = ErrorGuaranteed;
185
186    fn typeck_results(&self) -> Self::TypeckResults<'_> {
187        self.typeck_results.borrow()
188    }
189
190    fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
191        self.infcx.resolve_vars_if_possible(t)
192    }
193
194    fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
195        (**self).structurally_resolve_type(sp, ty)
196    }
197
198    fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error {
199        self.dcx().span_delayed_bug(span, msg.to_string())
200    }
201
202    fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error> {
203        ty.error_reported()
204    }
205
206    fn tainted_by_errors(&self) -> Result<(), ErrorGuaranteed> {
207        if let Some(guar) = self.infcx.tainted_by_errors() { Err(guar) } else { Ok(()) }
208    }
209
210    fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
211        self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
212    }
213
214    fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
215        self.infcx.type_is_use_cloned_modulo_regions(self.param_env, ty)
216    }
217
218    fn body_owner_def_id(&self) -> LocalDefId {
219        self.body_id
220    }
221
222    fn tcx(&self) -> TyCtxt<'tcx> {
223        self.tcx
224    }
225}
226
227impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
228    type TypeckResults<'a>
229        = &'tcx ty::TypeckResults<'tcx>
230    where
231        Self: 'a;
232
233    type Error = !;
234
235    fn typeck_results(&self) -> Self::TypeckResults<'_> {
236        self.0.maybe_typeck_results().expect("expected typeck results")
237    }
238
239    fn structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
240        // FIXME: Maybe need to normalize here.
241        ty
242    }
243
244    fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
245        t
246    }
247
248    fn report_bug(&self, span: Span, msg: impl ToString) -> ! {
249        span_bug!(span, "{}", msg.to_string())
250    }
251
252    fn error_reported_in_ty(&self, _ty: Ty<'tcx>) -> Result<(), !> {
253        Ok(())
254    }
255
256    fn tainted_by_errors(&self) -> Result<(), !> {
257        Ok(())
258    }
259
260    fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
261        self.0.type_is_copy_modulo_regions(ty)
262    }
263
264    fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
265        self.0.type_is_use_cloned_modulo_regions(ty)
266    }
267
268    fn body_owner_def_id(&self) -> LocalDefId {
269        self.1
270    }
271
272    fn tcx(&self) -> TyCtxt<'tcx> {
273        self.0.tcx
274    }
275}
276
277/// A visitor that reports how each expression is being used.
278///
279/// See [module-level docs][self] and [`Delegate`] for details.
280pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> {
281    cx: Cx,
282    /// We use a `RefCell` here so that delegates can mutate themselves, but we can
283    /// still have calls to our own helper functions.
284    delegate: RefCell<D>,
285    upvars: Option<&'tcx FxIndexMap<HirId, hir::Upvar>>,
286}
287
288impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'tcx, (&'a LateContext<'tcx>, LocalDefId), D> {
289    pub fn for_clippy(cx: &'a LateContext<'tcx>, body_def_id: LocalDefId, delegate: D) -> Self {
290        Self::new((cx, body_def_id), delegate)
291    }
292}
293
294impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> {
295    /// Creates the ExprUseVisitor, configuring it with the various options provided:
296    ///
297    /// - `delegate` -- who receives the callbacks
298    /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`)
299    /// - `typeck_results` --- typeck results for the code being analyzed
300    pub(crate) fn new(cx: Cx, delegate: D) -> Self {
301        ExprUseVisitor {
302            delegate: RefCell::new(delegate),
303            upvars: cx.tcx().upvars_mentioned(cx.body_owner_def_id()),
304            cx,
305        }
306    }
307
308    pub fn consume_body(&self, body: &hir::Body<'_>) -> Result<(), Cx::Error> {
309        for param in body.params {
310            let param_ty = self.pat_ty_adjusted(param.pat)?;
311            debug!("consume_body: param_ty = {:?}", param_ty);
312
313            let param_place = self.cat_rvalue(param.hir_id, param_ty);
314
315            self.walk_irrefutable_pat(&param_place, param.pat)?;
316        }
317
318        self.consume_expr(body.value)?;
319
320        Ok(())
321    }
322
323    #[instrument(skip(self), level = "debug")]
324    fn consume_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
325        if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
326            self.delegate.borrow_mut().copy(place_with_id, diag_expr_id);
327        } else {
328            self.delegate.borrow_mut().consume(place_with_id, diag_expr_id);
329        }
330    }
331
332    #[instrument(skip(self), level = "debug")]
333    pub fn consume_clone_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
334        // `x.use` will do one of the following
335        // * if it implements `Copy`, it will be a copy
336        // * if it implements `UseCloned`, it will be a call to `clone`
337        // * otherwise, it is a move
338        //
339        // we do a conservative approximation of this, treating it as a move unless we know that it implements copy or `UseCloned`
340        if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
341            self.delegate.borrow_mut().copy(place_with_id, diag_expr_id);
342        } else if self.cx.type_is_use_cloned_modulo_regions(place_with_id.place.ty()) {
343            self.delegate.borrow_mut().use_cloned(place_with_id, diag_expr_id);
344        } else {
345            self.delegate.borrow_mut().consume(place_with_id, diag_expr_id);
346        }
347    }
348
349    fn consume_exprs(&self, exprs: &[hir::Expr<'_>]) -> Result<(), Cx::Error> {
350        for expr in exprs {
351            self.consume_expr(expr)?;
352        }
353
354        Ok(())
355    }
356
357    // FIXME: It's suspicious that this is public; clippy should probably use `walk_expr`.
358    #[instrument(skip(self), level = "debug")]
359    pub fn consume_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
360        let place_with_id = self.cat_expr(expr)?;
361        self.consume_or_copy(&place_with_id, place_with_id.hir_id);
362        self.walk_expr(expr)?;
363        Ok(())
364    }
365
366    #[instrument(skip(self), level = "debug")]
367    pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
368        let place_with_id = self.cat_expr(expr)?;
369        self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id);
370        self.walk_expr(expr)?;
371        Ok(())
372    }
373
374    fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
375        let place_with_id = self.cat_expr(expr)?;
376        self.delegate.borrow_mut().mutate(&place_with_id, place_with_id.hir_id);
377        self.walk_expr(expr)?;
378        Ok(())
379    }
380
381    #[instrument(skip(self), level = "debug")]
382    fn borrow_expr(&self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) -> Result<(), Cx::Error> {
383        let place_with_id = self.cat_expr(expr)?;
384        self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
385        self.walk_expr(expr)
386    }
387
388    #[instrument(skip(self), level = "debug")]
389    pub fn walk_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
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::Missing => unreachable!(),
615                    PatKind::Binding(.., opt_sub_pat) => {
616                        // If the opt_sub_pat is None, then the binding does not count as
617                        // a wildcard for the purpose of borrowing discr.
618                        if opt_sub_pat.is_none() {
619                            needs_to_be_read = true;
620                        }
621                    }
622                    PatKind::Never => {
623                        // A never pattern reads the value.
624                        // FIXME(never_patterns): does this do what I expect?
625                        needs_to_be_read = true;
626                    }
627                    PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
628                        // A `Path` pattern is just a name like `Foo`. This is either a
629                        // named constant or else it refers to an ADT variant
630
631                        let res = self.cx.typeck_results().qpath_res(qpath, *hir_id);
632                        match res {
633                            Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
634                                // Named constants have to be equated with the value
635                                // being matched, so that's a read of the value being matched.
636                                //
637                                // FIXME: We don't actually reads for ZSTs.
638                                needs_to_be_read = true;
639                            }
640                            _ => {
641                                // Otherwise, this is a struct/enum variant, and so it's
642                                // only a read if we need to read the discriminant.
643                                needs_to_be_read |=
644                                    self.is_multivariant_adt(place.place.ty(), *span);
645                            }
646                        }
647                    }
648                    PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
649                        // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
650                        // against a multivariant enum or struct. In that case, we have to read
651                        // the discriminant. Otherwise this kind of pattern doesn't actually
652                        // read anything (we'll get invoked for the `...`, which may indeed
653                        // perform some reads).
654
655                        let place_ty = place.place.ty();
656                        needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span);
657                    }
658                    PatKind::Expr(_) | PatKind::Range(..) => {
659                        // If the PatKind is a Lit or a Range then we want
660                        // to borrow discr.
661                        needs_to_be_read = true;
662                    }
663                    PatKind::Slice(lhs, wild, rhs) => {
664                        // We don't need to test the length if the pattern is `[..]`
665                        if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
666                            // Arrays have a statically known size, so
667                            // there is no need to read their length
668                            || place.place.ty().peel_refs().is_array()
669                        {
670                        } else {
671                            needs_to_be_read = true;
672                        }
673                    }
674                    PatKind::Or(_)
675                    | PatKind::Box(_)
676                    | PatKind::Deref(_)
677                    | PatKind::Ref(..)
678                    | PatKind::Guard(..)
679                    | PatKind::Wild
680                    | PatKind::Err(_) => {
681                        // If the PatKind is Or, Box, or Ref, the decision is made later
682                        // as these patterns contains subpatterns
683                        // If the PatKind is Wild or Err, the decision is made based on the other patterns
684                        // being examined
685                    }
686                }
687
688                Ok(())
689            })?
690        }
691
692        if needs_to_be_read {
693            self.borrow_expr(discr, BorrowKind::Immutable)?;
694        } else {
695            let closure_def_id = match discr_place.place.base {
696                PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
697                _ => None,
698            };
699
700            self.delegate.borrow_mut().fake_read(
701                &discr_place,
702                FakeReadCause::ForMatchedPlace(closure_def_id),
703                discr_place.hir_id,
704            );
705
706            // We always want to walk the discriminant. We want to make sure, for instance,
707            // that the discriminant has been initialized.
708            self.walk_expr(discr)?;
709        }
710        Ok(())
711    }
712
713    fn walk_local<F>(
714        &self,
715        expr: &hir::Expr<'_>,
716        pat: &hir::Pat<'_>,
717        els: Option<&hir::Block<'_>>,
718        mut f: F,
719    ) -> Result<(), Cx::Error>
720    where
721        F: FnMut() -> Result<(), Cx::Error>,
722    {
723        self.walk_expr(expr)?;
724        let expr_place = self.cat_expr(expr)?;
725        f()?;
726        if let Some(els) = els {
727            // borrowing because we need to test the discriminant
728            self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter())?;
729            self.walk_block(els)?;
730        }
731        self.walk_irrefutable_pat(&expr_place, pat)?;
732        Ok(())
733    }
734
735    /// Indicates that the value of `blk` will be consumed, meaning either copied or moved
736    /// depending on its type.
737    #[instrument(skip(self), level = "debug")]
738    fn walk_block(&self, blk: &hir::Block<'_>) -> Result<(), Cx::Error> {
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.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 `expr` represented as a place,
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    #[instrument(skip(self), level = "debug")]
946    fn walk_pat(
947        &self,
948        discr_place: &PlaceWithHirId<'tcx>,
949        pat: &hir::Pat<'_>,
950        has_guard: bool,
951    ) -> Result<(), Cx::Error> {
952        let tcx = self.cx.tcx();
953        self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
954            match pat.kind {
955                PatKind::Binding(_, canonical_id, ..) => {
956                    debug!("walk_pat: binding place={:?} pat={:?}", place, pat);
957                    let bm = self
958                        .cx
959                        .typeck_results()
960                        .extract_binding_mode(tcx.sess, pat.hir_id, pat.span);
961                    debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
962
963                    // pat_ty: the type of the binding being produced.
964                    let pat_ty = self.node_ty(pat.hir_id)?;
965                    debug!("walk_pat: pat_ty={:?}", pat_ty);
966
967                    let def = Res::Local(canonical_id);
968                    if let Ok(ref binding_place) = self.cat_res(pat.hir_id, pat.span, pat_ty, def) {
969                        self.delegate.borrow_mut().bind(binding_place, binding_place.hir_id);
970                    }
971
972                    // Subtle: MIR desugaring introduces immutable borrows for each pattern
973                    // binding when lowering pattern guards to ensure that the guard does not
974                    // modify the scrutinee.
975                    if has_guard {
976                        self.delegate.borrow_mut().borrow(
977                            place,
978                            discr_place.hir_id,
979                            BorrowKind::Immutable,
980                        );
981                    }
982
983                    // It is also a borrow or copy/move of the value being matched.
984                    // In a cases of pattern like `let pat = upvar`, don't use the span
985                    // of the pattern, as this just looks confusing, instead use the span
986                    // of the discriminant.
987                    match bm.0 {
988                        hir::ByRef::Yes(m) => {
989                            let bk = ty::BorrowKind::from_mutbl(m);
990                            self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
991                        }
992                        hir::ByRef::No => {
993                            debug!("walk_pat binding consuming pat");
994                            self.consume_or_copy(place, discr_place.hir_id);
995                        }
996                    }
997                }
998                PatKind::Deref(subpattern) => {
999                    // A deref pattern is a bit special: the binding mode of its inner bindings
1000                    // determines whether to borrow *at the level of the deref pattern* rather than
1001                    // borrowing the bound place (since that inner place is inside the temporary that
1002                    // stores the result of calling `deref()`/`deref_mut()` so can't be captured).
1003                    // Deref patterns on boxes don't borrow, so we ignore them here.
1004                    // HACK: this could be a fake pattern corresponding to a deref inserted by match
1005                    // ergonomics, in which case `pat.hir_id` will be the id of the subpattern.
1006                    if let hir::ByRef::Yes(mutability) =
1007                        self.cx.typeck_results().deref_pat_borrow_mode(place.place.ty(), subpattern)
1008                    {
1009                        let bk = ty::BorrowKind::from_mutbl(mutability);
1010                        self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
1011                    }
1012                }
1013                PatKind::Never => {
1014                    // A `!` pattern always counts as an immutable read of the discriminant,
1015                    // even in an irrefutable pattern.
1016                    self.delegate.borrow_mut().borrow(
1017                        place,
1018                        discr_place.hir_id,
1019                        BorrowKind::Immutable,
1020                    );
1021                }
1022                _ => {}
1023            }
1024
1025            Ok(())
1026        })
1027    }
1028
1029    /// Handle the case where the current body contains a closure.
1030    ///
1031    /// When the current body being handled is a closure, then we must make sure that
1032    /// - The parent closure only captures Places from the nested closure that are not local to it.
1033    ///
1034    /// In the following example the closures `c` only captures `p.x` even though `incr`
1035    /// is a capture of the nested closure
1036    ///
1037    /// ```
1038    /// struct P { x: i32 }
1039    /// let mut p = P { x: 4 };
1040    /// let c = || {
1041    ///    let incr = 10;
1042    ///    let nested = || p.x += incr;
1043    /// };
1044    /// ```
1045    ///
1046    /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
1047    /// closure as the DefId.
1048    #[instrument(skip(self), level = "debug")]
1049    fn walk_captures(&self, closure_expr: &hir::Closure<'_>) -> Result<(), Cx::Error> {
1050        fn upvar_is_local_variable(
1051            upvars: Option<&FxIndexMap<HirId, hir::Upvar>>,
1052            upvar_id: HirId,
1053            body_owner_is_closure: bool,
1054        ) -> bool {
1055            upvars.map(|upvars| !upvars.contains_key(&upvar_id)).unwrap_or(body_owner_is_closure)
1056        }
1057
1058        let tcx = self.cx.tcx();
1059        let closure_def_id = closure_expr.def_id;
1060        // For purposes of this function, coroutine and closures are equivalent.
1061        let body_owner_is_closure = matches!(
1062            tcx.hir_body_owner_kind(self.cx.body_owner_def_id()),
1063            hir::BodyOwnerKind::Closure
1064        );
1065
1066        // If we have a nested closure, we want to include the fake reads present in the nested
1067        // closure.
1068        if let Some(fake_reads) = self.cx.typeck_results().closure_fake_reads.get(&closure_def_id) {
1069            for (fake_read, cause, hir_id) in fake_reads.iter() {
1070                match fake_read.base {
1071                    PlaceBase::Upvar(upvar_id) => {
1072                        if upvar_is_local_variable(
1073                            self.upvars,
1074                            upvar_id.var_path.hir_id,
1075                            body_owner_is_closure,
1076                        ) {
1077                            // The nested closure might be fake reading the current (enclosing) closure's local variables.
1078                            // The only places we want to fake read before creating the parent closure are the ones that
1079                            // are not local to it/ defined by it.
1080                            //
1081                            // ```rust,ignore(cannot-test-this-because-pseudo-code)
1082                            // let v1 = (0, 1);
1083                            // let c = || { // fake reads: v1
1084                            //    let v2 = (0, 1);
1085                            //    let e = || { // fake reads: v1, v2
1086                            //       let (_, t1) = v1;
1087                            //       let (_, t2) = v2;
1088                            //    }
1089                            // }
1090                            // ```
1091                            // This check is performed when visiting the body of the outermost closure (`c`) and ensures
1092                            // that we don't add a fake read of v2 in c.
1093                            continue;
1094                        }
1095                    }
1096                    _ => {
1097                        bug!(
1098                            "Do not know how to get HirId out of Rvalue and StaticItem {:?}",
1099                            fake_read.base
1100                        );
1101                    }
1102                };
1103                self.delegate.borrow_mut().fake_read(
1104                    &PlaceWithHirId { place: fake_read.clone(), hir_id: *hir_id },
1105                    *cause,
1106                    *hir_id,
1107                );
1108            }
1109        }
1110
1111        if let Some(min_captures) =
1112            self.cx.typeck_results().closure_min_captures.get(&closure_def_id)
1113        {
1114            for (var_hir_id, min_list) in min_captures.iter() {
1115                if self
1116                    .upvars
1117                    .map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id))
1118                {
1119                    // The nested closure might be capturing the current (enclosing) closure's local variables.
1120                    // We check if the root variable is ever mentioned within the enclosing closure, if not
1121                    // then for the current body (if it's a closure) these aren't captures, we will ignore them.
1122                    continue;
1123                }
1124                for captured_place in min_list {
1125                    let place = &captured_place.place;
1126                    let capture_info = captured_place.info;
1127
1128                    let place_base = if body_owner_is_closure {
1129                        // Mark the place to be captured by the enclosing closure
1130                        PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.cx.body_owner_def_id()))
1131                    } else {
1132                        // If the body owner isn't a closure then the variable must
1133                        // be a local variable
1134                        PlaceBase::Local(*var_hir_id)
1135                    };
1136                    let closure_hir_id = tcx.local_def_id_to_hir_id(closure_def_id);
1137                    let place_with_id = PlaceWithHirId::new(
1138                        capture_info
1139                            .path_expr_id
1140                            .unwrap_or(capture_info.capture_kind_expr_id.unwrap_or(closure_hir_id)),
1141                        place.base_ty,
1142                        place_base,
1143                        place.projections.clone(),
1144                    );
1145
1146                    match capture_info.capture_kind {
1147                        ty::UpvarCapture::ByValue => {
1148                            self.consume_or_copy(&place_with_id, place_with_id.hir_id);
1149                        }
1150                        ty::UpvarCapture::ByUse => {
1151                            self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id);
1152                        }
1153                        ty::UpvarCapture::ByRef(upvar_borrow) => {
1154                            self.delegate.borrow_mut().borrow(
1155                                &place_with_id,
1156                                place_with_id.hir_id,
1157                                upvar_borrow,
1158                            );
1159                        }
1160                    }
1161                }
1162            }
1163        }
1164
1165        Ok(())
1166    }
1167}
1168
1169/// The job of the methods whose name starts with `cat_` is to analyze
1170/// expressions and construct the corresponding [`Place`]s. The `cat`
1171/// stands for "categorize", this is a leftover from long ago when
1172/// places were called "categorizations".
1173///
1174/// Note that a [`Place`] differs somewhat from the expression itself. For
1175/// example, auto-derefs are explicit. Also, an index `a[b]` is decomposed into
1176/// two operations: a dereference to reach the array data and then an index to
1177/// jump forward to the relevant item.
1178impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> {
1179    fn expect_and_resolve_type(
1180        &self,
1181        id: HirId,
1182        ty: Option<Ty<'tcx>>,
1183    ) -> Result<Ty<'tcx>, Cx::Error> {
1184        match ty {
1185            Some(ty) => {
1186                let ty = self.cx.resolve_vars_if_possible(ty);
1187                self.cx.error_reported_in_ty(ty)?;
1188                Ok(ty)
1189            }
1190            None => {
1191                // FIXME: We shouldn't be relying on the infcx being tainted.
1192                self.cx.tainted_by_errors()?;
1193                bug!("no type for node {} in ExprUseVisitor", self.cx.tcx().hir_id_to_string(id));
1194            }
1195        }
1196    }
1197
1198    fn node_ty(&self, hir_id: HirId) -> Result<Ty<'tcx>, Cx::Error> {
1199        self.expect_and_resolve_type(hir_id, self.cx.typeck_results().node_type_opt(hir_id))
1200    }
1201
1202    fn expr_ty(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
1203        self.expect_and_resolve_type(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr))
1204    }
1205
1206    fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
1207        self.expect_and_resolve_type(
1208            expr.hir_id,
1209            self.cx.typeck_results().expr_ty_adjusted_opt(expr),
1210        )
1211    }
1212
1213    /// Returns the type of value that this pattern matches against.
1214    /// Some non-obvious cases:
1215    ///
1216    /// - a `ref x` binding matches against a value of type `T` and gives
1217    ///   `x` the type `&T`; we return `T`.
1218    /// - a pattern with implicit derefs (thanks to default binding
1219    ///   modes #42640) may look like `Some(x)` but in fact have
1220    ///   implicit deref patterns attached (e.g., it is really
1221    ///   `&Some(x)`). In that case, we return the "outermost" type
1222    ///   (e.g., `&Option<T>`).
1223    fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> Result<Ty<'tcx>, Cx::Error> {
1224        // Check for implicit `&` types wrapping the pattern; note
1225        // that these are never attached to binding patterns, so
1226        // actually this is somewhat "disjoint" from the code below
1227        // that aims to account for `ref x`.
1228        if let Some(vec) = self.cx.typeck_results().pat_adjustments().get(pat.hir_id) {
1229            if let Some(first_adjust) = vec.first() {
1230                debug!("pat_ty(pat={:?}) found adjustment `{:?}`", pat, first_adjust);
1231                return Ok(first_adjust.source);
1232            }
1233        } else if let PatKind::Ref(subpat, _) = pat.kind
1234            && self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id)
1235        {
1236            return self.pat_ty_adjusted(subpat);
1237        }
1238
1239        self.pat_ty_unadjusted(pat)
1240    }
1241
1242    /// Like [`Self::pat_ty_adjusted`], but ignores implicit `&` patterns.
1243    fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> Result<Ty<'tcx>, Cx::Error> {
1244        let base_ty = self.node_ty(pat.hir_id)?;
1245        trace!(?base_ty);
1246
1247        // This code detects whether we are looking at a `ref x`,
1248        // and if so, figures out what the type *being borrowed* is.
1249        match pat.kind {
1250            PatKind::Binding(..) => {
1251                let bm = *self
1252                    .cx
1253                    .typeck_results()
1254                    .pat_binding_modes()
1255                    .get(pat.hir_id)
1256                    .expect("missing binding mode");
1257
1258                if matches!(bm.0, hir::ByRef::Yes(_)) {
1259                    // a bind-by-ref means that the base_ty will be the type of the ident itself,
1260                    // but what we want here is the type of the underlying value being borrowed.
1261                    // So peel off one-level, turning the &T into T.
1262                    match self.cx.structurally_resolve_type(pat.span, base_ty).builtin_deref(false)
1263                    {
1264                        Some(ty) => Ok(ty),
1265                        None => {
1266                            debug!("By-ref binding of non-derefable type");
1267                            Err(self
1268                                .cx
1269                                .report_bug(pat.span, "by-ref binding of non-derefable type"))
1270                        }
1271                    }
1272                } else {
1273                    Ok(base_ty)
1274                }
1275            }
1276            _ => Ok(base_ty),
1277        }
1278    }
1279
1280    fn cat_expr(&self, expr: &hir::Expr<'_>) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1281        self.cat_expr_(expr, self.cx.typeck_results().expr_adjustments(expr))
1282    }
1283
1284    /// This recursion helper avoids going through *too many*
1285    /// adjustments, since *only* non-overloaded deref recurses.
1286    fn cat_expr_(
1287        &self,
1288        expr: &hir::Expr<'_>,
1289        adjustments: &[adjustment::Adjustment<'tcx>],
1290    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1291        match adjustments.split_last() {
1292            None => self.cat_expr_unadjusted(expr),
1293            Some((adjustment, previous)) => {
1294                self.cat_expr_adjusted_with(expr, || self.cat_expr_(expr, previous), adjustment)
1295            }
1296        }
1297    }
1298
1299    fn cat_expr_adjusted(
1300        &self,
1301        expr: &hir::Expr<'_>,
1302        previous: PlaceWithHirId<'tcx>,
1303        adjustment: &adjustment::Adjustment<'tcx>,
1304    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1305        self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
1306    }
1307
1308    fn cat_expr_adjusted_with<F>(
1309        &self,
1310        expr: &hir::Expr<'_>,
1311        previous: F,
1312        adjustment: &adjustment::Adjustment<'tcx>,
1313    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
1314    where
1315        F: FnOnce() -> Result<PlaceWithHirId<'tcx>, Cx::Error>,
1316    {
1317        let target = self.cx.resolve_vars_if_possible(adjustment.target);
1318        match adjustment.kind {
1319            adjustment::Adjust::Deref(overloaded) => {
1320                // Equivalent to *expr or something similar.
1321                let base = if let Some(deref) = overloaded {
1322                    let ref_ty = Ty::new_ref(
1323                        self.cx.tcx(),
1324                        self.cx.tcx().lifetimes.re_erased,
1325                        target,
1326                        deref.mutbl,
1327                    );
1328                    self.cat_rvalue(expr.hir_id, ref_ty)
1329                } else {
1330                    previous()?
1331                };
1332                self.cat_deref(expr.hir_id, base)
1333            }
1334
1335            adjustment::Adjust::NeverToAny
1336            | adjustment::Adjust::Pointer(_)
1337            | adjustment::Adjust::Borrow(_)
1338            | adjustment::Adjust::ReborrowPin(..) => {
1339                // Result is an rvalue.
1340                Ok(self.cat_rvalue(expr.hir_id, target))
1341            }
1342        }
1343    }
1344
1345    fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1346        let expr_ty = self.expr_ty(expr)?;
1347        match expr.kind {
1348            hir::ExprKind::Unary(hir::UnOp::Deref, e_base) => {
1349                if self.cx.typeck_results().is_method_call(expr) {
1350                    self.cat_overloaded_place(expr, e_base)
1351                } else {
1352                    let base = self.cat_expr(e_base)?;
1353                    self.cat_deref(expr.hir_id, base)
1354                }
1355            }
1356
1357            hir::ExprKind::Field(base, _) => {
1358                let base = self.cat_expr(base)?;
1359                debug!(?base);
1360
1361                let field_idx = self
1362                    .cx
1363                    .typeck_results()
1364                    .field_indices()
1365                    .get(expr.hir_id)
1366                    .cloned()
1367                    .expect("Field index not found");
1368
1369                Ok(self.cat_projection(
1370                    expr.hir_id,
1371                    base,
1372                    expr_ty,
1373                    ProjectionKind::Field(field_idx, FIRST_VARIANT),
1374                ))
1375            }
1376
1377            hir::ExprKind::Index(base, _, _) => {
1378                if self.cx.typeck_results().is_method_call(expr) {
1379                    // If this is an index implemented by a method call, then it
1380                    // will include an implicit deref of the result.
1381                    // The call to index() returns a `&T` value, which
1382                    // is an rvalue. That is what we will be
1383                    // dereferencing.
1384                    self.cat_overloaded_place(expr, base)
1385                } else {
1386                    let base = self.cat_expr(base)?;
1387                    Ok(self.cat_projection(expr.hir_id, base, expr_ty, ProjectionKind::Index))
1388                }
1389            }
1390
1391            hir::ExprKind::Path(ref qpath) => {
1392                let res = self.cx.typeck_results().qpath_res(qpath, expr.hir_id);
1393                self.cat_res(expr.hir_id, expr.span, expr_ty, res)
1394            }
1395
1396            // both type ascription and unsafe binder casts don't affect
1397            // the place-ness of the subexpression.
1398            hir::ExprKind::Type(e, _) => self.cat_expr(e),
1399            hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e),
1400
1401            hir::ExprKind::AddrOf(..)
1402            | hir::ExprKind::Call(..)
1403            | hir::ExprKind::Use(..)
1404            | hir::ExprKind::Assign(..)
1405            | hir::ExprKind::AssignOp(..)
1406            | hir::ExprKind::Closure { .. }
1407            | hir::ExprKind::Ret(..)
1408            | hir::ExprKind::Become(..)
1409            | hir::ExprKind::Unary(..)
1410            | hir::ExprKind::Yield(..)
1411            | hir::ExprKind::MethodCall(..)
1412            | hir::ExprKind::Cast(..)
1413            | hir::ExprKind::DropTemps(..)
1414            | hir::ExprKind::Array(..)
1415            | hir::ExprKind::If(..)
1416            | hir::ExprKind::Tup(..)
1417            | hir::ExprKind::Binary(..)
1418            | hir::ExprKind::Block(..)
1419            | hir::ExprKind::Let(..)
1420            | hir::ExprKind::Loop(..)
1421            | hir::ExprKind::Match(..)
1422            | hir::ExprKind::Lit(..)
1423            | hir::ExprKind::ConstBlock(..)
1424            | hir::ExprKind::Break(..)
1425            | hir::ExprKind::Continue(..)
1426            | hir::ExprKind::Struct(..)
1427            | hir::ExprKind::Repeat(..)
1428            | hir::ExprKind::InlineAsm(..)
1429            | hir::ExprKind::OffsetOf(..)
1430            | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)),
1431        }
1432    }
1433
1434    fn cat_res(
1435        &self,
1436        hir_id: HirId,
1437        span: Span,
1438        expr_ty: Ty<'tcx>,
1439        res: Res,
1440    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1441        match res {
1442            Res::Def(
1443                DefKind::Ctor(..)
1444                | DefKind::Const
1445                | DefKind::ConstParam
1446                | DefKind::AssocConst
1447                | DefKind::Fn
1448                | DefKind::AssocFn,
1449                _,
1450            )
1451            | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, expr_ty)),
1452
1453            Res::Def(DefKind::Static { .. }, _) => {
1454                Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
1455            }
1456
1457            Res::Local(var_id) => {
1458                if self.upvars.is_some_and(|upvars| upvars.contains_key(&var_id)) {
1459                    self.cat_upvar(hir_id, var_id)
1460                } else {
1461                    Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new()))
1462                }
1463            }
1464
1465            def => span_bug!(span, "unexpected definition in ExprUseVisitor: {:?}", def),
1466        }
1467    }
1468
1469    /// Categorize an upvar.
1470    ///
1471    /// Note: the actual upvar access contains invisible derefs of closure
1472    /// environment and upvar reference as appropriate. Only regionck cares
1473    /// about these dereferences, so we let it compute them as needed.
1474    fn cat_upvar(&self, hir_id: HirId, var_id: HirId) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1475        let closure_expr_def_id = self.cx.body_owner_def_id();
1476
1477        let upvar_id = ty::UpvarId {
1478            var_path: ty::UpvarPath { hir_id: var_id },
1479            closure_expr_id: closure_expr_def_id,
1480        };
1481        let var_ty = self.node_ty(var_id)?;
1482
1483        Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()))
1484    }
1485
1486    fn cat_rvalue(&self, hir_id: HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx> {
1487        PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
1488    }
1489
1490    fn cat_projection(
1491        &self,
1492        node: HirId,
1493        base_place: PlaceWithHirId<'tcx>,
1494        ty: Ty<'tcx>,
1495        kind: ProjectionKind,
1496    ) -> PlaceWithHirId<'tcx> {
1497        let place_ty = base_place.place.ty();
1498        let mut projections = base_place.place.projections;
1499
1500        let node_ty = self.cx.typeck_results().node_type(node);
1501        if !self.cx.tcx().next_trait_solver_globally() {
1502            // Opaque types can't have field projections, but we can instead convert
1503            // the current place in-place (heh) to the hidden type, and then apply all
1504            // follow up projections on that.
1505            if node_ty != place_ty
1506                && self
1507                    .cx
1508                    .structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), place_ty)
1509                    .is_impl_trait()
1510            {
1511                projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
1512            }
1513        }
1514        projections.push(Projection { kind, ty });
1515        PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections)
1516    }
1517
1518    fn cat_overloaded_place(
1519        &self,
1520        expr: &hir::Expr<'_>,
1521        base: &hir::Expr<'_>,
1522    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1523        // Reconstruct the output assuming it's a reference with the
1524        // same region and mutability as the receiver. This holds for
1525        // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
1526        let place_ty = self.expr_ty(expr)?;
1527        let base_ty = self.expr_ty_adjusted(base)?;
1528
1529        let ty::Ref(region, _, mutbl) =
1530            *self.cx.structurally_resolve_type(base.span, base_ty).kind()
1531        else {
1532            span_bug!(expr.span, "cat_overloaded_place: base is not a reference");
1533        };
1534        let ref_ty = Ty::new_ref(self.cx.tcx(), region, place_ty, mutbl);
1535
1536        let base = self.cat_rvalue(expr.hir_id, ref_ty);
1537        self.cat_deref(expr.hir_id, base)
1538    }
1539
1540    fn cat_deref(
1541        &self,
1542        node: HirId,
1543        base_place: PlaceWithHirId<'tcx>,
1544    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1545        let base_curr_ty = base_place.place.ty();
1546        let deref_ty = match self
1547            .cx
1548            .structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty)
1549            .builtin_deref(true)
1550        {
1551            Some(ty) => ty,
1552            None => {
1553                debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
1554                return Err(self.cx.report_bug(
1555                    self.cx.tcx().hir_span(node),
1556                    "explicit deref of non-derefable type",
1557                ));
1558            }
1559        };
1560        let mut projections = base_place.place.projections;
1561        projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });
1562
1563        Ok(PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections))
1564    }
1565
1566    /// Returns the variant index for an ADT used within a Struct or TupleStruct pattern
1567    /// Here `pat_hir_id` is the HirId of the pattern itself.
1568    fn variant_index_for_adt(
1569        &self,
1570        qpath: &hir::QPath<'_>,
1571        pat_hir_id: HirId,
1572        span: Span,
1573    ) -> Result<VariantIdx, Cx::Error> {
1574        let res = self.cx.typeck_results().qpath_res(qpath, pat_hir_id);
1575        let ty = self.cx.typeck_results().node_type(pat_hir_id);
1576        let ty::Adt(adt_def, _) = self.cx.structurally_resolve_type(span, ty).kind() else {
1577            return Err(self
1578                .cx
1579                .report_bug(span, "struct or tuple struct pattern not applied to an ADT"));
1580        };
1581
1582        match res {
1583            Res::Def(DefKind::Variant, variant_id) => Ok(adt_def.variant_index_with_id(variant_id)),
1584            Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
1585                Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id))
1586            }
1587            Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
1588            | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
1589            | Res::SelfCtor(..)
1590            | Res::SelfTyParam { .. }
1591            | Res::SelfTyAlias { .. } => {
1592                // Structs and Unions have only have one variant.
1593                Ok(FIRST_VARIANT)
1594            }
1595            _ => bug!("expected ADT path, found={:?}", res),
1596        }
1597    }
1598
1599    /// Returns the total number of fields in an ADT variant used within a pattern.
1600    /// Here `pat_hir_id` is the HirId of the pattern itself.
1601    fn total_fields_in_adt_variant(
1602        &self,
1603        pat_hir_id: HirId,
1604        variant_index: VariantIdx,
1605        span: Span,
1606    ) -> Result<usize, Cx::Error> {
1607        let ty = self.cx.typeck_results().node_type(pat_hir_id);
1608        match self.cx.structurally_resolve_type(span, ty).kind() {
1609            ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()),
1610            _ => {
1611                self.cx
1612                    .tcx()
1613                    .dcx()
1614                    .span_bug(span, "struct or tuple struct pattern not applied to an ADT");
1615            }
1616        }
1617    }
1618
1619    /// Returns the total number of fields in a tuple used within a Tuple pattern.
1620    /// Here `pat_hir_id` is the HirId of the pattern itself.
1621    fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> Result<usize, Cx::Error> {
1622        let ty = self.cx.typeck_results().node_type(pat_hir_id);
1623        match self.cx.structurally_resolve_type(span, ty).kind() {
1624            ty::Tuple(args) => Ok(args.len()),
1625            _ => Err(self.cx.report_bug(span, "tuple pattern not applied to a tuple")),
1626        }
1627    }
1628
1629    /// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
1630    /// is being matched against.
1631    ///
1632    /// In general, the way that this works is that we walk down the pattern,
1633    /// constructing a `PlaceWithHirId` that represents the path that will be taken
1634    /// to reach the value being matched.
1635    fn cat_pattern<F>(
1636        &self,
1637        mut place_with_id: PlaceWithHirId<'tcx>,
1638        pat: &hir::Pat<'_>,
1639        op: &mut F,
1640    ) -> Result<(), Cx::Error>
1641    where
1642        F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>) -> Result<(), Cx::Error>,
1643    {
1644        // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly.
1645        // `PlaceWithHirId`s are constructed differently from patterns. For example, in
1646        //
1647        // ```
1648        // match foo {
1649        //     &&Some(x, ) => { ... },
1650        //     _ => { ... },
1651        // }
1652        // ```
1653        //
1654        // the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the
1655        // corresponding `PlaceWithHirId` we start with the `PlaceWithHirId` for `foo`, and then, by traversing the
1656        // pattern, try to answer the question: given the address of `foo`, how is `x` reached?
1657        //
1658        // `&&Some(x,)` `place_foo`
1659        //  `&Some(x,)` `deref { place_foo}`
1660        //   `Some(x,)` `deref { deref { place_foo }}`
1661        //       `(x,)` `field0 { deref { deref { place_foo }}}` <- resulting place
1662        //
1663        // The above example has no adjustments. If the code were instead the (after adjustments,
1664        // equivalent) version
1665        //
1666        // ```
1667        // match foo {
1668        //     Some(x, ) => { ... },
1669        //     _ => { ... },
1670        // }
1671        // ```
1672        //
1673        // Then we see that to get the same result, we must start with
1674        // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
1675        // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
1676        let typeck_results = self.cx.typeck_results();
1677        let adjustments: &[adjustment::PatAdjustment<'tcx>] =
1678            typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
1679        let mut adjusts = adjustments.iter().peekable();
1680        while let Some(adjust) = adjusts.next() {
1681            debug!("applying adjustment to place_with_id={:?}", place_with_id);
1682            place_with_id = match adjust.kind {
1683                adjustment::PatAdjust::BuiltinDeref => self.cat_deref(pat.hir_id, place_with_id)?,
1684                adjustment::PatAdjust::OverloadedDeref => {
1685                    // This adjustment corresponds to an overloaded deref; unless it's on a box, it
1686                    // borrows the scrutinee to call `Deref::deref` or `DerefMut::deref_mut`. Invoke
1687                    // the callback before setting `place_with_id` to the temporary storing the
1688                    // result of the deref.
1689                    // HACK(dianne): giving the callback a fake deref pattern makes sure it behaves the
1690                    // same as it would if this were an explicit deref pattern (including for boxes).
1691                    op(&place_with_id, &hir::Pat { kind: PatKind::Deref(pat), ..*pat })?;
1692                    let target_ty = match adjusts.peek() {
1693                        Some(&&next_adjust) => next_adjust.source,
1694                        // At the end of the deref chain, we get `pat`'s scrutinee.
1695                        None => self.pat_ty_unadjusted(pat)?,
1696                    };
1697                    self.pat_deref_place(pat.hir_id, place_with_id, pat, target_ty)?
1698                }
1699            };
1700        }
1701        drop(typeck_results); // explicitly release borrow of typeck results, just in case.
1702        let place_with_id = place_with_id; // lose mutability
1703        debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
1704
1705        // Invoke the callback, but only now, after the `place_with_id` has adjusted.
1706        //
1707        // To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that
1708        // case, the initial `place_with_id` will be that for `&Some(3)` and the pattern is `Some(x)`. We
1709        // don't want to call `op` with these incompatible values. As written, what happens instead
1710        // is that `op` is called with the adjusted place (that for `*&Some(3)`) and the pattern
1711        // `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)`
1712        // result in the place `Downcast<Some>(*&Some(3)).0` associated to `x` and invoke `op` with
1713        // that (where the `ref` on `x` is implied).
1714        op(&place_with_id, pat)?;
1715
1716        match pat.kind {
1717            PatKind::Tuple(subpats, dots_pos) => {
1718                // (p1, ..., pN)
1719                let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?;
1720
1721                for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
1722                    let subpat_ty = self.pat_ty_adjusted(subpat)?;
1723                    let projection_kind =
1724                        ProjectionKind::Field(FieldIdx::from_usize(i), FIRST_VARIANT);
1725                    let sub_place = self.cat_projection(
1726                        pat.hir_id,
1727                        place_with_id.clone(),
1728                        subpat_ty,
1729                        projection_kind,
1730                    );
1731                    self.cat_pattern(sub_place, subpat, op)?;
1732                }
1733            }
1734
1735            PatKind::TupleStruct(ref qpath, subpats, dots_pos) => {
1736                // S(p1, ..., pN)
1737                let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
1738                let total_fields =
1739                    self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?;
1740
1741                for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
1742                    let subpat_ty = self.pat_ty_adjusted(subpat)?;
1743                    let projection_kind =
1744                        ProjectionKind::Field(FieldIdx::from_usize(i), variant_index);
1745                    let sub_place = self.cat_projection(
1746                        pat.hir_id,
1747                        place_with_id.clone(),
1748                        subpat_ty,
1749                        projection_kind,
1750                    );
1751                    self.cat_pattern(sub_place, subpat, op)?;
1752                }
1753            }
1754
1755            PatKind::Struct(ref qpath, field_pats, _) => {
1756                // S { f1: p1, ..., fN: pN }
1757
1758                let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
1759
1760                for fp in field_pats {
1761                    let field_ty = self.pat_ty_adjusted(fp.pat)?;
1762                    let field_index = self
1763                        .cx
1764                        .typeck_results()
1765                        .field_indices()
1766                        .get(fp.hir_id)
1767                        .cloned()
1768                        .expect("no index for a field");
1769
1770                    let field_place = self.cat_projection(
1771                        pat.hir_id,
1772                        place_with_id.clone(),
1773                        field_ty,
1774                        ProjectionKind::Field(field_index, variant_index),
1775                    );
1776                    self.cat_pattern(field_place, fp.pat, op)?;
1777                }
1778            }
1779
1780            PatKind::Or(pats) => {
1781                for pat in pats {
1782                    self.cat_pattern(place_with_id.clone(), pat, op)?;
1783                }
1784            }
1785
1786            PatKind::Binding(.., Some(subpat)) | PatKind::Guard(subpat, _) => {
1787                self.cat_pattern(place_with_id, subpat, op)?;
1788            }
1789
1790            PatKind::Ref(subpat, _)
1791                if self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id) =>
1792            {
1793                self.cat_pattern(place_with_id, subpat, op)?;
1794            }
1795
1796            PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
1797                // box p1, &p1, &mut p1. we can ignore the mutability of
1798                // PatKind::Ref since that information is already contained
1799                // in the type.
1800                let subplace = self.cat_deref(pat.hir_id, place_with_id)?;
1801                self.cat_pattern(subplace, subpat, op)?;
1802            }
1803            PatKind::Deref(subpat) => {
1804                let ty = self.pat_ty_adjusted(subpat)?;
1805                let place = self.pat_deref_place(pat.hir_id, place_with_id, subpat, ty)?;
1806                self.cat_pattern(place, subpat, op)?;
1807            }
1808
1809            PatKind::Slice(before, ref slice, after) => {
1810                let Some(element_ty) = self
1811                    .cx
1812                    .structurally_resolve_type(pat.span, place_with_id.place.ty())
1813                    .builtin_index()
1814                else {
1815                    debug!("explicit index of non-indexable type {:?}", place_with_id);
1816                    return Err(self
1817                        .cx
1818                        .report_bug(pat.span, "explicit index of non-indexable type"));
1819                };
1820                let elt_place = self.cat_projection(
1821                    pat.hir_id,
1822                    place_with_id.clone(),
1823                    element_ty,
1824                    ProjectionKind::Index,
1825                );
1826                for before_pat in before {
1827                    self.cat_pattern(elt_place.clone(), before_pat, op)?;
1828                }
1829                if let Some(slice_pat) = *slice {
1830                    let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?;
1831                    let slice_place = self.cat_projection(
1832                        pat.hir_id,
1833                        place_with_id,
1834                        slice_pat_ty,
1835                        ProjectionKind::Subslice,
1836                    );
1837                    self.cat_pattern(slice_place, slice_pat, op)?;
1838                }
1839                for after_pat in after {
1840                    self.cat_pattern(elt_place.clone(), after_pat, op)?;
1841                }
1842            }
1843
1844            PatKind::Binding(.., None)
1845            | PatKind::Expr(..)
1846            | PatKind::Range(..)
1847            | PatKind::Never
1848            | PatKind::Missing
1849            | PatKind::Wild
1850            | PatKind::Err(_) => {
1851                // always ok
1852            }
1853        }
1854
1855        Ok(())
1856    }
1857
1858    /// Represents the place matched on by a deref pattern's interior.
1859    fn pat_deref_place(
1860        &self,
1861        hir_id: HirId,
1862        base_place: PlaceWithHirId<'tcx>,
1863        inner: &hir::Pat<'_>,
1864        target_ty: Ty<'tcx>,
1865    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
1866        match self.cx.typeck_results().deref_pat_borrow_mode(base_place.place.ty(), inner) {
1867            // Deref patterns on boxes are lowered using a built-in deref.
1868            hir::ByRef::No => self.cat_deref(hir_id, base_place),
1869            // For other types, we create a temporary to match on.
1870            hir::ByRef::Yes(mutability) => {
1871                let re_erased = self.cx.tcx().lifetimes.re_erased;
1872                let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability);
1873                // A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...
1874                let base = self.cat_rvalue(hir_id, ty);
1875                // ... and the inner pattern matches on the place behind that reference.
1876                self.cat_deref(hir_id, base)
1877            }
1878        }
1879    }
1880
1881    fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
1882        if let ty::Adt(def, _) = self.cx.structurally_resolve_type(span, ty).kind() {
1883            // Note that if a non-exhaustive SingleVariant is defined in another crate, we need
1884            // to assume that more cases will be added to the variant in the future. This mean
1885            // that we should handle non-exhaustive SingleVariant the same way we would handle
1886            // a MultiVariant.
1887            def.variants().len() > 1 || def.variant_list_has_applicable_non_exhaustive()
1888        } else {
1889            false
1890        }
1891    }
1892}