Skip to main content

hir_ty/infer/closure/analysis/
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//! This is only used for upvar inference.
6
7use either::Either;
8use hir_def::{
9    AdtId, HasModule, VariantId,
10    attrs::AttrFlags,
11    hir::{
12        Array, AsmOperand, BindingId, Expr, ExprId, ExprOrPatId, ExprOrPatIdPacked, MatchArm, Pat,
13        PatId, RecordLitField, RecordSpread, Statement,
14    },
15    resolver::ValueNs,
16};
17use macros::{TypeFoldable, TypeVisitable};
18use rustc_type_ir::inherent::{IntoKind, Ty as _};
19use smallvec::{SmallVec, smallvec};
20use stdx::impl_from;
21use syntax::ast::{BinaryOp, UnaryOp};
22use tracing::{debug, instrument, trace};
23
24use crate::{
25    Adjust, Adjustment, AutoBorrow, Span,
26    infer::{
27        ByRef, CaptureSourceStack, DerefPatBorrowMode, InferenceContext, PatAdjust, PatAdjustment,
28        UpvarCapture, closure::analysis::BorrowKind,
29    },
30    method_resolution::CandidateId,
31    next_solver::{ErrorGuaranteed, StoredTy, Ty, TyKind},
32    upvars::UpvarsRef,
33    utils::EnumerateAndAdjustIterator,
34};
35
36type Result<T = (), E = ErrorGuaranteed> = std::result::Result<T, E>;
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
39pub enum ProjectionKind {
40    /// A dereference of a pointer, reference or `Box<T>` of the given type.
41    Deref,
42
43    /// `B.F` where `B` is the base expression and `F` is
44    /// the field. The field is identified by which variant
45    /// it appears in along with a field index. The variant
46    /// is used for enums.
47    Field { field_idx: u32, variant_idx: u32 },
48
49    /// Some index like `B[x]`, where `B` is the base
50    /// expression. We don't preserve the index `x` because
51    /// we won't need it.
52    Index,
53
54    /// A subslice covering a range of values like `B[x..y]`.
55    Subslice,
56
57    /// `unwrap_binder!(expr)`
58    UnwrapUnsafeBinder,
59}
60
61#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
62pub enum PlaceBase {
63    /// A temporary variable.
64    Rvalue,
65    /// A named `static` item.
66    StaticItem,
67    /// A named local variable.
68    Local(BindingId),
69    /// An upvar referenced by closure env.
70    Upvar { closure: ExprId, var_id: BindingId },
71}
72
73#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
74pub struct Projection {
75    /// Type after the projection is applied.
76    pub ty: StoredTy,
77
78    /// Defines the kind of access made by the projection.
79    #[type_visitable(ignore)]
80    pub kind: ProjectionKind,
81}
82
83/// A `Place` represents how a value is located in memory. This does not
84/// always correspond to a syntactic place expression. For example, when
85/// processing a pattern, a `Place` can be used to refer to the sub-value
86/// currently being inspected.
87#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
88pub struct Place {
89    /// The type of the `PlaceBase`
90    pub base_ty: StoredTy,
91    /// The "outermost" place that holds this value.
92    #[type_visitable(ignore)]
93    pub base: PlaceBase,
94    /// How this place is derived from the base place.
95    pub projections: Vec<Projection>,
96}
97
98impl Place {
99    /// Returns an iterator of the types that have to be dereferenced to access
100    /// the `Place`.
101    ///
102    /// The types are in the reverse order that they are applied. So if
103    /// `x: &*const u32` and the `Place` is `**x`, then the types returned are
104    ///`*const u32` then `&*const u32`.
105    pub fn deref_tys<'db>(&self) -> impl Iterator<Item = Ty<'db>> {
106        self.projections.iter().enumerate().rev().filter_map(move |(index, proj)| {
107            if ProjectionKind::Deref == proj.kind {
108                Some(self.ty_before_projection(index))
109            } else {
110                None
111            }
112        })
113    }
114
115    /// Returns the type of this `Place` after all projections have been applied.
116    pub fn ty<'db>(&self) -> Ty<'db> {
117        self.projections.last().map_or(self.base_ty.as_ref(), |proj| proj.ty.as_ref())
118    }
119
120    /// Returns the type of this `Place` immediately before `projection_index`th projection
121    /// is applied.
122    pub fn ty_before_projection<'db>(&self, projection_index: usize) -> Ty<'db> {
123        assert!(projection_index < self.projections.len());
124        if projection_index == 0 {
125            self.base_ty.as_ref()
126        } else {
127            self.projections[projection_index - 1].ty.as_ref()
128        }
129    }
130}
131
132/// A `PlaceWithOrigin` represents how a value is located in memory. This does not
133/// always correspond to a syntactic place expression. For example, when
134/// processing a pattern, a `Place` can be used to refer to the sub-value
135/// currently being inspected.
136#[derive(Clone, Debug, PartialEq, Eq, Hash)]
137pub(crate) struct PlaceWithOrigin {
138    /// `ExprId`s or `PatId`s of the expressions or patterns producing this value.
139    pub origins: SmallVec<[CaptureSourceStack; 2]>,
140
141    /// Information about the `Place`.
142    pub place: Place,
143}
144
145impl PlaceWithOrigin {
146    fn new_no_projections<'db>(
147        origin: impl Into<ExprOrPatIdPacked>,
148        base_ty: Ty<'db>,
149        base: PlaceBase,
150    ) -> PlaceWithOrigin {
151        Self::new(
152            smallvec![CaptureSourceStack::from_single(origin.into())],
153            base_ty,
154            base,
155            Vec::new(),
156        )
157    }
158
159    fn new<'db>(
160        origins: SmallVec<[CaptureSourceStack; 2]>,
161        base_ty: Ty<'db>,
162        base: PlaceBase,
163        projections: Vec<Projection>,
164    ) -> PlaceWithOrigin {
165        debug_assert!(origins.iter().all(|origin| origin.len() == projections.len() + 1));
166        PlaceWithOrigin { origins, place: Place { base_ty: base_ty.store(), base, projections } }
167    }
168
169    fn push_projection(&mut self, projection: Projection, origin: ExprOrPatIdPacked) {
170        self.place.projections.push(projection);
171        for origin_stack in &mut self.origins {
172            origin_stack.push(origin);
173        }
174    }
175
176    pub(crate) fn span(&self) -> Span {
177        match self.origins.first() {
178            Some(origin) => origin.final_source().into(),
179            None => Span::Dummy,
180        }
181    }
182}
183
184/// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists.
185#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
186pub enum FakeReadCause {
187    /// A fake read injected into a match guard to ensure that the discriminants
188    /// that are being matched on aren't modified while the match guard is being
189    /// evaluated.
190    ///
191    /// At the beginning of each match guard, a fake borrow is
192    /// inserted for each discriminant accessed in the entire `match` statement.
193    ///
194    /// Then, at the end of the match guard, a `FakeRead(ForMatchGuard)` is
195    /// inserted to keep the fake borrows alive until that point.
196    ///
197    /// This should ensure that you cannot change the variant for an enum while
198    /// you are in the midst of matching on it.
199    ForMatchGuard,
200
201    /// Fake read of the scrutinee of a `match` or destructuring `let`
202    /// (i.e. `let` with non-trivial pattern).
203    ///
204    /// In `match x { ... }`, we generate a `FakeRead(ForMatchedPlace, x)`
205    /// and insert it into the `otherwise_block` (which is supposed to be
206    /// unreachable for irrefutable pattern-matches like `match` or `let`).
207    ///
208    /// This is necessary because `let x: !; match x {}` doesn't generate any
209    /// actual read of x, so we need to generate a `FakeRead` to check that it
210    /// is initialized.
211    ///
212    /// If the `FakeRead(ForMatchedPlace)` is being performed with a closure
213    /// that doesn't capture the required upvars, the `FakeRead` within the
214    /// closure is omitted entirely.
215    ///
216    /// To make sure that this is still sound, if a closure matches against
217    /// a Place starting with an Upvar, we hoist the `FakeRead` to the
218    /// definition point of the closure.
219    ///
220    /// If the `FakeRead` comes from being hoisted out of a closure like this,
221    /// we record the `ExprId` of the closure. Otherwise, the `Option` will be `None`.
222    //
223    // We can use LocalDefId here since fake read statements are removed
224    // before codegen in the `CleanupNonCodegenStatements` pass.
225    ForMatchedPlace(Option<ExprId>),
226
227    /// A fake read injected into a match guard to ensure that the places
228    /// bound by the pattern are immutable for the duration of the match guard.
229    ///
230    /// Within a match guard, references are created for each place that the
231    /// pattern creates a binding for — this is known as the `RefWithinGuard`
232    /// version of the variables. To make sure that the references stay
233    /// alive until the end of the match guard, and properly prevent the
234    /// places in question from being modified, a `FakeRead(ForGuardBinding)`
235    /// is inserted at the end of the match guard.
236    ///
237    /// For details on how these references are created, see the extensive
238    /// documentation on `bind_matched_candidate_for_guard` in
239    /// `rustc_mir_build`.
240    ForGuardBinding,
241
242    /// Officially, the semantics of
243    ///
244    /// `let pattern = <expr>;`
245    ///
246    /// is that `<expr>` is evaluated into a temporary and then this temporary is
247    /// into the pattern.
248    ///
249    /// However, if we see the simple pattern `let var = <expr>`, we optimize this to
250    /// evaluate `<expr>` directly into the variable `var`. This is mostly unobservable,
251    /// but in some cases it can affect the borrow checker, as in #53695.
252    ///
253    /// Therefore, we insert a `FakeRead(ForLet)` immediately after each `let`
254    /// with a trivial pattern.
255    ///
256    /// FIXME: `ExprUseVisitor` has an entirely different opinion on what `FakeRead(ForLet)`
257    /// is supposed to mean. If it was accurate to what MIR lowering does,
258    /// would it even make sense to hoist these out of closures like
259    /// `ForMatchedPlace`?
260    ForLet(Option<ExprId>),
261
262    /// Currently, index expressions overloaded through the `Index` trait
263    /// get lowered differently than index expressions with builtin semantics
264    /// for arrays and slices — the latter will emit code to perform
265    /// bound checks, and then return a MIR place that will only perform the
266    /// indexing "for real" when it gets incorporated into an instruction.
267    ///
268    /// This is observable in the fact that the following compiles:
269    ///
270    /// ```
271    /// fn f(x: &mut [&mut [u32]], i: usize) {
272    ///     x[i][x[i].len() - 1] += 1;
273    /// }
274    /// ```
275    ///
276    /// However, we need to be careful to not let the user invalidate the
277    /// bound check with an expression like
278    ///
279    /// `(*x)[1][{ x = y; 4}]`
280    ///
281    /// Here, the first bounds check would be invalidated when we evaluate the
282    /// second index expression. To make sure that this doesn't happen, we
283    /// create a fake borrow of `x` and hold it while we evaluate the second
284    /// index.
285    ///
286    /// This borrow is kept alive by a `FakeRead(ForIndex)` at the end of its
287    /// scope.
288    ForIndex,
289}
290
291/// This trait defines the callbacks you can expect to receive when
292/// employing the ExprUseVisitor.
293pub(crate) trait Delegate<'db> {
294    /// The value found at `place` is moved, depending
295    /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
296    ///
297    /// If the value is `Copy`, [`copy`][Self::copy] is called instead, which
298    /// by default falls back to [`borrow`][Self::borrow].
299    ///
300    /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
301    /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
302    /// id will be the id of the expression `expr` but the place itself will have
303    /// the id of the binding in the pattern `pat`.
304    fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>);
305
306    /// The value found at `place` is used, depending
307    /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
308    ///
309    /// Use of a `Copy` type in a ByUse context is considered a use
310    /// by `ImmBorrow` and `borrow` is called instead. This is because
311    /// a shared borrow is the "minimum access" that would be needed
312    /// to perform a copy.
313    ///
314    ///
315    /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
316    /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
317    /// id will be the id of the expression `expr` but the place itself will have
318    /// the id of the binding in the pattern `pat`.
319    fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>);
320
321    /// The value found at `place` is being borrowed with kind `bk`.
322    /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
323    fn borrow(
324        &mut self,
325        place_with_id: PlaceWithOrigin,
326        bk: BorrowKind,
327        ctx: &mut InferenceContext<'db>,
328    );
329
330    /// The value found at `place` is being copied.
331    /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
332    ///
333    /// If an implementation is not provided, use of a `Copy` type in a ByValue context is instead
334    /// considered a use by `ImmBorrow` and `borrow` is called instead. This is because a shared
335    /// borrow is the "minimum access" that would be needed to perform a copy.
336    fn copy(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) {
337        // In most cases, copying data from `x` is equivalent to doing `*&x`, so by default
338        // we treat a copy of `x` as a borrow of `x`.
339        self.borrow(place_with_id, BorrowKind::Immutable, ctx)
340    }
341
342    /// The path at `assignee_place` is being assigned to.
343    /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
344    fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>);
345
346    /// The path at `binding_place` is a binding that is being initialized.
347    ///
348    /// This covers cases such as `let x = 42;`
349    fn bind(&mut self, binding_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) {
350        // Bindings can normally be treated as a regular assignment, so by default we
351        // forward this to the mutate callback.
352        self.mutate(binding_place, ctx)
353    }
354
355    /// The `place` should be a fake read because of specified `cause`.
356    fn fake_read(
357        &mut self,
358        place_with_id: PlaceWithOrigin,
359        cause: FakeReadCause,
360        ctx: &mut InferenceContext<'db>,
361    );
362}
363
364impl<'db, D: Delegate<'db>> Delegate<'db> for &mut D {
365    fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) {
366        (**self).consume(place_with_id, ctx)
367    }
368
369    fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) {
370        (**self).use_cloned(place_with_id, ctx)
371    }
372
373    fn borrow(
374        &mut self,
375        place_with_id: PlaceWithOrigin,
376        bk: BorrowKind,
377        ctx: &mut InferenceContext<'db>,
378    ) {
379        (**self).borrow(place_with_id, bk, ctx)
380    }
381
382    fn copy(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) {
383        (**self).copy(place_with_id, ctx)
384    }
385
386    fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) {
387        (**self).mutate(assignee_place, ctx)
388    }
389
390    fn bind(&mut self, binding_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) {
391        (**self).bind(binding_place, ctx)
392    }
393
394    fn fake_read(
395        &mut self,
396        place_with_id: PlaceWithOrigin,
397        cause: FakeReadCause,
398        ctx: &mut InferenceContext<'db>,
399    ) {
400        (**self).fake_read(place_with_id, cause, ctx)
401    }
402}
403
404/// A visitor that reports how each expression is being used.
405///
406/// See [module-level docs][self] and [`Delegate`] for details.
407pub(crate) struct ExprUseVisitor<'a, 'db, D: Delegate<'db>> {
408    cx: &'a mut InferenceContext<'db>,
409    delegate: D,
410    closure_expr: ExprId,
411    upvars: UpvarsRef<'db>,
412}
413
414impl<'a, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'db, D> {
415    /// Creates the ExprUseVisitor, configuring it with the various options provided:
416    ///
417    /// - `delegate` -- who receives the callbacks
418    /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`)
419    /// - `typeck_results` --- typeck results for the code being analyzed
420    pub(crate) fn new(
421        cx: &'a mut InferenceContext<'db>,
422        closure_expr: ExprId,
423        upvars: UpvarsRef<'db>,
424        delegate: D,
425    ) -> Self {
426        ExprUseVisitor { delegate, closure_expr, upvars, cx }
427    }
428
429    pub(crate) fn consume_closure_body(&mut self, params: &[PatId], body: ExprId) -> Result {
430        for &param in params {
431            let param_ty = self.pat_ty_adjusted(param)?;
432            debug!("consume_body: param_ty = {:?}", param_ty);
433
434            let param_place = self.cat_rvalue(param.into(), param_ty);
435
436            self.fake_read_scrutinee(param_place.clone(), false);
437            self.walk_pat(param_place, param, false)?;
438        }
439
440        self.consume_expr(body)?;
441
442        Ok(())
443    }
444
445    #[instrument(skip(self), level = "debug")]
446    fn consume_or_copy(&mut self, place_with_id: PlaceWithOrigin) {
447        if self.cx.table.type_is_copy_modulo_regions(place_with_id.place.ty()) {
448            self.delegate.copy(place_with_id, self.cx);
449        } else {
450            self.delegate.consume(place_with_id, self.cx);
451        }
452    }
453
454    #[instrument(skip(self), level = "debug")]
455    pub(crate) fn consume_clone_or_copy(&mut self, place_with_id: PlaceWithOrigin) {
456        // `x.use` will do one of the following
457        // * if it implements `Copy`, it will be a copy
458        // * if it implements `UseCloned`, it will be a call to `clone`
459        // * otherwise, it is a move
460        //
461        // we do a conservative approximation of this, treating it as a move unless we know that it implements copy or `UseCloned`
462        if self.cx.table.type_is_copy_modulo_regions(place_with_id.place.ty()) {
463            self.delegate.copy(place_with_id, self.cx);
464        } else if self.cx.table.type_is_use_cloned_modulo_regions(place_with_id.place.ty()) {
465            self.delegate.use_cloned(place_with_id, self.cx);
466        } else {
467            self.delegate.consume(place_with_id, self.cx);
468        }
469    }
470
471    fn consume_exprs(&mut self, exprs: &[ExprId]) -> Result {
472        for &expr in exprs {
473            self.consume_expr(expr)?;
474        }
475        Ok(())
476    }
477
478    #[instrument(skip(self), level = "debug")]
479    pub(crate) fn consume_expr(&mut self, expr: ExprId) -> Result {
480        let place_with_id = self.cat_expr(expr)?;
481        self.consume_or_copy(place_with_id);
482        self.walk_expr(expr)?;
483        Ok(())
484    }
485
486    fn mutate_expr(&mut self, expr: ExprId) -> Result {
487        let place_with_id = self.cat_expr(expr)?;
488        self.delegate.mutate(place_with_id, self.cx);
489        self.walk_expr(expr)?;
490        Ok(())
491    }
492
493    #[instrument(skip(self), level = "debug")]
494    fn borrow_expr(&mut self, expr: ExprId, bk: BorrowKind) -> Result {
495        let place_with_id = self.cat_expr(expr)?;
496        self.delegate.borrow(place_with_id, bk, self.cx);
497        self.walk_expr(expr)?;
498        Ok(())
499    }
500
501    #[instrument(skip(self), level = "debug")]
502    pub(crate) fn walk_expr(&mut self, expr: ExprId) -> Result {
503        self.walk_adjustment(expr)?;
504
505        match self.cx.store[expr] {
506            Expr::Path(_) => {}
507
508            Expr::UnaryOp { op: UnaryOp::Deref, expr: base } => {
509                // *base
510                self.walk_expr(base)?;
511            }
512
513            Expr::Field { expr: base, .. } => {
514                // base.f
515                self.walk_expr(base)?;
516            }
517
518            Expr::Index { base: lhs, index: rhs } => {
519                // lhs[rhs]
520                self.walk_expr(lhs)?;
521                self.consume_expr(rhs)?;
522            }
523
524            Expr::Call { callee, ref args } => {
525                // callee(args)
526                self.consume_expr(callee)?;
527                self.consume_exprs(args)?;
528            }
529
530            Expr::MethodCall { receiver, ref args, .. } => {
531                // callee.m(args)
532                self.consume_expr(receiver)?;
533                self.consume_exprs(args)?;
534            }
535
536            Expr::RecordLit { ref fields, spread, .. } => {
537                self.walk_struct_expr(fields, spread)?;
538            }
539
540            Expr::Tuple { ref exprs } => {
541                self.consume_exprs(exprs)?;
542            }
543
544            Expr::If {
545                condition: cond_expr,
546                then_branch: then_expr,
547                else_branch: opt_else_expr,
548            } => {
549                self.consume_expr(cond_expr)?;
550                self.consume_expr(then_expr)?;
551                if let Some(else_expr) = opt_else_expr {
552                    self.consume_expr(else_expr)?;
553                }
554            }
555
556            Expr::Let { pat, expr: init } => {
557                self.walk_local(init, pat, None, |this| {
558                    this.borrow_expr(init, BorrowKind::Immutable)
559                })?;
560            }
561
562            Expr::Match { expr: discr, ref arms } => {
563                let discr_place = self.cat_expr(discr)?;
564                self.fake_read_scrutinee(discr_place.clone(), true);
565                self.walk_expr(discr)?;
566
567                for arm in arms {
568                    self.walk_arm(discr_place.clone(), arm)?;
569                }
570            }
571
572            Expr::Array(Array::ElementList { elements: ref exprs }) => {
573                self.consume_exprs(exprs)?;
574            }
575
576            Expr::Ref { expr: base, mutability: m, .. } => {
577                // &base
578                // make sure that the thing we are pointing out stays valid
579                // for the lifetime `scope_r` of the resulting ptr:
580                let bk = BorrowKind::from_hir_mutbl(m);
581                self.borrow_expr(base, bk)?;
582            }
583
584            Expr::InlineAsm(ref asm) => {
585                for (_, op) in &asm.operands {
586                    match *op {
587                        AsmOperand::In { expr, .. } => {
588                            self.consume_expr(expr)?;
589                        }
590                        AsmOperand::Out { expr: Some(expr), .. }
591                        | AsmOperand::InOut { expr, .. } => {
592                            self.mutate_expr(expr)?;
593                        }
594                        AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
595                            self.consume_expr(in_expr)?;
596                            if let Some(out_expr) = out_expr {
597                                self.mutate_expr(out_expr)?;
598                            }
599                        }
600                        AsmOperand::Out { expr: None, .. }
601                        | AsmOperand::Const { .. }
602                        | AsmOperand::Sym { .. } => {}
603                        AsmOperand::Label(block) => {
604                            self.walk_expr(block)?;
605                        }
606                    }
607                }
608            }
609
610            Expr::Continue { .. }
611            | Expr::Literal(..)
612            | Expr::Const(..)
613            | Expr::OffsetOf(..)
614            | Expr::Missing
615            | Expr::Underscore => {}
616
617            Expr::Loop { body: blk, .. } => {
618                self.walk_expr(blk)?;
619            }
620
621            Expr::UnaryOp { expr: lhs, .. } => {
622                self.consume_expr(lhs)?;
623            }
624
625            Expr::BinaryOp {
626                lhs,
627                rhs,
628                op: Some(BinaryOp::ArithOp(..) | BinaryOp::CmpOp(..) | BinaryOp::LogicOp(..)),
629            } => {
630                self.consume_expr(lhs)?;
631                self.consume_expr(rhs)?;
632            }
633
634            Expr::Block { ref statements, tail, .. } => {
635                for stmt in statements {
636                    self.walk_stmt(stmt)?;
637                }
638
639                if let Some(tail_expr) = tail {
640                    self.consume_expr(tail_expr)?;
641                }
642            }
643
644            Expr::Break { expr: opt_expr, .. } | Expr::Return { expr: opt_expr } => {
645                if let Some(expr) = opt_expr {
646                    self.consume_expr(expr)?;
647                }
648            }
649
650            Expr::Become { expr } | Expr::Await { expr } => {
651                self.consume_expr(expr)?;
652            }
653
654            Expr::Assignment { target, value } => {
655                self.walk_expr(value)?;
656                let expr_place = self.cat_expr(value)?;
657                let update_guard =
658                    self.cx.resolver.update_to_inner_scope(self.cx.db, self.cx.store_owner, expr);
659                self.walk_pat(expr_place, target, false)?;
660                self.cx.resolver.reset_to_guard(update_guard);
661            }
662
663            Expr::Cast { expr: base, .. } => {
664                self.consume_expr(base)?;
665            }
666
667            Expr::BinaryOp { lhs, rhs, op: None | Some(BinaryOp::Assignment { .. }) } => {
668                self.consume_expr(lhs)?;
669                self.consume_expr(rhs)?;
670            }
671
672            Expr::Array(Array::Repeat { initializer: base, .. }) => {
673                self.consume_expr(base)?;
674            }
675
676            Expr::Closure { .. } => {
677                self.walk_captures(expr);
678            }
679
680            Expr::Yield { expr: value } | Expr::Yeet { expr: value } => {
681                if let Some(value) = value {
682                    self.consume_expr(value)?;
683                }
684            }
685
686            Expr::IncludeBytes => {}
687        }
688        Ok(())
689    }
690
691    fn walk_stmt(&mut self, stmt: &Statement) -> Result {
692        match *stmt {
693            Statement::Let { pat, initializer: Some(expr), else_branch: els, .. } => {
694                self.walk_local(expr, pat, els, |_| Ok(()))?;
695            }
696
697            Statement::Let { .. } => {}
698
699            Statement::Item(_) => {
700                // We don't visit nested items in this visitor,
701                // only the fn body we were given.
702            }
703
704            Statement::Expr { expr, .. } => {
705                self.consume_expr(expr)?;
706            }
707        }
708        Ok(())
709    }
710
711    #[instrument(skip(self), level = "debug")]
712    fn fake_read_scrutinee(&mut self, discr_place: PlaceWithOrigin, refutable: bool) {
713        let closure_def_id = match discr_place.place.base {
714            PlaceBase::Upvar { closure, var_id: _ } => Some(closure),
715            _ => None,
716        };
717
718        let cause = if refutable {
719            FakeReadCause::ForMatchedPlace(closure_def_id)
720        } else {
721            FakeReadCause::ForLet(closure_def_id)
722        };
723
724        self.delegate.fake_read(discr_place, cause, self.cx);
725    }
726
727    fn walk_local<F>(&mut self, expr: ExprId, pat: PatId, els: Option<ExprId>, mut f: F) -> Result
728    where
729        F: FnMut(&mut Self) -> Result,
730    {
731        self.walk_expr(expr)?;
732        let expr_place = self.cat_expr(expr)?;
733        f(self)?;
734        self.fake_read_scrutinee(expr_place.clone(), els.is_some());
735        self.walk_pat(expr_place, pat, false)?;
736        if let Some(els) = els {
737            self.walk_expr(els)?;
738        }
739        Ok(())
740    }
741
742    fn walk_struct_expr(&mut self, fields: &[RecordLitField], spread: RecordSpread) -> Result {
743        // Consume the expressions supplying values for each field.
744        for field in fields {
745            self.consume_expr(field.expr)?;
746        }
747
748        let RecordSpread::Expr(with_expr) = spread else { return Ok(()) };
749
750        let with_place = self.cat_expr(with_expr)?;
751
752        // Select just those fields of the `with`
753        // expression that will actually be used
754        match self.cx.structurally_resolve_type(with_expr.into(), with_place.place.ty()).kind() {
755            TyKind::Adt(adt, args) if adt.is_struct() => {
756                let AdtId::StructId(adt) = adt.def_id() else { unreachable!() };
757                let adt_fields = VariantId::from(adt).fields(self.cx.db).fields();
758                let adt_field_types = self.cx.db.field_types(adt.into());
759                // Consume those fields of the with expression that are needed.
760                for (f_index, with_field) in adt_fields.iter() {
761                    let is_mentioned = fields.iter().any(|f| f.name == with_field.name);
762                    if !is_mentioned {
763                        let field_place = self.cat_projection(
764                            with_expr.into(),
765                            with_place.clone(),
766                            adt_field_types[f_index]
767                                .ty()
768                                .instantiate(self.cx.interner(), args)
769                                .skip_norm_wip(),
770                            ProjectionKind::Field {
771                                field_idx: f_index.into_raw().into_u32(),
772                                variant_idx: 0,
773                            },
774                        );
775                        self.consume_or_copy(field_place);
776                    }
777                }
778            }
779            _ => {}
780        }
781
782        // walk the with expression so that complex expressions
783        // are properly handled.
784        self.walk_expr(with_expr)?;
785
786        Ok(())
787    }
788
789    fn expr_adjustments(&self, expr: ExprId) -> SmallVec<[Adjustment; 5]> {
790        // Due to borrowck problems, we cannot borrow the adjustments, unfortunately.
791        self.cx.result.expr_adjustment(expr).unwrap_or_default().into()
792    }
793
794    fn pat_adjustments(&self, pat: PatId) -> SmallVec<[PatAdjustment; 5]> {
795        // Due to borrowck problems, we cannot borrow the adjustments, unfortunately.
796        self.cx.result.pat_adjustment(pat).unwrap_or_default().into()
797    }
798
799    /// Invoke the appropriate delegate calls for anything that gets
800    /// consumed or borrowed as part of the automatic adjustment
801    /// process.
802    fn walk_adjustment(&mut self, expr: ExprId) -> Result {
803        let adjustments = self.expr_adjustments(expr);
804        let mut place_with_id = self.cat_expr_unadjusted(expr)?;
805        for adjustment in &adjustments {
806            debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
807            match adjustment.kind {
808                Adjust::NeverToAny | Adjust::Pointer(_) => {
809                    // Creating a closure/fn-pointer or unsizing consumes
810                    // the input and stores it into the resulting rvalue.
811                    self.consume_or_copy(place_with_id.clone());
812                }
813
814                Adjust::Deref(None) => {}
815
816                // Autoderefs for overloaded Deref calls in fact reference
817                // their receiver. That is, if we have `(*x)` where `x`
818                // is of type `Rc<T>`, then this in fact is equivalent to
819                // `x.deref()`. Since `deref()` is declared with `&self`,
820                // this is an autoref of `x`.
821                Adjust::Deref(Some(ref deref)) => {
822                    let bk = BorrowKind::from_mutbl(deref.0);
823                    self.delegate.borrow(place_with_id.clone(), bk, self.cx);
824                }
825
826                Adjust::Borrow(ref autoref) => {
827                    self.walk_autoref(expr, place_with_id.clone(), autoref);
828                }
829            }
830            place_with_id = self.cat_expr_adjusted(expr, place_with_id, adjustment)?;
831        }
832        Ok(())
833    }
834
835    /// Walks the autoref `autoref` applied to the autoderef'd
836    /// `expr`. `base_place` is `expr` represented as a place,
837    /// after all relevant autoderefs have occurred.
838    fn walk_autoref(&mut self, expr: ExprId, base_place: PlaceWithOrigin, autoref: &AutoBorrow) {
839        debug!("walk_autoref(expr={:?} base_place={:?} autoref={:?})", expr, base_place, autoref);
840
841        match *autoref {
842            AutoBorrow::Ref(m) => {
843                self.delegate.borrow(base_place, BorrowKind::from_mutbl(m.into()), self.cx);
844            }
845
846            AutoBorrow::RawPtr(m) => {
847                debug!("walk_autoref: expr={:?} base_place={:?}", expr, base_place);
848
849                self.delegate.borrow(base_place, BorrowKind::from_mutbl(m), self.cx);
850            }
851        }
852    }
853
854    fn walk_arm(&mut self, discr_place: PlaceWithOrigin, arm: &MatchArm) -> Result {
855        self.walk_pat(discr_place, arm.pat, arm.guard.is_some())?;
856
857        if let Some(e) = arm.guard {
858            self.consume_expr(e)?;
859        }
860
861        self.consume_expr(arm.expr)
862    }
863
864    /// The core driver for walking a pattern
865    ///
866    /// This should mirror how pattern-matching gets lowered to MIR, as
867    /// otherwise lowering will ICE when trying to resolve the upvars.
868    ///
869    /// However, it is okay to approximate it here by doing *more* accesses than
870    /// the actual MIR builder will, which is useful when some checks are too
871    /// cumbersome to perform here. For example, if after typeck it becomes
872    /// clear that only one variant of an enum is inhabited, and therefore a
873    /// read of the discriminant is not necessary, `walk_pat` will have
874    /// over-approximated the necessary upvar capture granularity.
875    ///
876    /// Do note that discrepancies like these do still create obscure corners
877    /// in the semantics of the language, and should be avoided if possible.
878    #[instrument(skip(self), level = "debug")]
879    fn walk_pat(&mut self, discr_place: PlaceWithOrigin, pat: PatId, has_guard: bool) -> Result {
880        self.cat_pattern(discr_place.clone(), pat, &mut |this, place, pat| {
881            let walk_deref_pat = |this: &mut Self, subpattern: PatId, place: PlaceWithOrigin| {
882                // A deref pattern is a bit special: the binding mode of its inner bindings
883                // determines whether to borrow *at the level of the deref pattern* rather than
884                // borrowing the bound place (since that inner place is inside the temporary that
885                // stores the result of calling `deref()`/`deref_mut()` so can't be captured).
886                // Deref patterns on boxes don't borrow, so we ignore them here.
887                // HACK: this could be a fake pattern corresponding to a deref inserted by match
888                // ergonomics, in which case `pat.hir_id` will be the id of the subpattern.
889                if let DerefPatBorrowMode::Borrow(mutability) =
890                    this.cx.deref_pat_borrow_mode(place.place.ty(), subpattern)
891                {
892                    let bk = BorrowKind::from_mutbl(mutability);
893                    this.delegate.borrow(place, bk, this.cx);
894                }
895            };
896
897            let pat = match pat {
898                CatPatternPat::PatId(pat) => pat,
899                CatPatternPat::DerefPat { inner } => {
900                    debug!("walk_pat: Deref {{ inner: {:?} }}", inner);
901                    walk_deref_pat(this, inner, place);
902                    return Ok(());
903                }
904            };
905
906            debug!("walk_pat: pat.kind={:?}", this.cx.store[pat]);
907            let read_discriminant = {
908                let place = place.clone();
909                |this: &mut Self| {
910                    this.delegate.borrow(place, BorrowKind::Immutable, this.cx);
911                }
912            };
913
914            match this.cx.store[pat] {
915                Pat::Bind { id, .. } => {
916                    debug!("walk_pat: binding place={:?} pat={:?}", place, pat);
917                    let bm = this.cx.result.binding_modes[pat];
918                    debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat, bm);
919
920                    // pat_ty: the type of the binding being produced.
921                    let pat_ty = this.node_ty(pat.into())?;
922                    debug!("walk_pat: pat_ty={:?}", pat_ty);
923
924                    if let Ok(binding_place) = this.cat_local(pat.into(), pat_ty, id) {
925                        this.delegate.bind(binding_place, this.cx);
926                    }
927
928                    // Subtle: MIR desugaring introduces immutable borrows for each pattern
929                    // binding when lowering pattern guards to ensure that the guard does not
930                    // modify the scrutinee.
931                    if has_guard {
932                        read_discriminant(this);
933                    }
934
935                    // It is also a borrow or copy/move of the value being matched.
936                    // In a cases of pattern like `let pat = upvar`, don't use the span
937                    // of the pattern, as this just looks confusing, instead use the span
938                    // of the discriminant.
939                    match this.cx.result.binding_mode(pat).ok_or(ErrorGuaranteed)?.0 {
940                        ByRef::Yes(m) => {
941                            let bk = BorrowKind::from_mutbl(m);
942                            this.delegate.borrow(place, bk, this.cx);
943                        }
944                        ByRef::No => {
945                            debug!("walk_pat binding consuming pat");
946                            this.consume_or_copy(place);
947                        }
948                    }
949                }
950                Pat::Deref { inner: subpattern } => walk_deref_pat(this, subpattern, place),
951                Pat::Path(ref path) => {
952                    // A `Path` pattern is just a name like `Foo`. This is either a
953                    // named constant or else it refers to an ADT variant
954
955                    let is_assoc_const = this
956                        .cx
957                        .result
958                        .assoc_resolutions_for_pat(pat)
959                        .is_some_and(|it| matches!(it.0, CandidateId::ConstId(_)));
960                    let resolution = this.cx.resolver.resolve_path_in_value_ns_fully(
961                        this.cx.db,
962                        path,
963                        this.cx.store.pat_path_hygiene(pat),
964                    );
965                    let is_normal_const = matches!(resolution, Some(ValueNs::ConstId(_)));
966                    if is_assoc_const || is_normal_const {
967                        // Named constants have to be equated with the value
968                        // being matched, so that's a read of the value being matched.
969                        //
970                        // FIXME: Does the MIR code skip this read when matching on a ZST?
971                        // If so, we can also skip it here.
972                        read_discriminant(this);
973                    } else if this.is_multivariant_adt(pat.into(), place.place.ty()) {
974                        // Otherwise, this is a struct/enum variant, and so it's
975                        // only a read if we need to read the discriminant.
976                        read_discriminant(this);
977                    }
978                }
979                Pat::Lit(_) | Pat::Range { .. } => {
980                    // When matching against a literal or range, we need to
981                    // borrow the place to compare it against the pattern.
982                    //
983                    // Note that we do this read even if the range matches all
984                    // possible values, such as 0..=u8::MAX. This is because
985                    // we don't want to depend on consteval here.
986                    //
987                    // FIXME: What if the type being matched only has one
988                    // possible value?
989                    read_discriminant(this);
990                }
991                Pat::Record { .. } | Pat::TupleStruct { .. } => {
992                    if this.is_multivariant_adt(pat.into(), place.place.ty()) {
993                        read_discriminant(this);
994                    }
995                }
996                Pat::Slice { prefix: ref lhs, slice: wild, suffix: ref rhs } => {
997                    // We don't need to test the length if the pattern is `[..]`
998                    if matches!((&**lhs, wild, &**rhs), (&[], Some(_), &[]))
999                        // Arrays have a statically known size, so
1000                        // there is no need to read their length
1001                        || place.place.ty().strip_references().is_array()
1002                    {
1003                        // No read necessary
1004                    } else {
1005                        read_discriminant(this);
1006                    }
1007                }
1008                Pat::Expr(expr) => {
1009                    this.mutate_expr(expr)?;
1010                    // Destructuring assignment moves
1011                    this.consume_or_copy(place);
1012                }
1013                Pat::Or(_)
1014                | Pat::Box { .. }
1015                | Pat::Ref { .. }
1016                | Pat::Tuple { .. }
1017                | Pat::Wild
1018                | Pat::Missing
1019                | Pat::NotNull
1020                | Pat::Rest => {
1021                    // If the PatKind is Or, Box, Ref, Guard, or Tuple, the relevant accesses
1022                    // are made later as these patterns contains subpatterns.
1023                    // If the PatKind is Missing, Wild or Err, any relevant accesses are made when processing
1024                    // the other patterns that are part of the match
1025                }
1026            }
1027
1028            Ok(())
1029        })
1030    }
1031
1032    /// Handle the case where the current body contains a closure.
1033    ///
1034    /// When the current body being handled is a closure, then we must make sure that
1035    /// - The parent closure only captures Places from the nested closure that are not local to it.
1036    ///
1037    /// In the following example the closures `c` only captures `p.x` even though `incr`
1038    /// is a capture of the nested closure
1039    ///
1040    /// ```
1041    /// struct P { x: i32 }
1042    /// let mut p = P { x: 4 };
1043    /// let c = || {
1044    ///    let incr = 10;
1045    ///    let nested = || p.x += incr;
1046    /// };
1047    /// ```
1048    ///
1049    /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
1050    /// closure as the DefId.
1051    #[instrument(skip(self), level = "debug")]
1052    fn walk_captures(&mut self, closure_expr: ExprId) {
1053        fn upvar_is_local_variable(upvars: UpvarsRef<'_>, var_id: BindingId) -> bool {
1054            upvars.contains(var_id)
1055        }
1056
1057        // If we have a nested closure, we want to include the fake reads present in the nested
1058        // closure.
1059        // `remove()` then re-insert and not `get()` due to borrowck errors.
1060        if let Some(closure_data) = self.cx.result.closures_data.remove(&closure_expr) {
1061            for (fake_read, cause, origins) in closure_data.fake_reads.iter() {
1062                match fake_read.base {
1063                    PlaceBase::Upvar { var_id, closure: _ } => {
1064                        if upvar_is_local_variable(self.upvars, var_id) {
1065                            // The nested closure might be fake reading the current (enclosing) closure's local variables.
1066                            // The only places we want to fake read before creating the parent closure are the ones that
1067                            // are not local to it/ defined by it.
1068                            //
1069                            // ```rust,ignore(cannot-test-this-because-pseudo-code)
1070                            // let v1 = (0, 1);
1071                            // let c = || { // fake reads: v1
1072                            //    let v2 = (0, 1);
1073                            //    let e = || { // fake reads: v1, v2
1074                            //       let (_, t1) = v1;
1075                            //       let (_, t2) = v2;
1076                            //    }
1077                            // }
1078                            // ```
1079                            // This check is performed when visiting the body of the outermost closure (`c`) and ensures
1080                            // that we don't add a fake read of v2 in c.
1081                            continue;
1082                        }
1083                    }
1084                    _ => {
1085                        panic!(
1086                            "Do not know how to get ExprId out of Rvalue and StaticItem {:?}",
1087                            fake_read.base
1088                        );
1089                    }
1090                };
1091                self.delegate.fake_read(
1092                    PlaceWithOrigin { place: fake_read.clone(), origins: origins.clone() },
1093                    *cause,
1094                    self.cx,
1095                );
1096            }
1097
1098            for (var_id, min_list) in closure_data.min_captures.iter() {
1099                if !self.upvars.contains(*var_id) {
1100                    // The nested closure might be capturing the current (enclosing) closure's local variables.
1101                    // We check if the root variable is ever mentioned within the enclosing closure, if not
1102                    // then for the current body (if it's a closure) these aren't captures, we will ignore them.
1103                    continue;
1104                }
1105                for captured_place in min_list {
1106                    let place = &captured_place.place;
1107                    let capture_info = &captured_place.info;
1108
1109                    // Mark the place to be captured by the enclosing closure
1110                    let place_base =
1111                        PlaceBase::Upvar { var_id: *var_id, closure: self.closure_expr };
1112                    let place_with_id = PlaceWithOrigin::new(
1113                        capture_info.sources.clone(),
1114                        place.base_ty.as_ref(),
1115                        place_base,
1116                        place.projections.clone(),
1117                    );
1118
1119                    match capture_info.capture_kind {
1120                        UpvarCapture::ByValue => {
1121                            self.consume_or_copy(place_with_id);
1122                        }
1123                        UpvarCapture::ByUse => {
1124                            self.consume_clone_or_copy(place_with_id);
1125                        }
1126                        UpvarCapture::ByRef(upvar_borrow) => {
1127                            self.delegate.borrow(place_with_id, upvar_borrow, self.cx);
1128                        }
1129                    }
1130                }
1131            }
1132
1133            self.cx.result.closures_data.insert(closure_expr, closure_data);
1134        }
1135    }
1136
1137    fn error_reported_in_ty(&self, ty: Ty<'db>) -> Result {
1138        if ty.is_ty_error() { Err(ErrorGuaranteed) } else { Ok(()) }
1139    }
1140}
1141
1142#[derive(Debug, Clone, Copy)]
1143enum CatPatternPat {
1144    PatId(PatId),
1145    DerefPat { inner: PatId },
1146}
1147impl_from!(PatId for CatPatternPat);
1148
1149/// The job of the methods whose name starts with `cat_` is to analyze
1150/// expressions and construct the corresponding [`Place`]s. The `cat`
1151/// stands for "categorize", this is a leftover from long ago when
1152/// places were called "categorizations".
1153///
1154/// Note that a [`Place`] differs somewhat from the expression itself. For
1155/// example, auto-derefs are explicit. Also, an index `a[b]` is decomposed into
1156/// two operations: a dereference to reach the array data and then an index to
1157/// jump forward to the relevant item.
1158impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, 'db, D> {
1159    fn expect_and_resolve_type(&mut self, ty: Option<Ty<'db>>) -> Result<Ty<'db>> {
1160        match ty {
1161            Some(ty) => {
1162                let ty = self.cx.infcx().resolve_vars_if_possible(ty);
1163                self.error_reported_in_ty(ty)?;
1164                Ok(ty)
1165            }
1166            None => Err(ErrorGuaranteed),
1167        }
1168    }
1169
1170    fn node_ty(&mut self, id: ExprOrPatId) -> Result<Ty<'db>> {
1171        self.expect_and_resolve_type(self.cx.result.type_of_expr_or_pat(id))
1172    }
1173
1174    fn expr_ty(&mut self, expr: ExprId) -> Result<Ty<'db>> {
1175        self.node_ty(expr.into())
1176    }
1177
1178    fn expr_ty_adjusted(&mut self, expr: ExprId) -> Result<Ty<'db>> {
1179        self.expect_and_resolve_type(self.cx.result.type_of_expr_with_adjust(expr))
1180    }
1181
1182    /// Returns the type of value that this pattern matches against.
1183    /// Some non-obvious cases:
1184    ///
1185    /// - a `ref x` binding matches against a value of type `T` and gives
1186    ///   `x` the type `&T`; we return `T`.
1187    /// - a pattern with implicit derefs (thanks to default binding
1188    ///   modes #42640) may look like `Some(x)` but in fact have
1189    ///   implicit deref patterns attached (e.g., it is really
1190    ///   `&Some(x)`). In that case, we return the "outermost" type
1191    ///   (e.g., `&Option<T>`).
1192    fn pat_ty_adjusted(&mut self, pat: PatId) -> Result<Ty<'db>> {
1193        // Check for implicit `&` types wrapping the pattern; note
1194        // that these are never attached to binding patterns, so
1195        // actually this is somewhat "disjoint" from the code below
1196        // that aims to account for `ref x`.
1197        if let Some(vec) = self.cx.result.pat_adjustment(pat) {
1198            if let Some(first_adjust) = vec.first() {
1199                debug!("pat_ty(pat={:?}) found adjustment `{:?}`", pat, first_adjust);
1200                return Ok(first_adjust.source.as_ref());
1201            }
1202        } else if let Pat::Ref { pat: subpat, .. } = self.cx.store[pat]
1203            && self.cx.result.is_skipped_ref_pat(pat)
1204        {
1205            return self.pat_ty_adjusted(subpat);
1206        }
1207
1208        self.pat_ty_unadjusted(pat)
1209    }
1210
1211    /// Like [`Self::pat_ty_adjusted`], but ignores implicit `&` patterns.
1212    fn pat_ty_unadjusted(&mut self, pat: PatId) -> Result<Ty<'db>> {
1213        let base_ty = self.node_ty(pat.into())?;
1214        trace!(?base_ty);
1215
1216        // This code detects whether we are looking at a `ref x`,
1217        // and if so, figures out what the type *being borrowed* is.
1218        match self.cx.store[pat] {
1219            Pat::Bind { .. } => {
1220                let bm = self.cx.result.binding_mode(pat).ok_or(ErrorGuaranteed)?;
1221
1222                if let ByRef::Yes(_) = bm.0 {
1223                    // a bind-by-ref means that the base_ty will be the type of the ident itself,
1224                    // but what we want here is the type of the underlying value being borrowed.
1225                    // So peel off one-level, turning the &T into T.
1226                    match self
1227                        .cx
1228                        .structurally_resolve_type(pat.into(), base_ty)
1229                        .builtin_deref(false)
1230                    {
1231                        Some(ty) => Ok(ty),
1232                        None => {
1233                            debug!("By-ref binding of non-derefable type: {base_ty:?}");
1234                            Err(ErrorGuaranteed)
1235                        }
1236                    }
1237                } else {
1238                    Ok(base_ty)
1239                }
1240            }
1241            _ => Ok(base_ty),
1242        }
1243    }
1244
1245    fn cat_expr(&mut self, expr: ExprId) -> Result<PlaceWithOrigin> {
1246        self.cat_expr_(expr, &self.expr_adjustments(expr))
1247    }
1248
1249    /// This recursion helper avoids going through *too many*
1250    /// adjustments, since *only* non-overloaded deref recurses.
1251    fn cat_expr_(&mut self, expr: ExprId, adjustments: &[Adjustment]) -> Result<PlaceWithOrigin> {
1252        match adjustments.split_last() {
1253            None => self.cat_expr_unadjusted(expr),
1254            Some((adjustment, previous)) => {
1255                self.cat_expr_adjusted_with(expr, |this| this.cat_expr_(expr, previous), adjustment)
1256            }
1257        }
1258    }
1259
1260    fn cat_expr_adjusted(
1261        &mut self,
1262        expr: ExprId,
1263        previous: PlaceWithOrigin,
1264        adjustment: &Adjustment,
1265    ) -> Result<PlaceWithOrigin> {
1266        self.cat_expr_adjusted_with(expr, |_this| Ok(previous), adjustment)
1267    }
1268
1269    fn cat_expr_adjusted_with<F>(
1270        &mut self,
1271        expr: ExprId,
1272        previous: F,
1273        adjustment: &Adjustment,
1274    ) -> Result<PlaceWithOrigin>
1275    where
1276        F: FnOnce(&mut Self) -> Result<PlaceWithOrigin>,
1277    {
1278        let target = self.cx.infcx().resolve_vars_if_possible(adjustment.target.as_ref());
1279        match adjustment.kind {
1280            Adjust::Deref(overloaded) => {
1281                // Equivalent to *expr or something similar.
1282                let base = if let Some(deref) = overloaded {
1283                    let ref_ty = Ty::new_ref(
1284                        self.cx.interner(),
1285                        self.cx.types.regions.erased,
1286                        target,
1287                        deref.0,
1288                    );
1289                    self.cat_rvalue(expr.into(), ref_ty)
1290                } else {
1291                    previous(self)?
1292                };
1293                self.cat_deref(expr.into(), base)
1294            }
1295
1296            Adjust::NeverToAny | Adjust::Pointer(_) | Adjust::Borrow(_) => {
1297                // Result is an rvalue.
1298                Ok(self.cat_rvalue(expr.into(), target))
1299            }
1300        }
1301    }
1302
1303    fn cat_expr_unadjusted(&mut self, expr: ExprId) -> Result<PlaceWithOrigin> {
1304        let expr_ty = self.expr_ty(expr)?;
1305        match self.cx.store[expr] {
1306            Expr::UnaryOp { expr: e_base, op: UnaryOp::Deref } => {
1307                if self.cx.result.method_resolutions.contains_key(&expr) {
1308                    self.cat_overloaded_place(expr, e_base)
1309                } else {
1310                    let base = self.cat_expr(e_base)?;
1311                    self.cat_deref(expr.into(), base)
1312                }
1313            }
1314
1315            Expr::Field { expr: base, .. } => {
1316                let base = self.cat_expr(base)?;
1317                debug!(?base);
1318
1319                let field_idx = self
1320                    .cx
1321                    .result
1322                    .field_resolutions
1323                    .get(&expr)
1324                    .map(|field| match *field {
1325                        Either::Left(field) => field.local_id.into_raw().into_u32(),
1326                        Either::Right(tuple_field) => tuple_field.index,
1327                    })
1328                    .ok_or(ErrorGuaranteed)?;
1329
1330                Ok(self.cat_projection(
1331                    expr.into(),
1332                    base,
1333                    expr_ty,
1334                    ProjectionKind::Field { field_idx, variant_idx: 0 },
1335                ))
1336            }
1337
1338            Expr::Index { base, index: _ } => {
1339                // rustc checks if this is an overloaded index, but the check is buggy and treats any indexing
1340                // as overloaded, see https://rust-lang.zulipchat.com/#narrow/channel/144729-t-types/topic/.E2.9C.94.20Is.20builtin.20indexing.20any.20special.20in.20typeck.3F/near/565881390.
1341                // So that's what we do here.
1342                self.cat_overloaded_place(expr, base)
1343            }
1344
1345            Expr::Path(ref path) => {
1346                let resolver_guard =
1347                    self.cx.resolver.update_to_inner_scope(self.cx.db, self.cx.store_owner, expr);
1348                let resolution = self.cx.resolver.resolve_path_in_value_ns_fully(
1349                    self.cx.db,
1350                    path,
1351                    self.cx.store.expr_path_hygiene(expr),
1352                );
1353                self.cx.resolver.reset_to_guard(resolver_guard);
1354                match (resolution, self.cx.result.assoc_resolutions_for_expr(expr)) {
1355                    (_, Some((CandidateId::FunctionId(_) | CandidateId::ConstId(_), _)))
1356                    | (
1357                        Some(
1358                            ValueNs::ConstId(_)
1359                            | ValueNs::GenericParam(_)
1360                            | ValueNs::FunctionId(_)
1361                            | ValueNs::ImplSelf(_)
1362                            | ValueNs::EnumVariantId(_)
1363                            | ValueNs::StructId(_),
1364                        ),
1365                        None,
1366                    ) => Ok(self.cat_rvalue(expr.into(), expr_ty)),
1367                    (Some(ValueNs::StaticId(_)), None) => Ok(PlaceWithOrigin::new_no_projections(
1368                        expr,
1369                        expr_ty,
1370                        PlaceBase::StaticItem,
1371                    )),
1372                    (Some(ValueNs::LocalBinding(var_id)), None) => {
1373                        self.cat_local(expr.into(), expr_ty, var_id)
1374                    }
1375                    (None, None) => Err(ErrorGuaranteed),
1376                }
1377            }
1378
1379            _ => Ok(self.cat_rvalue(expr.into(), expr_ty)),
1380        }
1381    }
1382
1383    fn cat_local(
1384        &mut self,
1385        id: ExprOrPatIdPacked,
1386        expr_ty: Ty<'db>,
1387        var_id: BindingId,
1388    ) -> Result<PlaceWithOrigin> {
1389        if self.upvars.contains(var_id) {
1390            self.cat_upvar(id, var_id)
1391        } else {
1392            Ok(PlaceWithOrigin::new_no_projections(id, expr_ty, PlaceBase::Local(var_id)))
1393        }
1394    }
1395
1396    /// Categorize an upvar.
1397    ///
1398    /// Note: the actual upvar access contains invisible derefs of closure
1399    /// environment and upvar reference as appropriate. Only regionck cares
1400    /// about these dereferences, so we let it compute them as needed.
1401    fn cat_upvar(
1402        &mut self,
1403        hir_id: ExprOrPatIdPacked,
1404        var_id: BindingId,
1405    ) -> Result<PlaceWithOrigin> {
1406        let var_ty = self.expect_and_resolve_type(
1407            self.cx.result.type_of_binding.get(var_id).map(|it| it.as_ref()),
1408        )?;
1409
1410        Ok(PlaceWithOrigin::new_no_projections(
1411            hir_id,
1412            var_ty,
1413            PlaceBase::Upvar { closure: self.closure_expr, var_id },
1414        ))
1415    }
1416
1417    fn cat_rvalue(&self, hir_id: ExprOrPatIdPacked, expr_ty: Ty<'db>) -> PlaceWithOrigin {
1418        PlaceWithOrigin::new_no_projections(hir_id, expr_ty, PlaceBase::Rvalue)
1419    }
1420
1421    fn cat_projection(
1422        &self,
1423        node: ExprOrPatIdPacked,
1424        mut base_place: PlaceWithOrigin,
1425        ty: Ty<'db>,
1426        kind: ProjectionKind,
1427    ) -> PlaceWithOrigin {
1428        base_place.push_projection(Projection { kind, ty: ty.store() }, node);
1429        base_place
1430    }
1431
1432    fn cat_overloaded_place(&mut self, expr: ExprId, base: ExprId) -> Result<PlaceWithOrigin> {
1433        // Reconstruct the output assuming it's a reference with the
1434        // same region and mutability as the receiver. This holds for
1435        // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
1436        let place_ty = self.expr_ty(expr)?;
1437        let base_ty = self.expr_ty_adjusted(base)?;
1438
1439        let TyKind::Ref(region, _, mutbl) =
1440            self.cx.structurally_resolve_type(base.into(), base_ty).kind()
1441        else {
1442            return Err(ErrorGuaranteed);
1443        };
1444        let ref_ty = Ty::new_ref(self.cx.interner(), region, place_ty, mutbl);
1445
1446        let base = self.cat_rvalue(expr.into(), ref_ty);
1447        self.cat_deref(expr.into(), base)
1448    }
1449
1450    fn cat_deref(
1451        &mut self,
1452        node: ExprOrPatIdPacked,
1453        mut base_place: PlaceWithOrigin,
1454    ) -> Result<PlaceWithOrigin> {
1455        let base_curr_ty = base_place.place.ty();
1456        let Some(deref_ty) =
1457            self.cx.structurally_resolve_type(node, base_curr_ty).builtin_deref(true)
1458        else {
1459            debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
1460            return Err(ErrorGuaranteed);
1461        };
1462        base_place.push_projection(
1463            Projection { kind: ProjectionKind::Deref, ty: deref_ty.store() },
1464            node,
1465        );
1466        Ok(base_place)
1467    }
1468
1469    /// Returns the variant index for an ADT used within a Struct or TupleStruct pattern
1470    /// Here `pat_hir_id` is the ExprId of the pattern itself.
1471    fn variant_index_for_adt(&self, pat_id: PatId) -> Result<(u32, VariantId)> {
1472        let variant = self.cx.result.variant_resolution_for_pat(pat_id).ok_or(ErrorGuaranteed)?;
1473        let variant_idx = match variant {
1474            VariantId::EnumVariantId(variant) => variant.index(self.cx.db) as u32,
1475            VariantId::StructId(_) | VariantId::UnionId(_) => 0,
1476        };
1477        Ok((variant_idx, variant))
1478    }
1479
1480    /// Returns the total number of fields in a tuple used within a Tuple pattern.
1481    /// Here `pat_hir_id` is the ExprId of the pattern itself.
1482    fn total_fields_in_tuple(&mut self, pat_id: PatId) -> usize {
1483        let ty = self.cx.result.pat_ty(pat_id);
1484        match self.cx.structurally_resolve_type(pat_id.into(), ty).kind() {
1485            TyKind::Tuple(args) => args.len(),
1486            _ => panic!("tuple pattern not applied to a tuple"),
1487        }
1488    }
1489
1490    /// Here, `place` is the `PlaceWithId` being matched and pat is the pattern it
1491    /// is being matched against.
1492    ///
1493    /// In general, the way that this works is that we walk down the pattern,
1494    /// constructing a `PlaceWithId` that represents the path that will be taken
1495    /// to reach the value being matched.
1496    fn cat_pattern<F>(
1497        &mut self,
1498        mut place_with_id: PlaceWithOrigin,
1499        pat: PatId,
1500        op: &mut F,
1501    ) -> Result
1502    where
1503        F: FnMut(&mut Self, PlaceWithOrigin, CatPatternPat) -> Result,
1504    {
1505        // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithId` correspondingly.
1506        // `PlaceWithId`s are constructed differently from patterns. For example, in
1507        //
1508        // ```
1509        // match foo {
1510        //     &&Some(x, ) => { ... },
1511        //     _ => { ... },
1512        // }
1513        // ```
1514        //
1515        // the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the
1516        // corresponding `PlaceWithId` we start with the `PlaceWithId` for `foo`, and then, by traversing the
1517        // pattern, try to answer the question: given the address of `foo`, how is `x` reached?
1518        //
1519        // `&&Some(x,)` `place_foo`
1520        //  `&Some(x,)` `deref { place_foo}`
1521        //   `Some(x,)` `deref { deref { place_foo }}`
1522        //       `(x,)` `field0 { deref { deref { place_foo }}}` <- resulting place
1523        //
1524        // The above example has no adjustments. If the code were instead the (after adjustments,
1525        // equivalent) version
1526        //
1527        // ```
1528        // match foo {
1529        //     Some(x, ) => { ... },
1530        //     _ => { ... },
1531        // }
1532        // ```
1533        //
1534        // Then we see that to get the same result, we must start with
1535        // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
1536        // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
1537        let adjustments = self.pat_adjustments(pat);
1538        let mut adjusts = adjustments.iter().peekable();
1539        while let Some(adjust) = adjusts.next() {
1540            debug!("applying adjustment to place_with_id={:?}", place_with_id);
1541            place_with_id = match adjust.kind {
1542                PatAdjust::BuiltinDeref => self.cat_deref(pat.into(), place_with_id)?,
1543                PatAdjust::OverloadedDeref => {
1544                    // This adjustment corresponds to an overloaded deref; unless it's on a box, it
1545                    // borrows the scrutinee to call `Deref::deref` or `DerefMut::deref_mut`. Invoke
1546                    // the callback before setting `place_with_id` to the temporary storing the
1547                    // result of the deref.
1548                    op(self, place_with_id.clone(), CatPatternPat::DerefPat { inner: pat })?;
1549                    let target_ty = match adjusts.peek() {
1550                        Some(next_adjust) => next_adjust.source.as_ref(),
1551                        // At the end of the deref chain, we get `pat`'s scrutinee.
1552                        None => self.pat_ty_unadjusted(pat)?,
1553                    };
1554                    self.pat_deref_place(pat.into(), place_with_id, pat, target_ty)?
1555                }
1556            };
1557        }
1558        let place_with_id = place_with_id; // lose mutability
1559        debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
1560
1561        // Invoke the callback, but only now, after the `place_with_id` has adjusted.
1562        //
1563        // To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that
1564        // case, the initial `place_with_id` will be that for `&Some(3)` and the pattern is `Some(x)`. We
1565        // don't want to call `op` with these incompatible values. As written, what happens instead
1566        // is that `op` is called with the adjusted place (that for `*&Some(3)`) and the pattern
1567        // `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)`
1568        // result in the place `Downcast<Some>(*&Some(3)).0` associated to `x` and invoke `op` with
1569        // that (where the `ref` on `x` is implied).
1570        op(self, place_with_id.clone(), pat.into())?;
1571
1572        match self.cx.store[pat] {
1573            Pat::Tuple { args: ref subpats, ellipsis: dots_pos } => {
1574                // (p1, ..., pN)
1575                let total_fields = self.total_fields_in_tuple(pat);
1576
1577                for (i, &subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
1578                    let subpat_ty = self.pat_ty_adjusted(subpat)?;
1579                    let projection_kind =
1580                        ProjectionKind::Field { field_idx: i as u32, variant_idx: 0 };
1581                    let sub_place = self.cat_projection(
1582                        pat.into(),
1583                        place_with_id.clone(),
1584                        subpat_ty,
1585                        projection_kind,
1586                    );
1587                    self.cat_pattern(sub_place, subpat, op)?;
1588                }
1589            }
1590
1591            Pat::TupleStruct { args: ref subpats, ellipsis: dots_pos, .. } => {
1592                // S(p1, ..., pN)
1593                let (variant_index, variant) = self.variant_index_for_adt(pat)?;
1594                let total_fields = variant.fields(self.cx.db).len();
1595
1596                for (i, &subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
1597                    let subpat_ty = self.pat_ty_adjusted(subpat)?;
1598                    let projection_kind =
1599                        ProjectionKind::Field { variant_idx: variant_index, field_idx: i as u32 };
1600                    let sub_place = self.cat_projection(
1601                        pat.into(),
1602                        place_with_id.clone(),
1603                        subpat_ty,
1604                        projection_kind,
1605                    );
1606                    self.cat_pattern(sub_place, subpat, op)?;
1607                }
1608            }
1609
1610            Pat::Record { args: ref field_pats, .. } => {
1611                // S { f1: p1, ..., fN: pN }
1612
1613                let (variant_index, variant) = self.variant_index_for_adt(pat)?;
1614                let fields = variant.fields(self.cx.db);
1615
1616                for fp in field_pats {
1617                    let field_ty = self.pat_ty_adjusted(fp.pat)?;
1618                    let field_index = fields.field(&fp.name).ok_or(ErrorGuaranteed)?;
1619
1620                    let field_place = self.cat_projection(
1621                        pat.into(),
1622                        place_with_id.clone(),
1623                        field_ty,
1624                        ProjectionKind::Field {
1625                            variant_idx: variant_index,
1626                            field_idx: field_index.into_raw().into_u32(),
1627                        },
1628                    );
1629                    self.cat_pattern(field_place, fp.pat, op)?;
1630                }
1631            }
1632
1633            Pat::Or(ref pats) => {
1634                for &pat in pats {
1635                    self.cat_pattern(place_with_id.clone(), pat, op)?;
1636                }
1637            }
1638
1639            Pat::Bind { subpat: Some(subpat), .. } => {
1640                self.cat_pattern(place_with_id, subpat, op)?;
1641            }
1642
1643            Pat::Box { inner: subpat } | Pat::Ref { pat: subpat, .. } => {
1644                // box p1, &p1, &mut p1. we can ignore the mutability of
1645                // PatKind::Ref since that information is already contained
1646                // in the type.
1647                let subplace = self.cat_deref(pat.into(), place_with_id)?;
1648                self.cat_pattern(subplace, subpat, op)?;
1649            }
1650            Pat::Deref { inner: subpat } => {
1651                let ty = self.pat_ty_adjusted(subpat)?;
1652                let place = self.pat_deref_place(pat.into(), place_with_id, subpat, ty)?;
1653                self.cat_pattern(place, subpat, op)?;
1654            }
1655
1656            Pat::Slice { prefix: ref before, slice, suffix: ref after } => {
1657                let Some(element_ty) = self
1658                    .cx
1659                    .structurally_resolve_type(pat.into(), place_with_id.place.ty())
1660                    .builtin_index()
1661                else {
1662                    debug!("explicit index of non-indexable type {:?}", place_with_id);
1663                    return Err(ErrorGuaranteed);
1664                };
1665                let elt_place = self.cat_projection(
1666                    pat.into(),
1667                    place_with_id.clone(),
1668                    element_ty,
1669                    ProjectionKind::Index,
1670                );
1671                for &before_pat in before {
1672                    self.cat_pattern(elt_place.clone(), before_pat, op)?;
1673                }
1674                if let Some(slice_pat) = slice {
1675                    let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?;
1676                    let slice_place = self.cat_projection(
1677                        pat.into(),
1678                        place_with_id,
1679                        slice_pat_ty,
1680                        ProjectionKind::Subslice,
1681                    );
1682                    self.cat_pattern(slice_place, slice_pat, op)?;
1683                }
1684                for &after_pat in after {
1685                    self.cat_pattern(elt_place.clone(), after_pat, op)?;
1686                }
1687            }
1688
1689            Pat::Bind { subpat: None, .. }
1690            | Pat::Expr(..)
1691            | Pat::Path(_)
1692            | Pat::Lit(..)
1693            | Pat::Range { .. }
1694            | Pat::Missing
1695            | Pat::Rest
1696            | Pat::NotNull
1697            | Pat::Wild => {
1698                // always ok
1699            }
1700        }
1701
1702        Ok(())
1703    }
1704
1705    /// Represents the place matched on by a deref pattern's interior.
1706    fn pat_deref_place(
1707        &mut self,
1708        node: ExprOrPatIdPacked,
1709        base_place: PlaceWithOrigin,
1710        inner: PatId,
1711        target_ty: Ty<'db>,
1712    ) -> Result<PlaceWithOrigin> {
1713        match self.cx.deref_pat_borrow_mode(base_place.place.ty(), inner) {
1714            // Deref patterns on boxes are lowered using a built-in deref.
1715            DerefPatBorrowMode::Box => self.cat_deref(node, base_place),
1716            // For other types, we create a temporary to match on.
1717            DerefPatBorrowMode::Borrow(mutability) => {
1718                let re_erased = self.cx.types.regions.erased;
1719                let ty = Ty::new_ref(self.cx.interner(), re_erased, target_ty, mutability);
1720                // A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...
1721                let base = self.cat_rvalue(node, ty);
1722                // ... and the inner pattern matches on the place behind that reference.
1723                self.cat_deref(node, base)
1724            }
1725        }
1726    }
1727
1728    /// Checks whether a type has multiple variants, and therefore, whether a
1729    /// read of the discriminant might be necessary. Note that the actual MIR
1730    /// builder code does a more specific check, filtering out variants that
1731    /// happen to be uninhabited.
1732    ///
1733    /// Here, it is not practical to perform such a check, because inhabitedness
1734    /// queries require typeck results, and typeck requires closure capture analysis.
1735    ///
1736    /// Moreover, the language is moving towards uninhabited variants still semantically
1737    /// causing a discriminant read, so we *shouldn't* perform any such check.
1738    ///
1739    /// FIXME(never_patterns): update this comment once the aforementioned MIR builder
1740    /// code is changed to be insensitive to inhhabitedness.
1741    #[instrument(skip(self), level = "debug")]
1742    fn is_multivariant_adt(&mut self, node: ExprOrPatIdPacked, ty: Ty<'db>) -> bool {
1743        if let TyKind::Adt(def, _) = self.cx.structurally_resolve_type(node, ty).kind() {
1744            // Note that if a non-exhaustive SingleVariant is defined in another crate, we need
1745            // to assume that more cases will be added to the variant in the future. This mean
1746            // that we should handle non-exhaustive SingleVariant the same way we would handle
1747            // a MultiVariant.
1748            match def.def_id() {
1749                AdtId::StructId(_) | AdtId::UnionId(_) => false,
1750                AdtId::EnumId(did) => {
1751                    let has_foreign_non_exhaustive = || {
1752                        AttrFlags::query(self.cx.db, did.into()).contains(AttrFlags::NON_EXHAUSTIVE)
1753                            && did.krate(self.cx.db) != self.cx.krate()
1754                    };
1755                    did.enum_variants(self.cx.db).variants.len() > 1 || has_foreign_non_exhaustive()
1756                }
1757            }
1758        } else {
1759            false
1760        }
1761    }
1762}