Skip to main content

rustc_trait_selection/error_reporting/infer/
note_and_explain.rs

1use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
2use rustc_errors::{Diag, MultiSpan, pluralize};
3use rustc_hir::def::DefKind;
4use rustc_hir::{self as hir, LangItem, find_attr};
5use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
6use rustc_middle::ty::error::{ExpectedFound, TypeError};
7use rustc_middle::ty::fast_reject::DeepRejectCtxt;
8use rustc_middle::ty::print::{FmtPrinter, Printer};
9use rustc_middle::ty::{self, Ty, suggest_constraining_type_param};
10use rustc_span::def_id::DefId;
11use rustc_span::{BytePos, Span, Symbol};
12use tracing::debug;
13
14use crate::error_reporting::TypeErrCtxt;
15use crate::infer::InferCtxtExt;
16
17impl<'tcx> TypeErrCtxt<'_, 'tcx> {
18    pub fn note_and_explain_type_err(
19        &self,
20        diag: &mut Diag<'_>,
21        err: TypeError<'tcx>,
22        cause: &ObligationCause<'tcx>,
23        sp: Span,
24        body_owner_def_id: Option<DefId>,
25    ) {
26        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs:26",
                        "rustc_trait_selection::error_reporting::infer::note_and_explain",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs"),
                        ::tracing_core::__macro_support::Option::Some(26u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::infer::note_and_explain"),
                        ::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!("note_and_explain_type_err err={0:?} cause={1:?}",
                                                    err, cause) as &dyn Value))])
            });
    } else { ; }
};debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
27
28        let tcx = self.tcx;
29
30        let body_generics = body_owner_def_id.map(|def_id| tcx.generics_of(def_id));
31
32        match err {
33            TypeError::ArgumentSorts(values, _) | TypeError::Sorts(values) => {
34                match (*values.expected.kind(), *values.found.kind()) {
35                    (ty::Closure(..), ty::Closure(..)) => {
36                        diag.note("no two closures, even if identical, have the same type");
37                        diag.help("consider boxing your closure and/or using it as a trait object");
38                    }
39                    (ty::Coroutine(def_id1, ..), ty::Coroutine(def_id2, ..))
40                        if self.tcx.coroutine_is_async(def_id1)
41                            && self.tcx.coroutine_is_async(def_id2) =>
42                    {
43                        diag.note("no two async blocks, even if identical, have the same type");
44                        diag.help(
45                            "consider pinning your async block and casting it to a trait object",
46                        );
47                    }
48                    (
49                        ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }),
50                        ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }),
51                    ) => {
52                        // Issue #63167
53                        diag.note("distinct uses of `impl Trait` result in different opaque types");
54                    }
55                    (ty::Float(_), ty::Infer(ty::IntVar(_)))
56                        if let Ok(
57                            // Issue #53280
58                            snippet,
59                        ) = tcx.sess.source_map().span_to_snippet(sp) =>
60                    {
61                        if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
62                            diag.span_suggestion_verbose(
63                                sp.shrink_to_hi(),
64                                "use a float literal",
65                                ".0",
66                                MachineApplicable,
67                            );
68                        }
69                    }
70                    (ty::Param(expected), ty::Param(found)) => {
71                        if let Some(generics) = body_generics {
72                            let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id);
73                            if !sp.contains(e_span) {
74                                diag.span_label(e_span, "expected type parameter");
75                            }
76                            let f_span = tcx.def_span(generics.type_param(found, tcx).def_id);
77                            if !sp.contains(f_span) {
78                                diag.span_label(f_span, "found type parameter");
79                            }
80                        }
81                        diag.note(
82                            "a type parameter was expected, but a different one was found; \
83                             you might be missing a type parameter or trait bound",
84                        );
85                        diag.note(
86                            "for more information, visit \
87                             https://doc.rust-lang.org/book/ch10-02-traits.html\
88                             #traits-as-parameters",
89                        );
90                    }
91                    (
92                        ty::Alias(ty::AliasTy {
93                            kind: ty::Projection { .. } | ty::Inherent { .. },
94                            ..
95                        }),
96                        ty::Alias(ty::AliasTy {
97                            kind: ty::Projection { .. } | ty::Inherent { .. },
98                            ..
99                        }),
100                    ) => {
101                        diag.note("an associated type was expected, but a different one was found");
102                    }
103                    // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
104                    (
105                        ty::Param(p),
106                        ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { def_id }, .. }),
107                    )
108                    | (
109                        ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { def_id }, .. }),
110                        ty::Param(p),
111                    ) if !tcx.is_impl_trait_in_trait(def_id)
112                        && let Some(generics) = body_generics =>
113                    {
114                        let param = generics.type_param(p, tcx);
115                        let p_def_id = param.def_id;
116                        let p_span = tcx.def_span(p_def_id);
117                        let expected = match (values.expected.kind(), values.found.kind()) {
118                            (ty::Param(_), _) => "expected ",
119                            (_, ty::Param(_)) => "found ",
120                            _ => "",
121                        };
122                        if !sp.contains(p_span) {
123                            diag.span_label(p_span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}this type parameter", expected))
    })format!("{expected}this type parameter"));
