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