Skip to main content

rustc_hir_typeck/method/
prelude_edition_lints.rs

1use std::fmt::Write;
2
3use hir::def_id::DefId;
4use hir::{HirId, ItemKind};
5use rustc_ast::join_path_idents;
6use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level};
7use rustc_hir as hir;
8use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
9use rustc_middle::span_bug;
10use rustc_middle::ty::{self, Ty, TyCtxt};
11use rustc_session::lint::builtin::{RUST_2021_PRELUDE_COLLISIONS, RUST_2024_PRELUDE_COLLISIONS};
12use rustc_span::{Ident, STDLIB_STABLE_CRATES, Span, Symbol, kw, sym};
13use rustc_trait_selection::infer::InferCtxtExt;
14use tracing::debug;
15
16use crate::FnCtxt;
17use crate::method::probe::{self, Pick};
18
19struct AmbiguousTraitMethodCall<'a, 'b, 'tcx> {
20    segment_name: Symbol,
21    self_expr_span: Span,
22    pick: &'a Pick<'tcx>,
23    tcx: TyCtxt<'tcx>,
24    edition: &'b str,
25}
26
27impl<'a, 'b, 'c, 'tcx> Diagnostic<'a, ()> for AmbiguousTraitMethodCall<'b, 'c, 'tcx> {
28    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
29        let Self { segment_name, self_expr_span, pick, tcx, edition } = self;
30        let mut lint = Diag::new(
31            dcx,
32            level,
33            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("trait method `{0}` will become ambiguous in Rust {1}",
                segment_name, edition))
    })format!("trait method `{}` will become ambiguous in Rust {edition}", segment_name),
34        );
35        let derefs = "*".repeat(pick.autoderefs);
36
37        let autoref = match pick.autoref_or_ptr_adjustment {
38            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(),
39            Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
40            Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl {
41                hir::Mutability::Mut => "Pin<&mut ",
42                hir::Mutability::Not => "Pin<&",
43            },
44        };
45        if let Ok(self_expr) = tcx.sess.source_map().span_to_snippet(self_expr_span) {
46            let mut self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
47                pick.autoref_or_ptr_adjustment
48            {
49                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1} as *const _", derefs,
                self_expr))
    })format!("{derefs}{self_expr} as *const _")
50            } else {
51                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}{2}", autoref, derefs,
                self_expr))
    })format!("{autoref}{derefs}{self_expr}")
52            };
53
54            if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) =
55                pick.autoref_or_ptr_adjustment
56            {
57                self_adjusted.push('>');
58            }
59
60            lint.span_suggestion(
61                self_expr_span,
62                "disambiguate the method call",
63                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("({0})", self_adjusted))
    })format!("({self_adjusted})"),
64                Applicability::MachineApplicable,
65            );
66        } else {
67            let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
68                pick.autoref_or_ptr_adjustment
69            {
70                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}(...) as *const _", derefs))
    })format!("{derefs}(...) as *const _")
71            } else {
72                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}...", autoref, derefs))
    })format!("{autoref}{derefs}...")
73            };
74            lint.span_help(
75                self_expr_span,
76                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("disambiguate the method call with `({0})`",
                self_adjusted))
    })format!("disambiguate the method call with `({self_adjusted})`",),
