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