Skip to main content

rustc_hir_typeck/
place_op.rs

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