77            );
78        }
79        lint
80    }
81}
82
83struct AmbiguousTraitMethod<'a, 'b, 'tcx, 'pcx, 'fnctx> {
84    segment: &'a hir::PathSegment<'pcx>,
85    call_expr: &'tcx hir::Expr<'tcx>,
86    self_expr: &'tcx hir::Expr<'tcx>,
87    pick: &'a Pick<'tcx>,
88    args: &'tcx [hir::Expr<'tcx>],
89    edition: &'b str,
90    span: Span,
91    this: &'a FnCtxt<'fnctx, 'tcx>,
92}
93
94impl<'a, 'b, 'c, 'tcx, 'pcx, 'fnctx> Diagnostic<'a, ()>
95    for AmbiguousTraitMethod<'b, 'c, 'tcx, 'pcx, 'fnctx>
96{
97    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
98        let Self { segment, call_expr, self_expr, pick, args, edition, span, this } = self;
99        let mut lint = Diag::new(
100            dcx,
101            level,
102            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("trait method `{0}` will become ambiguous in Rust {1}",
                segment.ident.name, edition))
    })format!(
103                "trait method `{}` will become ambiguous in Rust {edition}",
104                segment.ident.name
105            ),
106        );
107
108        let sp = call_expr.span;
109        let trait_name =
110            this.trait_path_or_bare_name(span, call_expr.hir_id, pick.item.container_id(this.tcx));
111
112        let (self_adjusted, precise) = this.adjust_expr(pick, self_expr, sp);
113        if precise {
114            let args = args.iter().fold(String::new(), |mut string, arg| {
115                let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
116                string.write_fmt(format_args!(", {0}",
        this.sess().source_map().span_to_snippet(span).unwrap()))write!(string, ", {}", this.sess().source_map().span_to_snippet(span).unwrap())
117                    .unwrap();
118                string
119            });
120
121            lint.span_suggestion(
122                sp,
123                "disambiguate the associated function",
124                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}::{1}{2}({3}{4})", trait_name,
                segment.ident.name,
                if let Some(args) =
                        segment.args.as_ref().and_then(|args|
                                this.sess().source_map().span_to_snippet(args.span_ext).ok())
                    {
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!("::{0}", args))
                        })
                } else { String::new() }, self_adjusted, args))
    })format!(
125                    "{}::{}{}({}{})",
126                    trait_name,
127                    segment.ident.name,
128                    if let Some(args) = segment.args.as_ref().and_then(|args| this
129                        .sess()
130                        .source_map()
131                        .span_to_snippet(args.span_ext)
132                        .ok())
133                    {
134                        // Keep turbofish.
135                        format!("::{args}")
136                    } else {
137                        String::new()
138                    },
139                    self_adjusted,
140                    args,
141                ),
142                Applicability::MachineApplicable,
143            );
144        } else {
145            lint.span_help(
146                sp,
147                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("disambiguate the associated function with `{0}::{1}(...)`",
                trait_name, segment.ident))
    })format!(
148                    "disambiguate the associated function with `{}::{}(...)`",
149                    trait_name, segment.ident,
150                ),
151            );
152        }
153        lint
154    }
155}
156
157impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
158    pub(super) fn lint_edition_dependent_dot_call(
159        &self,
160        self_ty: Ty<'tcx>,
161        segment: &hir::PathSegment<'_>,
162        span: Span,
163        call_expr: &'tcx hir::Expr<'tcx>,
164        self_expr: &'tcx hir::Expr<'tcx>,
165        pick: &Pick<'tcx>,
166        args: &'tcx [hir::Expr<'tcx>],
167    ) {
168        {
    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/method/prelude_edition_lints.rs:168",
                        "rustc_hir_typeck::method::prelude_edition_lints",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs"),
                        ::tracing_core::__macro_support::Option::Some(168u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::method::prelude_edition_lints"),
                        ::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!("lookup(method_name={0}, self_ty={1:?}, call_expr={2:?}, self_expr={3:?})",
                                                    segment.ident, self_ty, call_expr, self_expr) as
                                            &dyn Value))])
            });
    } else { ; }
};debug!(
169            "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
170            segment.ident, self_ty, call_expr, self_expr
171        );
172
173        let (prelude_or_array_lint, edition) = match segment.ident.name {
174            // `try_into` was added to the prelude in Rust 2021.
175            sym::try_into if !span.at_least_rust_2021() => (RUST_2021_PRELUDE_COLLISIONS, "2021"),
176            // `Future::poll` was added to the prelude in Rust 2024.
177            sym::poll
178                // We check that the self type is `Pin<&mut _>` to avoid false positives for this common name.
179                if !span.at_least_rust_2024()
180                    && let ty::Adt(adt_def, args) = self_ty.kind()
181                    && self.tcx.is_lang_item(adt_def.did(), hir::LangItem::Pin)
182                    && let ty::Ref(_, _, ty::Mutability::Mut) =
183                        args[0].as_type().unwrap().kind() =>
184            {
185                (RUST_2024_PRELUDE_COLLISIONS, "2024")
186            }
187            // `IntoFuture::into_future` was added to the prelude in Rust 2024.
188            sym::into_future if !span.at_least_rust_2024() => {
189                (RUST_2024_PRELUDE_COLLISIONS, "2024")
190            }
191            // `into_iter` wasn't added to the prelude,
192            // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
193            // before Rust 2021, which results in the same problem.
194            // It is only a problem for arrays.
195            sym::into_iter => {
196                if let ty::Array(..) = self_ty.kind()
197                    && !span.at_least_rust_2021()
198                {
199                    // In this case, it wasn't really a prelude addition that was the problem.
200                    // Instead, the problem is that the array-into_iter hack will no longer
201                    // apply in Rust 2021.
202                    (ARRAY_INTO_ITER, "2021")
203                } else if self_ty.boxed_ty().is_some_and(Ty::is_slice)
204                    && !span.at_least_rust_2024()
205                {
206                    // In this case, it wasn't really a prelude addition that was the problem.
207                    // Instead, the problem is that the boxed-slice-into_iter hack will no
208                    // longer apply in Rust 2024.
209                    (BOXED_SLICE_INTO_ITER, "2024")
210                } else {
211                    return;
212                }
213            }
214            _ => return,
215        };
216
217        // No need to lint if method came from std/core, as that will now be in the prelude
218        if STDLIB_STABLE_CRATES.contains(&self.tcx.crate_name(pick.item.def_id.krate)) {
219            return;
220        }
221
222        if #[allow(non_exhaustive_omitted_patterns)] match pick.kind {
    probe::PickKind::InherentImplPick | probe::PickKind::ObjectPick => true,
    _ => false,
}matches!(pick.kind, probe::PickKind::InherentImplPick | probe::PickKind::ObjectPick) {
223            // avoid repeatedly adding unneeded `&*`s
224            if pick.autoderefs == 1
225                && #[allow(non_exhaustive_omitted_patterns)] match pick.autoref_or_ptr_adjustment
    {
    Some(probe::AutorefOrPtrAdjustment::Autoref { .. }) => true,
    _ => false,
}matches!(
226                    pick.autoref_or_ptr_adjustment,
227                    Some(probe::AutorefOrPtrAdjustment::Autoref { .. })
228                )
229                && #[allow(non_exhaustive_omitted_patterns)] match self_ty.kind() {
    ty::Ref(..) => true,
    _ => false,
}matches!(self_ty.kind(), ty::Ref(..))
230            {
231                return;
232            }
233
234            // if it's an inherent `self` method (not `&self` or `&mut self`), it will take
235            // precedence over the `TryInto` impl, and thus won't break in 2021 edition
236            if pick.autoderefs == 0 && pick.autoref_or_ptr_adjustment.is_none() {
237                return;
238            }
239
240            // Inherent impls only require not relying on autoref and autoderef in order to
241            // ensure that the trait implementation won't be used
242            self.tcx.emit_node_span_lint(
243                prelude_or_array_lint,
244                self_expr.hir_id,
245                self_expr.span,
246                AmbiguousTraitMethodCall {
247                    segment_name: segment.ident.name,
248                    self_expr_span: self_expr.span,
249                    pick,
250                    tcx: self.tcx,
251                    edition,
252                },
253            );
254        } else {
255            // trait implementations require full disambiguation to not clash with the new prelude
256            // additions (i.e. convert from dot-call to fully-qualified call)
257            self.tcx.emit_node_span_lint(
258                prelude_or_array_lint,
259                call_expr.hir_id,
260                call_expr.span,
261                AmbiguousTraitMethod {
262                    segment,
263                    call_expr,
264                    self_expr,
265                    pick,
266                    args,
267                    edition,
268                    span,
269                    this: self,
270                },
271            );
272        }
273    }
274
275    pub(super) fn lint_fully_qualified_call_from_2018(
276        &self,
277        span: Span,
278        method_name: Ident,
279        self_ty: Ty<'tcx>,
280        self_ty_span: Span,
281        expr_id: hir::HirId,
282        pick: &Pick<'tcx>,
283    ) {
284        struct AmbiguousTraitAssocFunc<'a, 'fnctx, 'tcx> {
285            method_name: Symbol,
286            this: &'a FnCtxt<'fnctx, 'tcx>,
287            pick: &'a Pick<'tcx>,
288            span: Span,
289            expr_id: hir::HirId,
290            self_ty_span: Span,
291            self_ty: Ty<'tcx>,
292        }
293
294        impl<'a, 'b, 'fnctx, 'tcx> Diagnostic<'a, ()> for AmbiguousTraitAssocFunc<'b, 'fnctx, 'tcx> {
295            fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
296                let Self { method_name, this, pick, span, expr_id, self_ty_span, self_ty } = self;
297                let mut lint = Diag::new(
298                    dcx,
299                    level,
300                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("trait-associated function `{0}` will become ambiguous in Rust 2021",
                method_name))
    })format!(
301                        "trait-associated function `{}` will become ambiguous in Rust 2021",
302                        method_name
303                    ),
304                );
305
306                // "type" refers to either a type or, more likely, a trait from which
307                // the associated function or method is from.
308                let container_id = pick.item.container_id(this.tcx);
309                let trait_path = this.trait_path_or_bare_name(span, expr_id, container_id);
310                let trait_generics = this.tcx.generics_of(container_id);
311
312                let trait_name =
313                    if trait_generics.own_params.len() <= trait_generics.has_self as usize {
314                        trait_path
315                    } else {
316                        let counts = trait_generics.own_counts();
317                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}<{1}>", trait_path,
                std::iter::repeat("'_").take(counts.lifetimes).chain(std::iter::repeat("_").take(counts.types
                                        + counts.consts -
                                    trait_generics.has_self as
                                        usize)).collect::<Vec<_>>().join(", ")))
    })format!(
318                            "{}<{}>",
319                            trait_path,
320                            std::iter::repeat("'_")
321                                .take(counts.lifetimes)
322                                .chain(std::iter::repeat("_").take(
323                                    counts.types + counts.consts - trait_generics.has_self as usize
324                                ))
325                                .collect::<Vec<_>>()
326                                .join(", ")
327                        )
328                    };
329
330                let mut self_ty_name = self_ty_span
331                    .find_ancestor_inside(span)
332                    .and_then(|span| this.sess().source_map().span_to_snippet(span).ok())
333                    .unwrap_or_else(|| self_ty.to_string());
334
335                // Get the number of generics the self type has (if an Adt) unless we can determine that
336                // the user has written the self type with generics already which we (naively) do by looking
337                // for a "<" in `self_ty_name`.
338                if !self_ty_name.contains('<') {
339                    if let ty::Adt(def, _) = self_ty.kind() {
340                        let generics = this.tcx.generics_of(def.did());
341                        if !generics.is_own_empty() {
342                            let counts = generics.own_counts();
343                            self_ty_name += &::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("<{0}>",
                std::iter::repeat("'_").take(counts.lifetimes).chain(std::iter::repeat("_").take(counts.types
                                    + counts.consts)).collect::<Vec<_>>().join(", ")))
    })format!(
344                                "<{}>",
345                                std::iter::repeat("'_")
346                                    .take(counts.lifetimes)
347                                    .chain(
348                                        std::iter::repeat("_").take(counts.types + counts.consts)
349                                    )
350                                    .collect::<Vec<_>>()
351                                    .join(", ")
352                            );
353                        }
354                    }
355                }
356                lint.span_suggestion(
357                    span,
358                    "disambiguate the associated function",
359                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("<{0} as {1}>::{2}", self_ty_name,
                trait_name, method_name))
    })format!("<{} as {}>::{}", self_ty_name, trait_name, method_name),