124                        }
125                        let param_def_id = match *proj.self_ty().kind() {
126                            ty::Param(param) => generics.type_param(param, tcx).def_id,
127                            _ => p_def_id,
128                        };
129                        let parent = param_def_id.as_local().and_then(|id| {
130                            let local_id = tcx.local_def_id_to_hir_id(id);
131                            let generics = tcx.parent_hir_node(local_id).generics()?;
132                            Some((id, generics))
133                        });
134                        let mut note = true;
135                        if let Some((local_id, generics)) = parent {
136                            // Synthesize the associated type restriction `Add<Output = Expected>`.
137                            // FIXME: extract this logic for use in other diagnostics.
138                            let (trait_ref, assoc_args) = proj.trait_ref_and_own_args(tcx);
139                            let item_name = tcx.item_name(def_id);
140                            let item_args = self.format_generic_args(assoc_args);
141
142                            if
143                            // if we're referencing an async fn trait's output future
144                            //
145                            // AsyncFnOnce
146                            (tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncFnOnce)
147                                && tcx.is_lang_item(def_id, LangItem::CallOnceFuture))
148                            // AsyncFnMut
149                            ||
150                            (tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncFnMut)
151                                && tcx.is_lang_item(def_id, LangItem::CallRefFuture))
152                            // AsyncFn
153                            ||
154                            (tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncFn)
155                                && tcx.is_lang_item(def_id, LangItem::CallRefFuture))
156                            {
157                                // don't make a suggestion to constrain it, it's not possible in
158                                // current rust. In fact, when something is referring to this, you
159                                // may have just needed to await something.
160
161                                diag.help("you may have forgotten to await an async function");
162                                diag.note(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("it is currently not possible to add bounds constraining the future returned from an async function (`{0}`)",
                item_name))
    })format!("it is currently not possible to add bounds constraining the future returned from an async function (`{item_name}`)"));
163                                // don't note, since it's talking about missing bounds. There's
164                                // currently no way to bound the return future
165                                note = false;
166                            } else {
167                                // Here, we try to see if there's an existing
168                                // trait implementation that matches the one that
169                                // we're suggesting to restrict. If so, find the
170                                // "end", whether it be at the end of the trait
171                                // or the end of the generic arguments.
172                                let mut matching_span = None;
173                                let mut matched_end_of_args = false;
174                                for bound in generics.bounds_for_param(local_id) {
175                                    let potential_spans = bound.bounds.iter().find_map(|bound| {
176                                        let bound_trait_path = bound.trait_ref()?.path;
177                                        let def_id = bound_trait_path.res.opt_def_id()?;
178                                        let generic_args = bound_trait_path
179                                            .segments
180                                            .iter()
181                                            .last()
182                                            .map(|path| path.args());
183                                        (def_id == trait_ref.def_id)
184                                            .then_some((bound_trait_path.span, generic_args))
185                                    });
186
187                                    if let Some((end_of_trait, end_of_args)) = potential_spans {
188                                        let args_span = end_of_args.and_then(|args| args.span());
189                                        matched_end_of_args = args_span.is_some();
190                                        matching_span = args_span
191                                            .or_else(|| Some(end_of_trait))
192                                            .map(|span| span.shrink_to_hi());
193                                        break;
194                                    }
195                                }
196
197                                if matched_end_of_args {
198                                    // Append suggestion to the end of our args
199                                    let path = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(", {0}{1} = {2}", item_name,
                item_args, p))
    })format!(", {item_name}{item_args} = {p}");
200                                    note = !suggest_constraining_type_param(
201                                        tcx,
202                                        generics,
203                                        diag,
204                                        &proj.self_ty().to_string(),
205                                        &path,
206                                        None,
207                                        matching_span,
208                                    );
209                                } else {
210                                    // Suggest adding a bound to an existing trait
211                                    // or if the trait doesn't exist, add the trait
212                                    // and the suggested bounds.
213                                    let path = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("<{0}{1} = {2}>", item_name,
                item_args, p))
    })format!("<{item_name}{item_args} = {p}>");
214                                    note = !suggest_constraining_type_param(
215                                        tcx,
216                                        generics,
217                                        diag,
218                                        &proj.self_ty().to_string(),
219                                        &path,
220                                        None,
221                                        matching_span,
222                                    );
223                                }
224                            }
225                        }
226                        if note {
227                            diag.note("you might be missing a type parameter or trait bound");
228                        }
229                    }
230                    (
231                        ty::Param(p),
232                        ty::Dynamic(..) | ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }),
233                    )
234                    | (
235                        ty::Dynamic(..) | ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }),
236                        ty::Param(p),
237                    ) => {
238                        if let Some(generics) = body_generics {
239                            let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
240                            let expected = match (values.expected.kind(), values.found.kind()) {
241                                (ty::Param(_), _) => "expected ",
242                                (_, ty::Param(_)) => "found ",
243                                _ => "",
244                            };
245                            if !sp.contains(p_span) {
246                                diag.span_label(p_span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}this type parameter", expected))
    })format!("{expected}this type parameter"));
