Skip to main content

rustc_hir_typeck/
place_op.rs

1use rustc_ast as ast;
2use rustc_errors::Applicability;
3use rustc_hir as hir;
4use rustc_hir_analysis::autoderef::Autoderef;
5use rustc_infer::infer::InferOk;
6use rustc_infer::traits::{Obligation, ObligationCauseCode};
7use rustc_middle::span_bug;
8use rustc_middle::ty::adjustment::{
9    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, DerefAdjustKind,
10    OverloadedDeref, PointerCoercion,
11};
12use rustc_middle::ty::{self, Ty};
13use rustc_span::{Span, sym};
14use tracing::debug;
15
16use crate::method::{MethodCallee, TreatNotYetDefinedOpaques};
17use crate::{FnCtxt, PlaceOp};
18
19impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20    /// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already.
21    pub(super) fn lookup_derefing(
22        &self,
23        expr: &hir::Expr<'_>,
24        oprnd_expr: &'tcx hir::Expr<'tcx>,
25        oprnd_ty: Ty<'tcx>,
26    ) -> Option<Ty<'tcx>> {
27        if let Some(ty) = oprnd_ty.builtin_deref(true) {
28            return Some(ty);
29        }
30
31        let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?;
32        let method = self.register_infer_ok_obligations(ok);
33        if let ty::Ref(_, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() {
34            self.apply_adjustments(
35                oprnd_expr,
36                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [Adjustment {
                    kind: Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)),
                    target: method.sig.inputs()[0],
                }]))vec![Adjustment {
37                    kind: Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)),
38                    target: method.sig.inputs()[0],
39                }],
40            );
41        } else {
42            ::rustc_middle::util::bug::span_bug_fmt(expr.span,
    format_args!("input to deref is not a ref?"));span_bug!(expr.span, "input to deref is not a ref?");
43        }
44        let ty = self.make_overloaded_place_return_type(method);
45        self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);
46        Some(ty)
47    }
48
49    /// Type-check `*base_expr[index_expr]` with `base_expr` and `index_expr` type-checked already.
50    pub(super) fn lookup_indexing(
51        &self,
52        expr: &hir::Expr<'_>,
53        base_expr: &'tcx hir::Expr<'tcx>,
54        base_ty: Ty<'tcx>,
55        index_expr: &'tcx hir::Expr<'tcx>,
56        idx_ty: Ty<'tcx>,
57    ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
58        // FIXME(#18741) -- this is almost but not quite the same as the
59        // autoderef that normal method probing does. They could likely be
60        // consolidated.
61
62        let mut autoderef = self.autoderef(base_expr.span, base_ty);
63        let mut result = None;
64        while result.is_none() && autoderef.next().is_some() {
65            result = self.try_index_step(expr, base_expr, &autoderef, idx_ty, index_expr);
66        }
67        self.register_predicates(autoderef.into_obligations());
68        result
69    }
70
71    fn negative_index(
72        &self,
73        ty: Ty<'tcx>,
74        span: Span,
75        base_expr: &hir::Expr<'_>,
76    ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
77        let ty = self.resolve_vars_if_possible(ty);
78        let mut err = self.dcx().struct_span_err(
79            span,
80            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("negative integers cannot be used to index on a `{0}`",
                ty))
    })format!("negative integers cannot be used to index on a `{ty}`"),
81        );
82        err.span_label(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cannot use a negative integer for indexing on `{0}`",
                ty))
    })format!("cannot use a negative integer for indexing on `{ty}`"));
83        if let (hir::ExprKind::Path(..), Ok(snippet)) =
84            (&base_expr.kind, self.tcx.sess.source_map().span_to_snippet(base_expr.span))
85        {
86            // `foo[-1]` to `foo[foo.len() - 1]`
87            err.span_suggestion_verbose(
88                span.shrink_to_lo(),
89                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("to access an element starting from the end of the `{0}`, compute the index",
                ty))
    })format!(
90                    "to access an element starting from the end of the `{ty}`, compute the index",
91                ),
92                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}.len() ", snippet))
    })format!("{snippet}.len() "),