360                    Applicability::MachineApplicable,
361                );
362                lint
363            }
364        }
365
366        // Rust 2021 and later is already using the new prelude
367        if span.at_least_rust_2021() {
368            return;
369        }
370
371        // These are the fully qualified methods added to prelude in Rust 2021
372        if !#[allow(non_exhaustive_omitted_patterns)] match method_name.name {
    sym::try_into | sym::try_from | sym::from_iter => true,
    _ => false,
}matches!(method_name.name, sym::try_into | sym::try_from | sym::from_iter) {
373            return;
374        }
375
376        // No need to lint if method came from std/core, as that will now be in the prelude
377        if STDLIB_STABLE_CRATES.contains(&self.tcx.crate_name(pick.item.def_id.krate)) {
378            return;
379        }
380
381        // For from_iter, check if the type actually implements FromIterator.
382        // If we know it does not, we don't need to warn.
383        if method_name.name == sym::from_iter {
384            if let Some(trait_def_id) = self.tcx.get_diagnostic_item(sym::FromIterator) {
385                let any_type = self.infcx.next_ty_var(span);
386                if !self
387                    .infcx
388                    .type_implements_trait(trait_def_id, [self_ty, any_type], self.param_env)
389                    .may_apply()
390                {
391                    return;
392                }
393            }
394        }
395
396        // No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`,
397        // since such methods take precedence over trait methods.
398        if #[allow(non_exhaustive_omitted_patterns)] match pick.kind {
    probe::PickKind::InherentImplPick => true,
    _ => false,
}matches!(pick.kind, probe::PickKind::InherentImplPick) {
399            return;
400        }
401
402        self.tcx.emit_node_span_lint(
403            RUST_2021_PRELUDE_COLLISIONS,
404            expr_id,
405            span,
406            AmbiguousTraitAssocFunc {
407                method_name: method_name.name,
408                this: self,
409                pick,
410                span,
411                expr_id,
412                self_ty_span,
413                self_ty,
414            },
415        );
416    }
417
418    fn trait_path_or_bare_name(
419        &self,
420        span: Span,
421        expr_hir_id: HirId,
422        trait_def_id: DefId,
423    ) -> String {
424        self.trait_path(span, expr_hir_id, trait_def_id).unwrap_or_else(|| {
425            let key = self.tcx.def_key(trait_def_id);
426            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", key.disambiguated_data.data))
    })format!("{}", key.disambiguated_data.data)
427        })
428    }
429
430    fn trait_path(&self, span: Span, expr_hir_id: HirId, trait_def_id: DefId) -> Option<String> {
431        let applicable_traits = self.tcx.in_scope_traits(expr_hir_id)?;
432        let applicable_trait = applicable_traits.iter().find(|t| t.def_id == trait_def_id)?;
433        if applicable_trait.import_ids.is_empty() {
434            // The trait was declared within the module, we only need to use its name.
435            return None;
436        }
437
438        let import_items: Vec<_> = applicable_trait
439            .import_ids
440            .iter()
441            .map(|&import_id| self.tcx.hir_expect_item(import_id))
442            .collect();
443
444        // Find an identifier with which this trait was imported (note that `_` doesn't count).
445        for item in import_items.iter() {
446            let (_, kind) = item.expect_use();
447            match kind {
448                hir::UseKind::Single(ident) => {
449                    if ident.name != kw::Underscore {
450                        return Some(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", ident.name))
    })format!("{}", ident.name));
451                    }
452                }
453                hir::UseKind::Glob => return None, // Glob import, so just use its name.
454                hir::UseKind::ListStem => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
455            }
456        }
457
458        // All that is left is `_`! We need to use the full path. It doesn't matter which one we
459        // pick, so just take the first one.
460        match import_items[0].kind {
461            ItemKind::Use(path, _) => {
462                Some(join_path_idents(path.segments.iter().map(|seg| seg.ident)))
463            }
464            _ => {
465                ::rustc_middle::util::bug::span_bug_fmt(span,
    format_args!("unexpected item kind, expected a use: {0:?}",
        import_items[0].kind));span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind);
466            }
467        }
468    }
469
470    /// Creates a string version of the `expr` that includes explicit adjustments.
471    /// Returns the string and also a bool indicating whether this is a *precise*
472    /// suggestion.
473    fn adjust_expr(
474        &self,
475        pick: &Pick<'tcx>,
476        expr: &hir::Expr<'tcx>,
477        outer: Span,
478    ) -> (String, bool) {
479        let derefs = "*".repeat(pick.autoderefs);
480
481        let autoref = match pick.autoref_or_ptr_adjustment {
482            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(),
483            Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
484            Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl {
485                hir::Mutability::Mut => "Pin<&mut ",
486                hir::Mutability::Not => "Pin<&",
487            },
488        };
489
490        let (expr_text, precise) = if let Some(expr_text) = expr
491            .span
492            .find_ancestor_inside(outer)
493            .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
494        {
495            (expr_text, true)
496        } else {
497            ("(..)".to_string(), false)
498        };
499
500        let mut adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
501            pick.autoref_or_ptr_adjustment
502        {
503            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1} as *const _", derefs,
                expr_text))
    })format!("{derefs}{expr_text} as *const _")
504        } else {
505            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}{2}", autoref, derefs,
                expr_text))
    })format!("{autoref}{derefs}{expr_text}")
506        };
507
508        if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = pick.autoref_or_ptr_adjustment
509        {
510            adjusted_text.push('>');
511        }
512
513        (adjusted_text, precise)
514    }
515}