247                            }
248                        }
249                        diag.help("type parameters must be constrained to match other types");
250                        if diag.code.is_some_and(|code| tcx.sess.teach(code)) {
251                            diag.help(
252                                "given a type parameter `T` and a method `foo`:
253```
254trait Trait<T> { fn foo(&self) -> T; }
255```
256the only ways to implement method `foo` are:
257- constrain `T` with an explicit type:
258```
259impl Trait<String> for X {
260    fn foo(&self) -> String { String::new() }
261}
262```
263- add a trait bound to `T` and call a method on that trait that returns `Self`:
264```
265impl<T: std::default::Default> Trait<T> for X {
266    fn foo(&self) -> T { <T as std::default::Default>::default() }
267}
268```
269- change `foo` to return an argument of type `T`:
270```
271impl<T> Trait<T> for X {
272    fn foo(&self, x: T) -> T { x }
273}
274```",
275                            );
276                        }
277                        diag.note(
278                            "for more information, visit \
279                             https://doc.rust-lang.org/book/ch10-02-traits.html\
280                             #traits-as-parameters",
281                        );
282                    }
283                    (
284                        ty::Param(p),
285                        ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..),
286                    ) => {
287                        if let Some(generics) = body_generics {
288                            let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
289                            if !sp.contains(p_span) {
290                                diag.span_label(p_span, "expected this type parameter");
291                            }
292                        }
293                        diag.help(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("every closure has a distinct type and so could not always match the caller-chosen type of parameter `{0}`",
                p))
    })format!(
294                            "every closure has a distinct type and so could not always match the \
295                             caller-chosen type of parameter `{p}`"
296                        ));
297                    }
298                    (ty::Param(p), _) | (_, ty::Param(p)) if let Some(generics) = body_generics => {
299                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
300                        let expected = match (values.expected.kind(), values.found.kind()) {
301                            (ty::Param(_), _) => "expected ",
302                            (_, ty::Param(_)) => "found ",
303                            _ => "",
304                        };
305                        if !sp.contains(p_span) {
306                            diag.span_label(p_span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}this type parameter", expected))
    })format!("{expected}this type parameter"));