93                Applicability::MachineApplicable,
94            );
95        }
96        let reported = err.emit();
97        Some((Ty::new_error(self.tcx, reported), Ty::new_error(self.tcx, reported)))
98    }
99
100    /// To type-check `base_expr[index_expr]`, we progressively autoderef
101    /// (and otherwise adjust) `base_expr`, looking for a type which either
102    /// supports builtin indexing or overloaded indexing.
103    /// This loop implements one step in that search; the autoderef loop
104    /// is implemented by `lookup_indexing`.
105    fn try_index_step(
106        &self,
107        expr: &hir::Expr<'_>,
108        base_expr: &hir::Expr<'_>,
109        autoderef: &Autoderef<'a, 'tcx>,
110        index_ty: Ty<'tcx>,
111        index_expr: &hir::Expr<'_>,
112    ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
113        let adjusted_ty = self.structurally_resolve_type(autoderef.span(), autoderef.final_ty());
114        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/place_op.rs:114",
                        "rustc_hir_typeck::place_op", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/place_op.rs"),
                        ::tracing_core::__macro_support::Option::Some(114u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::place_op"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("try_index_step(expr={0:?}, base_expr={1:?}, adjusted_ty={2:?}, index_ty={3:?})",
                                                    expr, base_expr, adjusted_ty, index_ty) as &dyn Value))])
            });
    } else { ; }
};debug!(
115            "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
116             index_ty={:?})",
117            expr, base_expr, adjusted_ty, index_ty
118        );
119
120        if let hir::ExprKind::Unary(
121            hir::UnOp::Neg,
122            hir::Expr {
123                kind: hir::ExprKind::Lit(hir::Lit { node: ast::LitKind::Int(..), .. }),
124                ..
125            },
126        ) = index_expr.kind
127        {
128            match adjusted_ty.kind() {
129                ty::Adt(def, _) if self.tcx.is_diagnostic_item(sym::Vec, def.did()) => {
130                    return self.negative_index(adjusted_ty, index_expr.span, base_expr);
131                }
132                ty::Slice(_) | ty::Array(_, _) => {
133                    return self.negative_index(adjusted_ty, index_expr.span, base_expr);
134                }
135                _ => {}
136            }
137        }
138
139        for unsize in [false, true] {
140            let mut self_ty = adjusted_ty;
141            if unsize {
142                // We only unsize arrays here.
143                if let ty::Array(element_ty, ct) = *adjusted_ty.kind() {
144                    self.register_predicate(Obligation::new(
145                        self.tcx,
146                        self.cause(base_expr.span, ObligationCauseCode::ArrayLen(adjusted_ty)),
147                        self.param_env,
148                        ty::ClauseKind::ConstArgHasType(ct, self.tcx.types.usize),
149                    ));
150                    self_ty = Ty::new_slice(self.tcx, element_ty);
151                } else {
152                    continue;
153                }
154            }
155
156            // If some lookup succeeds, write callee into table and extract index/element
157            // type from the method signature.
158            // If some lookup succeeded, install method in table
159            let input_ty = self.next_ty_var(base_expr.span);
160            let method =
161                self.try_overloaded_place_op(expr.span, self_ty, Some(input_ty), PlaceOp::Index);
162
163            if let Some(result) = method {
164                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/place_op.rs:164",
                        "rustc_hir_typeck::place_op", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/place_op.rs"),
                        ::tracing_core::__macro_support::Option::Some(164u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::place_op"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("try_index_step: success, using overloaded indexing")
                                            as &dyn Value))])
            });
    } else { ; }
};debug!("try_index_step: success, using overloaded indexing");
165                let method = self.register_infer_ok_obligations(result);
166
167                let mut adjustments = self.adjust_steps(autoderef);
168                if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() {
169                    adjustments.push(Adjustment {
170                        kind: Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)),
171                        target: Ty::new_imm_ref(self.tcx, *region, adjusted_ty),
172                    });
173                } else {
174                    ::rustc_middle::util::bug::span_bug_fmt(expr.span,
    format_args!("input to index is not a ref?"));span_bug!(expr.span, "input to index is not a ref?");
175                }
176                if unsize {
177                    adjustments.push(Adjustment {
178                        kind: Adjust::Pointer(PointerCoercion::Unsize),
179                        target: method.sig.inputs()[0],
180                    });
181                }
182                self.apply_adjustments(base_expr, adjustments);
183
184                self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);
185
186                return Some((input_ty, self.make_overloaded_place_return_type(method)));
187            }
188        }
189
190        None
191    }
192
193    /// Try to resolve an overloaded place op. We only deal with the immutable
194    /// variant here (Deref/Index). In some contexts we would need the mutable
195    /// variant (DerefMut/IndexMut); those would be later converted by
196    /// `convert_place_derefs_to_mutable`.
197    pub(super) fn try_overloaded_place_op(
198        &self,
199        span: Span,
200        base_ty: Ty<'tcx>,
201        opt_rhs_ty: Option<Ty<'tcx>>,
202        op: PlaceOp,
203    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
204        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/place_op.rs:204",
                        "rustc_hir_typeck::place_op", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/place_op.rs"),
                        ::tracing_core::__macro_support::Option::Some(204u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::place_op"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("try_overloaded_place_op({0:?},{1:?},{2:?})",
                                                    span, base_ty, op) as &dyn Value))])
            });
    } else { ; }
};debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
205
206        let (Some(imm_tr), imm_op) = (match op {
207            PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref),
208            PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index),
209        }) else {
210            // Bail if `Deref` or `Index` isn't defined.
211            return None;
212        };
213
214        // FIXME(trait-system-refactor-initiative#231): we may want to treat
215        // opaque types as rigid here to support `impl Deref<Target = impl Index<usize>>`.
216        let treat_opaques = TreatNotYetDefinedOpaques::AsInfer;
217        self.lookup_method_for_operator(
218            self.misc(span),
219            imm_op,
220            imm_tr,
221            base_ty,
222            opt_rhs_ty,
223            treat_opaques,
224        )
225    }
226
227    fn try_mutable_overloaded_place_op(
228        &self,
229        span: Span,
230        base_ty: Ty<'tcx>,
231        opt_rhs_ty: Option<Ty<'tcx>>,
232        op: PlaceOp,
233    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
234        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/place_op.rs:234",
                        "rustc_hir_typeck::place_op", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/place_op.rs"),
                        ::tracing_core::__macro_support::Option::Some(234u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::place_op"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("try_mutable_overloaded_place_op({0:?},{1:?},{2:?})",
                                                    span, base_ty, op) as &dyn Value))])
            });
    } else { ; }
};debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
235
236        let (Some(mut_tr), mut_op) = (match op {
237            PlaceOp::Deref => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut),
238            PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut),
239        }) else {
240            // Bail if `DerefMut` or `IndexMut` isn't defined.
241            return None;
242        };
243
244        // We have to replace the operator with the mutable variant for the
245        // program to compile, so we don't really have a choice here and want
246        // to just try using `DerefMut` even if its not in the item bounds
247        // of the opaque.
248        let treat_opaques = TreatNotYetDefinedOpaques::AsInfer;
249        self.lookup_method_for_operator(
250            self.misc(span),
251            mut_op,
252            mut_tr,
253            base_ty,
254            opt_rhs_ty,
255            treat_opaques,
256        )
257    }
258
259    /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index`
260    /// into `DerefMut` and `IndexMut` respectively.
261    ///
262    /// This is a second pass of typechecking derefs/indices. We need this because we do not
263    /// always know whether a place needs to be mutable or not in the first pass.
264    /// This happens whether there is an implicit mutable reborrow, e.g. when the type
265    /// is used as the receiver of a method call.
266    pub(crate) fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) {
267        // Gather up expressions we want to munge.
268        let mut exprs = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [expr]))vec![expr];
269
270        while let hir::ExprKind::Field(expr, _)
271        | hir::ExprKind::Index(expr, _, _)
272        | hir::ExprKind::Unary(hir::UnOp::Deref, expr) = exprs.last().unwrap().kind
273        {
274            exprs.push(expr);
275        }
276
277        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/place_op.rs:277",
                        "rustc_hir_typeck::place_op", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/place_op.rs"),
                        ::tracing_core::__macro_support::Option::Some(277u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::place_op"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("convert_place_derefs_to_mutable: exprs={0:?}",
                                                    exprs) as &dyn Value))])
            });
    } else { ; }
};debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
278
279        // Fix up autoderefs and derefs.
280        let mut inside_union = false;
281        for (i, &expr) in exprs.iter().rev().enumerate() {
282            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/place_op.rs:282",
                        "rustc_hir_typeck::place_op", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/place_op.rs"),
                        ::tracing_core::__macro_support::Option::Some(282u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::place_op"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("convert_place_derefs_to_mutable: i={0} expr={1:?}",
                                                    i, expr) as &dyn Value))])
            });
    } else { ; }
};debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
283
284            let mut source = self.node_ty(expr.hir_id);
285            if #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
    hir::ExprKind::Unary(hir::UnOp::Deref, _) => true,
    _ => false,
}matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::Deref, _)) {
286                // Clear previous flag; after a pointer indirection it does not apply any more.
287                inside_union = false;
288            }
289            if source.is_union() {
290                inside_union = true;
291            }
292            // Fix up the autoderefs. Autorefs can only occur immediately preceding
293            // overloaded place ops, and will be fixed by them in order to get
294            // the correct region.
295            // Do not mutate adjustments in place, but rather take them,
296            // and replace them after mutating them, to avoid having the
297            // typeck results borrowed during (`deref_mut`) method resolution.
298            let previous_adjustments =
299                self.typeck_results.borrow_mut().adjustments_mut().remove(expr.hir_id);
300            if let Some(mut adjustments) = previous_adjustments {
301                for adjustment in &mut adjustments {
302                    if let Adjust::Deref(DerefAdjustKind::Overloaded(ref mut deref)) =
303                        adjustment.kind
304                        && let Some(ok) = self.try_mutable_overloaded_place_op(
305                            expr.span,
306                            source,
307                            None,
308                            PlaceOp::Deref,
309                        )
310                    {
311                        let method = self.register_infer_ok_obligations(ok);
312                        let ty::Ref(_, _, mutbl) = *method.sig.output().kind() else {
313                            ::rustc_middle::util::bug::span_bug_fmt(self.tcx.def_span(method.def_id),
    format_args!("expected DerefMut to return a &mut"));span_bug!(
314                                self.tcx.def_span(method.def_id),
315                                "expected DerefMut to return a &mut"
316                            );
317                        };
318                        *deref = OverloadedDeref { mutbl, span: deref.span };
319                        self.enforce_context_effects(None, expr.span, method.def_id, method.args);
320                        // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514).
321                        // This helps avoid accidental drops.
322                        if inside_union
323                            && source.ty_adt_def().is_some_and(|adt| adt.is_manually_drop())
324                        {
325                            self.dcx().struct_span_err(
326                                expr.span,
327                                "not automatically applying `DerefMut` on `ManuallyDrop` union field",
328                            )
329                            .with_help(
330                                "writing to this reference calls the destructor for the old value",
331                            )
332                            .with_help("add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor")
333                            .emit();
334                        }
335                    }
336                    source = adjustment.target;
337                }
338                self.typeck_results.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
339            }
340
341            match expr.kind {
342                hir::ExprKind::Index(base_expr, ..) => {
343                    self.convert_place_op_to_mutable(PlaceOp::Index, expr, base_expr);
344                }
345                hir::ExprKind::Unary(hir::UnOp::Deref, base_expr) => {
346                    self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr);
347                }
348                _ => {}
349            }
350        }
351    }
352
353    fn convert_place_op_to_mutable(
354        &self,
355        op: PlaceOp,
356        expr: &hir::Expr<'_>,
357        base_expr: &hir::Expr<'_>,
358    ) {
359        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/place_op.rs:359",
                        "rustc_hir_typeck::place_op", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/place_op.rs"),
                        ::tracing_core::__macro_support::Option::Some(359u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::place_op"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("convert_place_op_to_mutable({0:?}, {1:?}, {2:?})",
                                                    op, expr, base_expr) as &dyn Value))])
            });
    } else { ; }
};debug!("convert_place_op_to_mutable({:?}, {:?}, {:?})", op, expr, base_expr);
360        if !self.typeck_results.borrow().is_method_call(expr) {
361            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/place_op.rs:361",
                        "rustc_hir_typeck::place_op", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/place_op.rs"),
                        ::tracing_core::__macro_support::Option::Some(361u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::place_op"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("convert_place_op_to_mutable - builtin, nothing to do")
                                            as &dyn Value))])
            });
    } else { ; }
};debug!("convert_place_op_to_mutable - builtin, nothing to do");
362            return;
363        }
364
365        // Need to deref because overloaded place ops take self by-reference.
366        let base_ty = self
367            .typeck_results
368            .borrow()
369            .expr_ty_adjusted(base_expr)
370            .builtin_deref(false)
371            .expect("place op takes something that is not a ref");
372
373        let arg_ty = match op {
374            PlaceOp::Deref => None,
375            PlaceOp::Index => {
376                // We would need to recover the `T` used when we resolve `<_ as Index<T>>::index`
377                // in try_index_step. This is the arg at index 1.
378                //
379                // Note: we should *not* use `expr_ty` of index_expr here because autoderef
380                // during coercions can cause type of index_expr to differ from `T` (#72002).
381                // We also could not use `expr_ty_adjusted` of index_expr because reborrowing
382                // during coercions can also cause type of index_expr to differ from `T`,
383                // which can potentially cause regionck failure (#74933).
384                Some(self.typeck_results.borrow().node_args(expr.hir_id).type_at(1))
385            }
386        };
387        let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_ty, op);
388        let method = match method {
389            Some(ok) => self.register_infer_ok_obligations(ok),
390            // Couldn't find the mutable variant of the place op, keep the
391            // current, immutable version.
392            None => return,
393        };
394        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/place_op.rs:394",
                        "rustc_hir_typeck::place_op", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/place_op.rs"),
                        ::tracing_core::__macro_support::Option::Some(394u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::place_op"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("convert_place_op_to_mutable: method={0:?}",
                                                    method) as &dyn Value))])
            });
    } else { ; }
};debug!("convert_place_op_to_mutable: method={:?}", method);
395        self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);
396
397        let ty::Ref(region, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() else {
398            ::rustc_middle::util::bug::span_bug_fmt(expr.span,
    format_args!("input to mutable place op is not a mut ref?"));span_bug!(expr.span, "input to mutable place op is not a mut ref?");
399        };
400
401        // Convert the autoref in the base expr to mutable with the correct
402        // region and mutability.
403        let base_expr_ty = self.node_ty(base_expr.hir_id);
404        if let Some(adjustments) =
405            self.typeck_results.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id)
406        {
407            let mut source = base_expr_ty;
408            for adjustment in &mut adjustments[..] {
409                if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
410                    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/place_op.rs:410",
                        "rustc_hir_typeck::place_op", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/place_op.rs"),
                        ::tracing_core::__macro_support::Option::Some(410u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::place_op"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("convert_place_op_to_mutable: converting autoref {0:?}",
                                                    adjustment) as &dyn Value))])
            });
    } else { ; }
};debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment);
411                    let mutbl = AutoBorrowMutability::Mut {
412                        // Deref/indexing can be desugared to a method call,
413                        // so maybe we could use two-phase here.
414                        // See the documentation of AllowTwoPhase for why that's
415                        // not the case today.
416                        allow_two_phase_borrow: AllowTwoPhase::No,
417                    };
418                    adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(mutbl));
419                    adjustment.target = Ty::new_ref(self.tcx, *region, source, mutbl.into());
420                }
421                source = adjustment.target;
422            }
423
424            // If we have an autoref followed by unsizing at the end, fix the unsize target.
425            if let [
426                ..,
427                Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
428                Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), ref mut target },
429            ] = adjustments[..]
430            {
431                *target = method.sig.inputs()[0];
432            }
433        }
434    }
435}