307                        }
308                    }
309                    (
310                        ty::Alias(
311                            proj_ty @ ty::AliasTy {
312                                kind: ty::Projection { def_id } | ty::Inherent { def_id },
313                                ..
314                            },
315                        ),
316                        _,
317                    ) if !tcx.is_impl_trait_in_trait(def_id) => {
318                        self.expected_projection(
319                            diag,
320                            proj_ty,
321                            values,
322                            body_owner_def_id,
323                            cause.code(),
324                        );
325                    }
326                    // Don't suggest constraining a projection to something
327                    // containing itself, e.g. `Item = &<I as Iterator>::Item`.
328                    (
329                        _,
330                        ty::Alias(
331                            proj_ty @ ty::AliasTy {
332                                kind: ty::Projection { def_id } | ty::Inherent { def_id },
333                                ..
334                            },
335                        ),
336                    ) if !tcx.is_impl_trait_in_trait(def_id)
337                        && !tcx
338                            .erase_and_anonymize_regions(values.expected)
339                            .contains(tcx.erase_and_anonymize_regions(values.found)) =>
340                    {
341                        let msg = || {
342                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider constraining the associated type `{0}` to `{1}`",
                values.found, values.expected))
    })format!(
343                                "consider constraining the associated type `{}` to `{}`",
344                                values.found, values.expected,
345                            )
346                        };
347                        let suggested_projection_constraint =
348                            #[allow(non_exhaustive_omitted_patterns)] match proj_ty.kind {
    ty::Projection { .. } => true,
    _ => false,
}matches!(proj_ty.kind, ty::Projection { .. })
349                                && (self.suggest_constraining_opaque_associated_type(
350                                    diag,
351                                    msg,
352                                    proj_ty,
353                                    values.expected,
354                                ) || self.suggest_constraint(
355                                    diag,
356                                    &msg,
357                                    body_owner_def_id,
358                                    proj_ty,
359                                    values.expected,
360                                ));
361                        if !suggested_projection_constraint {
362                            diag.help(msg());
363                            diag.note(
364                                "for more information, visit \
365                                https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
366                            );
367                        }
368                    }
369                    (
370                        ty::Dynamic(t, _),
371                        ty::Alias(ty::AliasTy {
372                            kind: ty::Opaque { def_id: opaque_def_id }, ..
373                        }),
374                    ) if let Some(def_id) = t.principal_def_id()
375                        && tcx
376                            .explicit_item_self_bounds(opaque_def_id)
377                            .skip_binder()
378                            .iter()
379                            .any(|(pred, _span)| match pred.kind().skip_binder() {
380                                ty::ClauseKind::Trait(trait_predicate)
381                                    if trait_predicate.polarity
382                                        == ty::PredicatePolarity::Positive =>
383                                {
384                                    trait_predicate.def_id() == def_id
385                                }
386                                _ => false,
387                            }) =>
388                    {
389                        diag.help(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("you can box the `{0}` to coerce it to `Box<{1}>`, but you\'ll have to change the expected type as well",
                values.found, values.expected))
    })format!(
390                            "you can box the `{}` to coerce it to `Box<{}>`, but you'll have to \
391                             change the expected type as well",
392                            values.found, values.expected,
393                        ));
394                    }
395                    (ty::Dynamic(t, _), _) if let Some(def_id) = t.principal_def_id() => {
396                        let mut has_matching_impl = false;
397                        tcx.for_each_relevant_impl(def_id, values.found, |did| {
398                            if DeepRejectCtxt::relate_rigid_infer(tcx)
399                                .types_may_unify(values.found, tcx.type_of(did).skip_binder())
400                            {
401                                has_matching_impl = true;
402                            }
403                        });
404                        if has_matching_impl {
405                            let trait_name = tcx.item_name(def_id);
406                            diag.help(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` implements `{1}` so you could box the found value and coerce it to the trait object `Box<dyn {1}>`, you will have to change the expected type as well",
                values.found, trait_name))
    })format!(
407                                "`{}` implements `{trait_name}` so you could box the found value \
408                                 and coerce it to the trait object `Box<dyn {trait_name}>`, you \
409                                 will have to change the expected type as well",
410                                values.found,
411                            ));
412                        }
413                    }
414                    (_, ty::Dynamic(t, _)) if let Some(def_id) = t.principal_def_id() => {
415                        let mut has_matching_impl = false;
416                        tcx.for_each_relevant_impl(def_id, values.expected, |did| {
417                            if DeepRejectCtxt::relate_rigid_infer(tcx)
418                                .types_may_unify(values.expected, tcx.type_of(did).skip_binder())
419                            {
420                                has_matching_impl = true;
421                            }
422                        });
423                        if has_matching_impl {
424                            let trait_name = tcx.item_name(def_id);
425                            diag.help(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` implements `{1}` so you could change the expected type to `Box<dyn {1}>`",
                values.expected, trait_name))
    })format!(
426                                "`{}` implements `{trait_name}` so you could change the expected \
427                                 type to `Box<dyn {trait_name}>`",
428                                values.expected,
429                            ));
430                        }
431                    }
432                    (_, ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }))
433                    | (ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }), _) => {
434                        if let Some(body_owner_def_id) = body_owner_def_id
435                            && def_id.is_local()
436                            && #[allow(non_exhaustive_omitted_patterns)] match tcx.def_kind(body_owner_def_id)
    {
    DefKind::Fn | DefKind::Static { .. } | DefKind::Const { .. } |
        DefKind::AssocFn | DefKind::AssocConst { .. } => true,
    _ => false,
}matches!(
437                                tcx.def_kind(body_owner_def_id),
438                                DefKind::Fn
439                                    | DefKind::Static { .. }
440                                    | DefKind::Const { .. }
441                                    | DefKind::AssocFn
442                                    | DefKind::AssocConst { .. }
443                            )
444                            && #[allow(non_exhaustive_omitted_patterns)] match tcx.opaque_ty_origin(def_id) {
    hir::OpaqueTyOrigin::TyAlias { .. } => true,
    _ => false,
}matches!(
445                                tcx.opaque_ty_origin(def_id),
446                                hir::OpaqueTyOrigin::TyAlias { .. }
447                            )
448                            && !tcx
449                                .opaque_types_defined_by(body_owner_def_id.expect_local())
450                                .contains(&def_id.expect_local())
451                        {
452                            let sp = tcx
453                                .def_ident_span(body_owner_def_id)
454                                .unwrap_or_else(|| tcx.def_span(body_owner_def_id));
455                            let mut alias_def_id = def_id;
456                            while let DefKind::OpaqueTy = tcx.def_kind(alias_def_id) {
457                                alias_def_id = tcx.parent(alias_def_id);
458                            }
459                            let opaque_path = tcx.def_path_str(alias_def_id);
460                            // FIXME(type_alias_impl_trait): make this a structured suggestion
461                            match tcx.opaque_ty_origin(def_id) {
462                                rustc_hir::OpaqueTyOrigin::FnReturn { .. } => {}
463                                rustc_hir::OpaqueTyOrigin::AsyncFn { .. } => {}
464                                rustc_hir::OpaqueTyOrigin::TyAlias {
465                                    in_assoc_ty: false, ..
466                                } => {
467                                    diag.span_note(
468                                        sp,
469                                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("this item must have a `#[define_opaque({0})]` attribute to be able to define hidden types",
                opaque_path))
    })format!("this item must have a `#[define_opaque({opaque_path})]` \
470                                        attribute to be able to define hidden types"),
471                                    );
472                                }
473                                rustc_hir::OpaqueTyOrigin::TyAlias {
474                                    in_assoc_ty: true, ..
475                                } => {}
476                            }
477                        }
478                        // If two if arms can be coerced to a trait object, provide a structured
479                        // suggestion.
480                        let ObligationCauseCode::IfExpression { expr_id, .. } = cause.code() else {
481                            return;
482                        };
483                        let hir::Node::Expr(&hir::Expr {
484                            kind:
485                                hir::ExprKind::If(
486                                    _,
487                                    &hir::Expr {
488                                        kind:
489                                            hir::ExprKind::Block(
490                                                &hir::Block { expr: Some(then), .. },
491                                                _,
492                                            ),
493                                        ..
494                                    },
495                                    Some(&hir::Expr {
496                                        kind:
497                                            hir::ExprKind::Block(
498                                                &hir::Block { expr: Some(else_), .. },
499                                                _,
500                                            ),
501                                        ..
502                                    }),
503                                ),
504                            ..
505                        }) = self.tcx.hir_node(*expr_id)
506                        else {
507                            return;
508                        };
509                        let expected = match values.found.kind() {
510                            ty::Alias(..) => values.expected,
511                            _ => values.found,
512                        };
513                        let preds = tcx.explicit_item_self_bounds(def_id);
514                        for (pred, _span) in preds.skip_binder() {
515                            let ty::ClauseKind::Trait(trait_predicate) = pred.kind().skip_binder()
516                            else {
517                                continue;
518                            };
519                            if trait_predicate.polarity != ty::PredicatePolarity::Positive {
520                                continue;
521                            }
522                            let def_id = trait_predicate.def_id();
523                            let mut impl_def_ids = ::alloc::vec::Vec::new()vec![];
524                            tcx.for_each_relevant_impl(def_id, expected, |did| {
525                                impl_def_ids.push(did)
526                            });
527                            if let [_] = &impl_def_ids[..] {
528                                let trait_name = tcx.item_name(def_id);
529                                diag.multipart_suggestion(
530                                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` implements `{1}` so you can box both arms and coerce to the trait object `Box<dyn {1}>`",
                expected, trait_name))
    })format!(
531                                        "`{expected}` implements `{trait_name}` so you can box \
532                                         both arms and coerce to the trait object \
533                                         `Box<dyn {trait_name}>`",
534                                    ),
535                                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(then.span.shrink_to_lo(), "Box::new(".to_string()),
                (then.span.shrink_to_hi(),
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!(") as Box<dyn {0}>",
                                    tcx.def_path_str(def_id)))
                        })), (else_.span.shrink_to_lo(), "Box::new(".to_string()),
                (else_.span.shrink_to_hi(), ")".to_string())]))vec![
536                                        (then.span.shrink_to_lo(), "Box::new(".to_string()),
537                                        (
538                                            then.span.shrink_to_hi(),
539                                            format!(") as Box<dyn {}>", tcx.def_path_str(def_id)),
540                                        ),
541                                        (else_.span.shrink_to_lo(), "Box::new(".to_string()),
542                                        (else_.span.shrink_to_hi(), ")".to_string()),
543                                    ],
544                                    MachineApplicable,
545                                );
546                            }
547                        }
548                    }
549                    (ty::FnPtr(_, hdr), ty::FnDef(def_id, _))
550                    | (ty::FnDef(def_id, _), ty::FnPtr(_, hdr)) => {
551                        if tcx.fn_sig(def_id).skip_binder().safety() < hdr.safety() {
552                            if !tcx.codegen_fn_attrs(def_id).safe_target_features {
553                                diag.note(
554                                "unsafe functions cannot be coerced into safe function pointers",
555                                );
556                            }
557                        }
558                    }
559                    (ty::Adt(_, _), ty::Adt(def, args))
560                        if let ObligationCauseCode::IfExpression { expr_id, .. } = cause.code()
561                            && let hir::Node::Expr(if_expr) = self.tcx.hir_node(*expr_id)
562                            && let hir::ExprKind::If(_, then_expr, _) = if_expr.kind
563                            && let hir::ExprKind::Block(blk, _) = then_expr.kind
564                            && let Some(then) = blk.expr
565                            && def.is_box()
566                            && let boxed_ty = args.type_at(0)
567                            && let ty::Dynamic(t, _) = boxed_ty.kind()
568                            && let Some(def_id) = t.principal_def_id()
569                            && let mut impl_def_ids = ::alloc::vec::Vec::new()vec![]
570                            && let _ =
571                                tcx.for_each_relevant_impl(def_id, values.expected, |did| {
572                                    impl_def_ids.push(did)
573                                })
574                            && let [_] = &impl_def_ids[..] =>
575                    {
576                        // We have divergent if/else arms where the expected value is a type that
577                        // implements the trait of the found boxed trait object.
578                        diag.multipart_suggestion(
579                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` implements `{1}` so you can box it to coerce to the trait object `{2}`",
                values.expected, tcx.item_name(def_id), values.found))
    })format!(
580                                "`{}` implements `{}` so you can box it to coerce to the trait \
581                                 object `{}`",
582                                values.expected,
583                                tcx.item_name(def_id),
584                                values.found,
585                            ),
586                            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(then.span.shrink_to_lo(), "Box::new(".to_string()),
                (then.span.shrink_to_hi(), ")".to_string())]))vec![
587                                (then.span.shrink_to_lo(), "Box::new(".to_string()),
588                                (then.span.shrink_to_hi(), ")".to_string()),
589                            ],
590                            MachineApplicable,
591                        );
592                    }
593                    _ => {}
594                }
595                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs:595",
                        "rustc_trait_selection::error_reporting::infer::note_and_explain",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs"),
                        ::tracing_core::__macro_support::Option::Some(595u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::infer::note_and_explain"),
                        ::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!("note_and_explain_type_err expected={0:?} ({1:?}) found={2:?} ({3:?})",
                                                    values.expected, values.expected.kind(), values.found,
                                                    values.found.kind()) as &dyn Value))])
            });
    } else { ; }
};debug!(
596                    "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})",
597                    values.expected,
598                    values.expected.kind(),
599                    values.found,
600                    values.found.kind(),
601                );
602            }
603            TypeError::CyclicTy(ty) => {
604                // Watch out for various cases of cyclic types and try to explain.
605                if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() {
606                    diag.note(
607                        "closures cannot capture themselves or take themselves as argument;\n\
608                         this error may be the result of a recent compiler bug-fix,\n\
609                         see issue #46062 <https://github.com/rust-lang/rust/issues/46062>\n\
610                         for more information",
611                    );
612                }
613            }
614            TypeError::TargetFeatureCast(def_id) => {
615                let target_spans = {
    {
        'done:
            {
            for i in ::rustc_hir::attrs::HasAttrs::get_attrs(def_id, &tcx) {
                #[allow(unused_imports)]
                use rustc_hir::attrs::AttributeKind::*;
                let i: &rustc_hir::Attribute = i;
                match i {
                    rustc_hir::Attribute::Parsed(TargetFeature {
                        attr_span: span, was_forced: false, .. }) => {
                        break 'done Some(*span);
                    }
                    rustc_hir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(tcx, def_id, TargetFeature{attr_span: span, was_forced: false, ..} => *span);
616                diag.note(
617                    "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
618                );
619                diag.span_labels(target_spans, "`#[target_feature]` added here");
620            }
621            _ => {}
622        }
623    }
624
625    fn suggest_constraint(
626        &self,
627        diag: &mut Diag<'_>,
628        msg: impl Fn() -> String,
629        body_owner_def_id: Option<DefId>,
630        proj_ty: ty::AliasTy<'tcx>,
631        ty: Ty<'tcx>,
632    ) -> bool {
633        let tcx = self.tcx;
634        // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
635        if !#[allow(non_exhaustive_omitted_patterns)] match proj_ty.kind {
    ty::AliasTyKind::Projection { .. } => true,
    _ => false,
}matches!(proj_ty.kind, ty::AliasTyKind::Projection { .. }) {
636            return false;
637        }
638        let Some(body_owner_def_id) = body_owner_def_id else {
639            return false;
640        };
641        let assoc = tcx.associated_item(proj_ty.kind.def_id());
642        let (trait_ref, assoc_args) = proj_ty.trait_ref_and_own_args(tcx);
643        let Some(item) = tcx.hir_get_if_local(body_owner_def_id) else {
644            return false;
645        };
646        let Some(hir_generics) = item.generics() else {
647            return false;
648        };
649        // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
650        // This will also work for `impl Trait`.
651        let ty::Param(param_ty) = *proj_ty.self_ty().kind() else {
652            return false;
653        };
654        let generics = tcx.generics_of(body_owner_def_id);
655        let def_id = generics.type_param(param_ty, tcx).def_id;
656        let Some(def_id) = def_id.as_local() else {
657            return false;
658        };
659
660        // First look in the `where` clause, as this might be
661        // `fn foo<T>(x: T) where T: Trait`.
662        for pred in hir_generics.bounds_for_param(def_id) {
663            if self.constrain_generic_bound_associated_type_structured_suggestion(
664                diag,
665                trait_ref,
666                pred.bounds,
667                assoc,
668                assoc_args,
669                ty,
670                &msg,
671                false,
672            ) {
673                return true;
674            }
675        }
676        if (param_ty.index as usize) >= generics.parent_count {
677            // The param comes from the current item, do not look at the parent. (#117209)
678            return false;
679        }
680        // If associated item, look to constrain the params of the trait/impl.
681        let hir_id = match item {
682            hir::Node::ImplItem(item) => item.hir_id(),
683            hir::Node::TraitItem(item) => item.hir_id(),
684            _ => return false,
685        };
686        let parent = tcx.hir_get_parent_item(hir_id).def_id;
687        self.suggest_constraint(diag, msg, Some(parent.into()), proj_ty, ty)
688    }
689
690    /// An associated type was expected and a different type was found.
691    ///
692    /// We perform a few different checks to see what we can suggest:
693    ///
694    ///  - In the current item, look for associated functions that return the expected type and
695    ///    suggest calling them. (Not a structured suggestion.)
696    ///  - If any of the item's generic bounds can be constrained, we suggest constraining the
697    ///    associated type to the found type.
698    ///  - If the associated type has a default type and was expected inside of a `trait`, we
699    ///    mention that this is disallowed.
700    ///  - If all other things fail, and the error is not because of a mismatch between the `trait`
701    ///    and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc
702    ///    fn that returns the type.
703    fn expected_projection(
704        &self,
705        diag: &mut Diag<'_>,
706        proj_ty: ty::AliasTy<'tcx>,
707        values: ExpectedFound<Ty<'tcx>>,
708        body_owner_def_id: Option<DefId>,
709        cause_code: &ObligationCauseCode<'_>,
710    ) {
711        let tcx = self.tcx;
712
713        // Don't suggest constraining a projection to something containing itself
714        if self
715            .tcx
716            .erase_and_anonymize_regions(values.found)
717            .contains(self.tcx.erase_and_anonymize_regions(values.expected))
718        {
719            return;
720        }
721
722        let msg = || {
723            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider constraining the associated type `{0}` to `{1}`",
                values.expected, values.found))
    })format!(
724                "consider constraining the associated type `{}` to `{}`",
725                values.expected, values.found
726            )
727        };
728
729        let body_owner = body_owner_def_id.and_then(|id| tcx.hir_get_if_local(id));
730        let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
731
732        // We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
733        let callable_scope = #[allow(non_exhaustive_omitted_patterns)] match body_owner {
    Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { .. }, .. }) |
        hir::Node::TraitItem(hir::TraitItem {
        kind: hir::TraitItemKind::Fn(..), .. }) |
        hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..),
        .. })) => true,
    _ => false,
}matches!(
734            body_owner,
735            Some(
736                hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { .. }, .. })
737                    | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
738                    | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
739            )
740        );
741        let impl_comparison = #[allow(non_exhaustive_omitted_patterns)] match cause_code {
    ObligationCauseCode::CompareImplItem { .. } => true,
    _ => false,
}matches!(cause_code, ObligationCauseCode::CompareImplItem { .. });
742        if impl_comparison {
743            // We do not want to suggest calling functions when the reason of the
744            // type error is a comparison of an `impl` with its `trait`.
745        } else {
746            let point_at_assoc_fn = if callable_scope
747                && self.point_at_methods_that_satisfy_associated_type(
748                    diag,
749                    tcx.parent(proj_ty.kind.def_id()),
750                    current_method_ident,
751                    proj_ty.kind.def_id(),
752                    values.expected,
753                ) {
754                // If we find a suitable associated function that returns the expected type, we
755                // don't want the more general suggestion later in this method about "consider
756                // constraining the associated type or calling a method that returns the associated
757                // type".
758                true
759            } else {
760                false
761            };
762            // Possibly suggest constraining the associated type to conform to the
763            // found type.
764            if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found)
765                || point_at_assoc_fn
766            {
767                return;
768            }
769        }
770
771        self.suggest_constraining_opaque_associated_type(diag, &msg, proj_ty, values.found);
772
773        if self.point_at_associated_type(diag, body_owner_def_id, values.found) {
774            return;
775        }
776
777        if !impl_comparison {
778            // Generic suggestion when we can't be more specific.
779            if callable_scope {
780                diag.help(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} or calling a method that returns `{1}`",
                msg(), values.expected))
    })format!(
781                    "{} or calling a method that returns `{}`",
782                    msg(),
783                    values.expected
784                ));
785            } else {
786                diag.help(msg());
787            }
788            diag.note(
789                "for more information, visit \
790                 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
791            );
792        }
793        if diag.code.is_some_and(|code| tcx.sess.teach(code)) {
794            diag.help(
795                "given an associated type `T` and a method `foo`:
796```
797trait Trait {
798type T;
799fn foo(&self) -> Self::T;
800}
801```
802the only way of implementing method `foo` is to constrain `T` with an explicit associated type:
803```
804impl Trait for X {
805type T = String;
806fn foo(&self) -> Self::T { String::new() }
807}
808```",
809            );
810        }
811    }
812
813    /// When the expected `impl Trait` is not defined in the current item, it will come from
814    /// a return type. This can occur when dealing with `TryStream` (#71035).
815    fn suggest_constraining_opaque_associated_type(
816        &self,
817        diag: &mut Diag<'_>,
818        msg: impl Fn() -> String,
819        proj_ty: ty::AliasTy<'tcx>,
820        ty: Ty<'tcx>,
821    ) -> bool {
822        let tcx = self.tcx;
823
824        let assoc = tcx.associated_item(proj_ty.kind.def_id());
825        if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }) =
826            *proj_ty.self_ty().kind()
827        {
828            let opaque_local_def_id = def_id.as_local();
829            let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
830                tcx.hir_expect_opaque_ty(opaque_local_def_id)
831            } else {
832                return false;
833            };
834
835            let (trait_ref, assoc_args) = proj_ty.trait_ref_and_own_args(tcx);
836
837            self.constrain_generic_bound_associated_type_structured_suggestion(
838                diag,
839                trait_ref,
840                opaque_hir_ty.bounds,
841                assoc,
842                assoc_args,
843                ty,
844                msg,
845                true,
846            )
847        } else {
848            false
849        }
850    }
851
852    fn point_at_methods_that_satisfy_associated_type(
853        &self,
854        diag: &mut Diag<'_>,
855        assoc_container_id: DefId,
856        current_method_ident: Option<Symbol>,
857        proj_ty_item_def_id: DefId,
858        expected: Ty<'tcx>,
859    ) -> bool {
860        let tcx = self.tcx;
861
862        let items = tcx.associated_items(assoc_container_id);
863        // Find all the methods in the trait that could be called to construct the
864        // expected associated type.
865        // FIXME: consider suggesting the use of associated `const`s.
866        let methods: Vec<(Span, String)> = items
867            .in_definition_order()
868            .filter(|item| {
869                item.is_fn()
870                    && Some(item.name()) != current_method_ident
871                    && !tcx.is_doc_hidden(item.def_id)
872            })
873            .filter_map(|item| {
874                let method = tcx.fn_sig(item.def_id).instantiate_identity().skip_norm_wip();
875                match *method.output().skip_binder().kind() {
876                    ty::Alias(ty::AliasTy {
877                        kind: ty::Projection { def_id: item_def_id }, ..
878                    }) if item_def_id == proj_ty_item_def_id => Some((
879                        tcx.def_span(item.def_id),
880                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider calling `{0}`",
                tcx.def_path_str(item.def_id)))
    })format!("consider calling `{}`", tcx.def_path_str(item.def_id)),
881                    )),
882                    _ => None,
883                }
884            })
885            .collect();
886        if !methods.is_empty() {
887            // Use a single `help:` to show all the methods in the trait that can
888            // be used to construct the expected associated type.
889            let mut span: MultiSpan =
890                methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into();
891            let msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} method{1} {2} available that return{3} `{4}`",
                if methods.len() == 1 { "a" } else { "some" },
                if methods.len() == 1 { "" } else { "s" },
                if methods.len() == 1 { "is" } else { "are" },
                if methods.len() == 1 { "s" } else { "" }, expected))
    })format!(
892                "{some} method{s} {are} available that return{r} `{ty}`",
893                some = if methods.len() == 1 { "a" } else { "some" },
894                s = pluralize!(methods.len()),
895                are = pluralize!("is", methods.len()),
896                r = if methods.len() == 1 { "s" } else { "" },
897                ty = expected
898            );
899            for (sp, label) in methods.into_iter() {
900                span.push_span_label(sp, label);
901            }
902            diag.span_help(span, msg);
903            return true;
904        }
905        false
906    }
907
908    fn point_at_associated_type(
909        &self,
910        diag: &mut Diag<'_>,
911        body_owner_def_id: Option<DefId>,
912        found: Ty<'tcx>,
913    ) -> bool {
914        let tcx = self.tcx;
915
916        let Some(def_id) = body_owner_def_id.and_then(|id| id.as_local()) else {
917            return false;
918        };
919
920        // When `body_owner` is an `impl` or `trait` item, look in its associated types for
921        // `expected` and point at it.
922        let hir_id = tcx.local_def_id_to_hir_id(def_id);
923        let parent_id = tcx.hir_get_parent_item(hir_id);
924        let item = tcx.hir_node_by_def_id(parent_id.def_id);
925
926        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs:926",
                        "rustc_trait_selection::error_reporting::infer::note_and_explain",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs"),
                        ::tracing_core::__macro_support::Option::Some(926u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::infer::note_and_explain"),
                        ::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!("expected_projection parent item {0:?}",
                                                    item) as &dyn Value))])
            });
    } else { ; }
};debug!("expected_projection parent item {:?}", item);
927
928        let param_env = tcx.param_env(def_id);
929
930        if let DefKind::Trait | DefKind::Impl { .. } = tcx.def_kind(parent_id) {
931            let assoc_items = tcx.associated_items(parent_id);
932            // FIXME: account for `#![feature(specialization)]`
933            for assoc_item in assoc_items.in_definition_order() {
934                if assoc_item.is_type()
935                    // FIXME: account for returning some type in a trait fn impl that has
936                    // an assoc type as a return type (#72076).
937                    && let hir::Defaultness::Default { has_value: true } = assoc_item.defaultness(tcx)
938                    && let assoc_ty = tcx.type_of(assoc_item.def_id).instantiate_identity().skip_norm_wip()
939                    && self.infcx.can_eq(param_env, assoc_ty, found)
940                {
941                    let msg = match assoc_item.container {
942                        ty::AssocContainer::Trait => {
943                            "associated type defaults can't be assumed inside the \
944                                            trait defining them"
945                        }
946                        ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
947                            "associated type is `default` and may be overridden"
948                        }
949                    };
950                    diag.span_label(tcx.def_span(assoc_item.def_id), msg);
951                    return true;
952                }
953            }
954        }
955
956        false
957    }
958
959    /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
960    /// requirement, provide a structured suggestion to constrain it to a given type `ty`.
961    ///
962    /// `is_bound_surely_present` indicates whether we know the bound we're looking for is
963    /// inside `bounds`. If that's the case then we can consider `bounds` containing only one
964    /// trait bound as the one we're looking for. This can help in cases where the associated
965    /// type is defined on a supertrait of the one present in the bounds.
966    fn constrain_generic_bound_associated_type_structured_suggestion(
967        &self,
968        diag: &mut Diag<'_>,
969        trait_ref: ty::TraitRef<'tcx>,
970        bounds: hir::GenericBounds<'_>,
971        assoc: ty::AssocItem,
972        assoc_args: &[ty::GenericArg<'tcx>],
973        ty: Ty<'tcx>,
974        msg: impl Fn() -> String,
975        is_bound_surely_present: bool,
976    ) -> bool {
977        // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
978
979        let trait_bounds = bounds.iter().filter_map(|bound| match bound {
980            hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifiers::NONE => {
981                Some(ptr)
982            }
983            _ => None,
984        });
985
986        let matching_trait_bounds = trait_bounds
987            .clone()
988            .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
989            .collect::<Vec<_>>();
990
991        let span = match &matching_trait_bounds[..] {
992            &[ptr] => ptr.span,
993            &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
994                &[ptr] => ptr.span,
995                _ => return false,
996            },
997            _ => return false,
998        };
999
1000        self.constrain_associated_type_structured_suggestion(diag, span, assoc, assoc_args, ty, msg)
1001    }
1002
1003    /// Given a span corresponding to a bound, provide a structured suggestion to set an
1004    /// associated type to a given type `ty`.
1005    fn constrain_associated_type_structured_suggestion(
1006        &self,
1007        diag: &mut Diag<'_>,
1008        span: Span,
1009        assoc: ty::AssocItem,
1010        assoc_args: &[ty::GenericArg<'tcx>],
1011        ty: Ty<'tcx>,
1012        msg: impl Fn() -> String,
1013    ) -> bool {
1014        let tcx = self.tcx;
1015
1016        if let Ok(has_params) =
1017            tcx.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>'))
1018        {
1019            let (span, sugg) = if has_params {
1020                let pos = span.hi() - BytePos(1);
1021                let span = Span::new(pos, pos, span.ctxt(), span.parent());
1022                (span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(", {0} = {1}", assoc.ident(tcx),
                ty))
    })format!(", {} = {}", assoc.ident(tcx), ty))
1023            } else {
1024                let item_args = self.format_generic_args(assoc_args);
1025                (span.shrink_to_hi(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("<{0}{1} = {2}>", assoc.ident(tcx),
                item_args, ty))
    })format!("<{}{} = {}>", assoc.ident(tcx), item_args, ty))
1026            };
1027            diag.span_suggestion_verbose(span, msg(), sugg, MaybeIncorrect);
1028            return true;
1029        }
1030        false
1031    }
1032
1033    pub fn format_generic_args(&self, args: &[ty::GenericArg<'tcx>]) -> String {
1034        FmtPrinter::print_string(self.tcx, hir::def::Namespace::TypeNS, |p| {
1035            p.print_path_with_generic_args(|_| Ok(()), args)
1036        })
1037        .expect("could not write to `String`.")
1038    }
1039}