Skip to main content

rustc_trait_selection/error_reporting/infer/nice_region_error/
placeholder_error.rs

1use std::fmt;
2
3use rustc_data_structures::intern::Interned;
4use rustc_errors::{Applicability, Diag, IntoDiagArg};
5use rustc_hir as hir;
6use rustc_hir::def::Namespace;
7use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
8use rustc_middle::bug;
9use rustc_middle::ty::error::ExpectedFound;
10use rustc_middle::ty::print::{FmtPrinter, Print, PrintTraitRefExt as _, RegionHighlightMode};
11use rustc_middle::ty::{self, GenericArgsRef, IsSuggestable, RePlaceholder, Region, TyCtxt};
12use tracing::{debug, instrument};
13
14use crate::diagnostics::{
15    ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,
16    TraitPlaceholderMismatch, TyOrSig,
17};
18use crate::error_reporting::infer::nice_region_error::NiceRegionError;
19use crate::infer::{RegionResolutionError, SubregionOrigin, TypeTrace, ValuePairs};
20use crate::traits::{ObligationCause, ObligationCauseCode};
21
22#[derive(#[automatically_derived]
impl<'tcx, T: ::core::marker::Copy> ::core::marker::Copy for
    Highlighted<'tcx, T> {
}Copy, #[automatically_derived]
impl<'tcx, T: ::core::clone::Clone> ::core::clone::Clone for
    Highlighted<'tcx, T> {
    #[inline]
    fn clone(&self) -> Highlighted<'tcx, T> {
        Highlighted {
            tcx: ::core::clone::Clone::clone(&self.tcx),
            highlight: ::core::clone::Clone::clone(&self.highlight),
            value: ::core::clone::Clone::clone(&self.value),
            ns: ::core::clone::Clone::clone(&self.ns),
        }
    }
}Clone)]
23pub(crate) struct Highlighted<'tcx, T> {
24    pub tcx: TyCtxt<'tcx>,
25    pub highlight: RegionHighlightMode<'tcx>,
26    pub value: T,
27    pub ns: Namespace,
28}
29
30impl<'tcx, T> IntoDiagArg for Highlighted<'tcx, T>
31where
32    T: for<'a> Print<FmtPrinter<'a, 'tcx>>,
33{
34    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
35        rustc_errors::DiagArgValue::Str(self.to_string().into())
36    }
37}
38
39impl<'tcx, T> Highlighted<'tcx, T> {
40    fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
41        Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value), ns: self.ns }
42    }
43}
44
45impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
46where
47    T: for<'a> Print<FmtPrinter<'a, 'tcx>>,
48{
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        let mut p = ty::print::FmtPrinter::new(self.tcx, self.ns);
51        p.region_highlight_mode = self.highlight;
52
53        self.value.print(&mut p)?;
54        f.write_str(&p.into_buffer())
55    }
56}
57
58impl<'tcx> NiceRegionError<'_, 'tcx> {
59    /// When given a `ConcreteFailure` for a function with arguments containing a named region and
60    /// an anonymous region, emit a descriptive diagnostic error.
61    pub(super) fn try_report_placeholder_conflict(&self) -> Option<Diag<'tcx>> {
62        match &self.error {
63            ///////////////////////////////////////////////////////////////////////////
64            // NB. The ordering of cases in this match is very
65            // sensitive, because we are often matching against
66            // specific cases and then using an `_` to match all
67            // others.
68
69            ///////////////////////////////////////////////////////////////////////////
70            // Check for errors from comparing trait failures -- first
71            // with two placeholders, then with one.
72            Some(RegionResolutionError::SubSupConflict(
73                vid,
74                _,
75                SubregionOrigin::Subtype(TypeTrace { cause, values }),
76                sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
77                _,
78                sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
79                _,
80            )) => self.try_report_trait_placeholder_mismatch(
81                Some(ty::Region::new_var(self.tcx(), *vid)),
82                cause,
83                Some(*sub_placeholder),
84                Some(*sup_placeholder),
85                values,
86            ),
87
88            Some(RegionResolutionError::SubSupConflict(
89                vid,
90                _,
91                SubregionOrigin::Subtype(TypeTrace { cause, values }),
92                sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
93                _,
94                _,
95                _,
96            )) => self.try_report_trait_placeholder_mismatch(
97                Some(ty::Region::new_var(self.tcx(), *vid)),
98                cause,
99                Some(*sub_placeholder),
100                None,
101                values,
102            ),
103
104            Some(RegionResolutionError::SubSupConflict(
105                vid,
106                _,
107                SubregionOrigin::Subtype(TypeTrace { cause, values }),
108                _,
109                _,
110                sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
111                _,
112            )) => self.try_report_trait_placeholder_mismatch(
113                Some(ty::Region::new_var(self.tcx(), *vid)),
114                cause,
115                None,
116                Some(*sup_placeholder),
117                values,
118            ),
119
120            Some(RegionResolutionError::SubSupConflict(
121                vid,
122                _,
123                _,
124                _,
125                SubregionOrigin::Subtype(TypeTrace { cause, values }),
126                sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
127                _,
128            )) => self.try_report_trait_placeholder_mismatch(
129                Some(ty::Region::new_var(self.tcx(), *vid)),
130                cause,
131                None,
132                Some(*sup_placeholder),
133                values,
134            ),
135
136            Some(RegionResolutionError::UpperBoundUniverseConflict(
137                vid,
138                _,
139                _,
140                SubregionOrigin::Subtype(TypeTrace { cause, values }),
141                sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
142            )) => self.try_report_trait_placeholder_mismatch(
143                Some(ty::Region::new_var(self.tcx(), *vid)),
144                cause,
145                None,
146                Some(*sup_placeholder),
147                values,
148            ),
149
150            Some(RegionResolutionError::ConcreteFailure(
151                SubregionOrigin::Subtype(TypeTrace { cause, values }),
152                sub_region @ Region(Interned(RePlaceholder(_), _)),
153                sup_region @ Region(Interned(RePlaceholder(_), _)),
154            )) => self.try_report_trait_placeholder_mismatch(
155                None,
156                cause,
157                Some(*sub_region),
158                Some(*sup_region),
159                values,
160            ),
161
162            Some(RegionResolutionError::ConcreteFailure(
163                SubregionOrigin::Subtype(TypeTrace { cause, values }),
164                sub_region @ Region(Interned(RePlaceholder(_), _)),
165                sup_region,
166            )) => self.try_report_trait_placeholder_mismatch(
167                (!sup_region.is_named(self.tcx())).then_some(*sup_region),
168                cause,
169                Some(*sub_region),
170                None,
171                values,
172            ),
173
174            Some(RegionResolutionError::ConcreteFailure(
175                SubregionOrigin::Subtype(TypeTrace { cause, values }),
176                sub_region,
177                sup_region @ Region(Interned(RePlaceholder(_), _)),
178            )) => self.try_report_trait_placeholder_mismatch(
179                (!sub_region.is_named(self.tcx())).then_some(*sub_region),
180                cause,
181                None,
182                Some(*sup_region),
183                values,
184            ),
185
186            _ => None,
187        }
188    }
189
190    fn try_report_trait_placeholder_mismatch(
191        &self,
192        vid: Option<Region<'tcx>>,
193        cause: &ObligationCause<'tcx>,
194        sub_placeholder: Option<Region<'tcx>>,
195        sup_placeholder: Option<Region<'tcx>>,
196        value_pairs: &ValuePairs<'tcx>,
197    ) -> Option<Diag<'tcx>> {
198        let (expected_args, found_args, trait_def_id) = match value_pairs {
199            ValuePairs::TraitRefs(ExpectedFound { expected, found })
200                if expected.def_id == found.def_id =>
201            {
202                // It's possible that the placeholders come from a binder
203                // outside of this value pair. Use `no_bound_vars` as a
204                // simple heuristic for that.
205                (expected.args, found.args, expected.def_id)
206            }
207            _ => return None,
208        };
209
210        Some(self.report_trait_placeholder_mismatch(
211            vid,
212            cause,
213            sub_placeholder,
214            sup_placeholder,
215            trait_def_id,
216            expected_args,
217            found_args,
218        ))
219    }
220
221    // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
222    //   --> /home/nmatsakis/tmp/foo.rs:12:5
223    //    |
224    // 12 |     all::<&'static u32>();
225    //    |     ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
226    //    |
227    //    = note: Due to a where-clause on the function `all`,
228    //    = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
229    //    = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
230    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("report_trait_placeholder_mismatch",
                                    "rustc_trait_selection::error_reporting::infer::nice_region_error::placeholder_error",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs"),
                                    ::tracing_core::__macro_support::Option::Some(230u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::infer::nice_region_error::placeholder_error"),
                                    ::tracing_core::field::FieldSet::new(&["vid", "cause",
                                                    "sub_placeholder", "sup_placeholder", "trait_def_id",
                                                    "expected_args", "actual_args"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&vid)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&cause)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&sub_placeholder)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&sup_placeholder)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&trait_def_id)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expected_args)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&actual_args)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: Diag<'tcx> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let span = cause.span;
            let (leading_ellipsis, satisfy_span, where_span, dup_span,
                    def_id) =
                if let ObligationCauseCode::WhereClause(def_id, span) |
                            ObligationCauseCode::WhereClauseInExpr(def_id, span, ..) =
                            *cause.code() && def_id != CRATE_DEF_ID.to_def_id() {
                    (true, Some(span), Some(self.tcx().def_span(def_id)), None,
                        self.tcx().def_path_str(def_id))
                } else { (false, None, None, Some(span), String::new()) };
            let expected_trait_ref =
                self.cx.resolve_vars_if_possible(ty::TraitRef::new_from_args(self.cx.tcx,
                        trait_def_id, expected_args));
            let actual_trait_ref =
                self.cx.resolve_vars_if_possible(ty::TraitRef::new_from_args(self.cx.tcx,
                        trait_def_id, actual_args));
            let mut counter = 0;
            let mut has_sub = None;
            let mut has_sup = None;
            let mut actual_has_vid = None;
            let mut expected_has_vid = None;
            self.tcx().for_each_free_region(&expected_trait_ref,
                |r|
                    {
                        if Some(r) == sub_placeholder && has_sub.is_none() {
                            has_sub = Some(counter);
                            counter += 1;
                        } else if Some(r) == sup_placeholder && has_sup.is_none() {
                            has_sup = Some(counter);
                            counter += 1;
                        }
                        if Some(r) == vid && expected_has_vid.is_none() {
                            expected_has_vid = Some(counter);
                            counter += 1;
                        }
                    });
            self.tcx().for_each_free_region(&actual_trait_ref,
                |r|
                    {
                        if Some(r) == vid && actual_has_vid.is_none() {
                            actual_has_vid = Some(counter);
                            counter += 1;
                        }
                    });
            let actual_self_ty_has_vid =
                self.tcx().any_free_region_meets(&actual_trait_ref.self_ty(),
                    |r| Some(r) == vid);
            let expected_self_ty_has_vid =
                self.tcx().any_free_region_meets(&expected_trait_ref.self_ty(),
                    |r| Some(r) == vid);
            let any_self_ty_has_vid =
                actual_self_ty_has_vid || expected_self_ty_has_vid;
            {
                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/nice_region_error/placeholder_error.rs:313",
                                    "rustc_trait_selection::error_reporting::infer::nice_region_error::placeholder_error",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs"),
                                    ::tracing_core::__macro_support::Option::Some(313u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::infer::nice_region_error::placeholder_error"),
                                    ::tracing_core::field::FieldSet::new(&["actual_has_vid",
                                                    "expected_has_vid", "has_sub", "has_sup",
                                                    "actual_self_ty_has_vid", "expected_self_ty_has_vid"],
                                        ::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(&debug(&actual_has_vid)
                                                        as &dyn Value)),
                                            (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&debug(&expected_has_vid)
                                                        as &dyn Value)),
                                            (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&debug(&has_sub) as
                                                        &dyn Value)),
                                            (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&debug(&has_sup) as
                                                        &dyn Value)),
                                            (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&debug(&actual_self_ty_has_vid)
                                                        as &dyn Value)),
                                            (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&debug(&expected_self_ty_has_vid)
                                                        as &dyn Value))])
                        });
                } else { ; }
            };
            let actual_impl_expl_notes =
                self.explain_actual_impl_that_was_found(sub_placeholder,
                    sup_placeholder, has_sub, has_sup, expected_trait_ref,
                    actual_trait_ref, vid, expected_has_vid, actual_has_vid,
                    any_self_ty_has_vid, leading_ellipsis);
            let mut err =
                self.tcx().dcx().create_err(TraitPlaceholderMismatch {
                        span,
                        satisfy_span,
                        where_span,
                        dup_span,
                        def_id,
                        trait_def_id: self.tcx().def_path_str(trait_def_id),
                        actual_impl_expl_notes,
                    });
            let mut current_code = cause.code();
            let mut coroutine_def_id = None;
            loop {
                match current_code {
                    ObligationCauseCode::MatchImpl(inner_cause, _) => {
                        current_code = inner_cause.code();
                    }
                    ObligationCauseCode::BuiltinDerived(derived) => {
                        let self_ty =
                            derived.parent_trait_pred.skip_binder().self_ty();
                        if let ty::Coroutine(def_id, _) |
                                ty::CoroutineWitness(def_id, _) = self_ty.kind() {
                            coroutine_def_id = Some(*def_id);
                            break;
                        }
                        current_code = &derived.parent_code;
                    }
                    _ => break,
                }
            }
            if let Some(def_id) = coroutine_def_id {
                if self.tcx().trait_is_auto(trait_def_id) {
                    let c_span = self.tcx().def_span(def_id);
                    let descr = self.tcx().def_descr(def_id);
                    let trait_name = self.tcx().def_path_str(trait_def_id);
                    err.span_label(c_span,
                        ::alloc::__export::must_use({
                                ::alloc::fmt::format(format_args!("this {0} captures a value whose type is not `{1}`",
                                        descr, trait_name))
                            }));
                }
            }
            if self.tcx().is_fn_trait(trait_def_id) {
                let actual_self_ty =
                    self.cx.resolve_vars_if_possible(ty::TraitRef::new_from_args(self.cx.tcx,
                                trait_def_id, actual_args).self_ty());
                if let ty::Closure(closure_def_id, _) = *actual_self_ty.kind()
                            && let Some(local_def_id) = closure_def_id.as_local() &&
                        let hir::Node::Expr(hir::Expr {
                            kind: hir::ExprKind::Closure(closure), .. }) =
                            self.tcx().hir_node_by_def_id(local_def_id) {
                    let body = self.tcx().hir_body(closure.body);
                    let expected_input_tys = expected_args.type_at(1);
                    if let ty::Tuple(input_tys) = *expected_input_tys.kind() {
                        let suggestions: Vec<_> =
                            body.params.iter().zip(input_tys.iter()).filter_map(|(param,
                                            ty)|
                                        {
                                            if param.ty_span == param.pat.span &&
                                                    ty.is_suggestable(self.tcx(), false) {
                                                Some((param.pat.span.shrink_to_hi(),
                                                        ::alloc::__export::must_use({
                                                                ::alloc::fmt::format(format_args!(": {0}", ty))
                                                            })))
                                            } else { None }
                                        }).collect();
                        if !suggestions.is_empty() {
                            let msg =
                                if suggestions.len() == 1 {
                                    "consider adding an explicit type annotation to the closure's argument"
                                } else {
                                    "consider adding explicit type annotations to the closure's arguments"
                                };
                            err.multipart_suggestion(msg, suggestions,
                                Applicability::MaybeIncorrect);
                        }
                    }
                }
            }
            err
        }
    }
}#[instrument(level = "debug", skip(self))]
231    fn report_trait_placeholder_mismatch(
232        &self,
233        vid: Option<Region<'tcx>>,
234        cause: &ObligationCause<'tcx>,
235        sub_placeholder: Option<Region<'tcx>>,
236        sup_placeholder: Option<Region<'tcx>>,
237        trait_def_id: DefId,
238        expected_args: GenericArgsRef<'tcx>,
239        actual_args: GenericArgsRef<'tcx>,
240    ) -> Diag<'tcx> {
241        let span = cause.span;
242
243        let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
244            if let ObligationCauseCode::WhereClause(def_id, span)
245            | ObligationCauseCode::WhereClauseInExpr(def_id, span, ..) = *cause.code()
246                && def_id != CRATE_DEF_ID.to_def_id()
247            {
248                (
249                    true,
250                    Some(span),
251                    Some(self.tcx().def_span(def_id)),
252                    None,
253                    self.tcx().def_path_str(def_id),
254                )
255            } else {
256                (false, None, None, Some(span), String::new())
257            };
258
259        let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new_from_args(
260            self.cx.tcx,
261            trait_def_id,
262            expected_args,
263        ));
264        let actual_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new_from_args(
265            self.cx.tcx,
266            trait_def_id,
267            actual_args,
268        ));
269
270        // Search the expected and actual trait references to see (a)
271        // whether the sub/sup placeholders appear in them (sometimes
272        // you have a trait ref like `T: Foo<fn(&u8)>`, where the
273        // placeholder was created as part of an inner type) and (b)
274        // whether the inference variable appears. In each case,
275        // assign a counter value in each case if so.
276        let mut counter = 0;
277        let mut has_sub = None;
278        let mut has_sup = None;
279
280        let mut actual_has_vid = None;
281        let mut expected_has_vid = None;
282
283        self.tcx().for_each_free_region(&expected_trait_ref, |r| {
284            if Some(r) == sub_placeholder && has_sub.is_none() {
285                has_sub = Some(counter);
286                counter += 1;
287            } else if Some(r) == sup_placeholder && has_sup.is_none() {
288                has_sup = Some(counter);
289                counter += 1;
290            }
291
292            if Some(r) == vid && expected_has_vid.is_none() {
293                expected_has_vid = Some(counter);
294                counter += 1;
295            }
296        });
297
298        self.tcx().for_each_free_region(&actual_trait_ref, |r| {
299            if Some(r) == vid && actual_has_vid.is_none() {
300                actual_has_vid = Some(counter);
301                counter += 1;
302            }
303        });
304
305        let actual_self_ty_has_vid =
306            self.tcx().any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);
307
308        let expected_self_ty_has_vid =
309            self.tcx().any_free_region_meets(&expected_trait_ref.self_ty(), |r| Some(r) == vid);
310
311        let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;
312
313        debug!(
314            ?actual_has_vid,
315            ?expected_has_vid,
316            ?has_sub,
317            ?has_sup,
318            ?actual_self_ty_has_vid,
319            ?expected_self_ty_has_vid,
320        );
321
322        let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(
323            sub_placeholder,
324            sup_placeholder,
325            has_sub,
326            has_sup,
327            expected_trait_ref,
328            actual_trait_ref,
329            vid,
330            expected_has_vid,
331            actual_has_vid,
332            any_self_ty_has_vid,
333            leading_ellipsis,
334        );
335
336        let mut err = self.tcx().dcx().create_err(TraitPlaceholderMismatch {
337            span,
338            satisfy_span,
339            where_span,
340            dup_span,
341            def_id,
342            trait_def_id: self.tcx().def_path_str(trait_def_id),
343            actual_impl_expl_notes,
344        });
345
346        let mut current_code = cause.code();
347        let mut coroutine_def_id = None;
348
349        loop {
350            match current_code {
351                ObligationCauseCode::MatchImpl(inner_cause, _) => {
352                    current_code = inner_cause.code();
353                }
354                ObligationCauseCode::BuiltinDerived(derived) => {
355                    let self_ty = derived.parent_trait_pred.skip_binder().self_ty();
356
357                    if let ty::Coroutine(def_id, _) | ty::CoroutineWitness(def_id, _) =
358                        self_ty.kind()
359                    {
360                        coroutine_def_id = Some(*def_id);
361                        break;
362                    }
363
364                    current_code = &derived.parent_code;
365                }
366                _ => break,
367            }
368        }
369
370        if let Some(def_id) = coroutine_def_id {
371            if self.tcx().trait_is_auto(trait_def_id) {
372                let c_span = self.tcx().def_span(def_id);
373                let descr = self.tcx().def_descr(def_id);
374                let trait_name = self.tcx().def_path_str(trait_def_id);
375
376                err.span_label(
377                    c_span,
378                    format!("this {descr} captures a value whose type is not `{trait_name}`"),
379                );
380            }
381        }
382
383        // When the mismatched trait is an Fn-trait and the self type is a closure with
384        // unannotated parameters, suggest adding explicit type annotations. This turns
385        // the confusing lifetime-generality error into an actionable hint, e.g.:
386        //   |buf|  →  |buf: &mut [u8]|
387        if self.tcx().is_fn_trait(trait_def_id) {
388            let actual_self_ty = self.cx.resolve_vars_if_possible(
389                ty::TraitRef::new_from_args(self.cx.tcx, trait_def_id, actual_args).self_ty(),
390            );
391            if let ty::Closure(closure_def_id, _) = *actual_self_ty.kind()
392                && let Some(local_def_id) = closure_def_id.as_local()
393                && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) =
394                    self.tcx().hir_node_by_def_id(local_def_id)
395            {
396                let body = self.tcx().hir_body(closure.body);
397                // For Fn traits, args[1] is the tupled input types (e.g. `(&mut [u8],)`).
398                let expected_input_tys = expected_args.type_at(1);
399                if let ty::Tuple(input_tys) = *expected_input_tys.kind() {
400                    let suggestions: Vec<_> = body
401                        .params
402                        .iter()
403                        .zip(input_tys.iter())
404                        .filter_map(|(param, ty)| {
405                            // ty_span == pat.span means no explicit type annotation was written.
406                            if param.ty_span == param.pat.span
407                                && ty.is_suggestable(self.tcx(), false)
408                            {
409                                Some((param.pat.span.shrink_to_hi(), format!(": {ty}")))
410                            } else {
411                                None
412                            }
413                        })
414                        .collect();
415                    if !suggestions.is_empty() {
416                        let msg = if suggestions.len() == 1 {
417                            "consider adding an explicit type annotation to the closure's argument"
418                        } else {
419                            "consider adding explicit type annotations to the closure's arguments"
420                        };
421                        err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
422                    }
423                }
424            }
425        }
426
427        err
428    }
429
430    /// Add notes with details about the expected and actual trait refs, with attention to cases
431    /// when placeholder regions are involved: either the trait or the self type containing
432    /// them needs to be mentioned the closest to the placeholders.
433    /// This makes the error messages read better, however at the cost of some complexity
434    /// due to the number of combinations we have to deal with.
435    fn explain_actual_impl_that_was_found(
436        &self,
437        sub_placeholder: Option<Region<'tcx>>,
438        sup_placeholder: Option<Region<'tcx>>,
439        has_sub: Option<usize>,
440        has_sup: Option<usize>,
441        expected_trait_ref: ty::TraitRef<'tcx>,
442        actual_trait_ref: ty::TraitRef<'tcx>,
443        vid: Option<Region<'tcx>>,
444        expected_has_vid: Option<usize>,
445        actual_has_vid: Option<usize>,
446        any_self_ty_has_vid: bool,
447        leading_ellipsis: bool,
448    ) -> Vec<ActualImplExplNotes<'tcx>> {
449        // The weird thing here with the `maybe_highlighting_region` calls and the
450        // the match inside is meant to be like this:
451        //
452        // - The match checks whether the given things (placeholders, etc) appear
453        //   in the types are about to print
454        // - Meanwhile, the `maybe_highlighting_region` calls set up
455        //   highlights so that, if they do appear, we will replace
456        //   them `'0` and whatever. (This replacement takes place
457        //   inside the closure given to `maybe_highlighting_region`.)
458        //
459        // There is some duplication between the calls -- i.e., the
460        // `maybe_highlighting_region` checks if (e.g.) `has_sub` is
461        // None, an then we check again inside the closure, but this
462        // setup sort of minimized the number of calls and so form.
463
464        let highlight_trait_ref = |trait_ref| Highlighted {
465            tcx: self.tcx(),
466            highlight: RegionHighlightMode::default(),
467            value: trait_ref,
468            ns: Namespace::TypeNS,
469        };
470
471        let same_self_type = actual_trait_ref.self_ty() == expected_trait_ref.self_ty();
472
473        let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
474        expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
475        expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
476
477        let passive_voice = match (has_sub, has_sup) {
478            (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
479            (None, None) => {
480                expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
481                match expected_has_vid {
482                    Some(_) => true,
483                    None => any_self_ty_has_vid,
484                }
485            }
486        };
487
488        let (kind, ty_or_sig, trait_path) = if same_self_type {
489            let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
490            self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
491
492            if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
493            {
494                let closure_sig = self_ty.map(|closure| {
495                    if let ty::Closure(_, args) = closure.kind() {
496                        self.tcx()
497                            .signature_unclosure(args.as_closure().sig(), rustc_hir::Safety::Safe)
498                    } else {
499                        ::rustc_middle::util::bug::bug_fmt(format_args!("type is not longer closure"));bug!("type is not longer closure");
500                    }
501                });
502                (
503                    ActualImplExpectedKind::Signature,
504                    TyOrSig::ClosureSig(closure_sig),
505                    expected_trait_ref.map(|tr| tr.print_only_trait_path()),
506                )
507            } else {
508                (
509                    ActualImplExpectedKind::Other,
510                    TyOrSig::Ty(self_ty),
511                    expected_trait_ref.map(|tr| tr.print_only_trait_path()),
512                )
513            }
514        } else if passive_voice {
515            (
516                ActualImplExpectedKind::Passive,
517                TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
518                expected_trait_ref.map(|tr| tr.print_only_trait_path()),
519            )
520        } else {
521            (
522                ActualImplExpectedKind::Other,
523                TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
524                expected_trait_ref.map(|tr| tr.print_only_trait_path()),
525            )
526        };
527
528        let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {
529            (Some(n1), Some(n2)) => {
530                (ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2))
531            }
532            (Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0),
533            (None, None) => {
534                if let Some(n) = expected_has_vid {
535                    (ActualImplExpectedLifetimeKind::Some, n, 0)
536                } else {
537                    (ActualImplExpectedLifetimeKind::Nothing, 0, 0)
538                }
539            }
540        };
541
542        let note_1 = ActualImplExplNotes::new_expected(
543            kind,
544            lt_kind,
545            leading_ellipsis,
546            ty_or_sig,
547            trait_path,
548            lifetime_1,
549            lifetime_2,
550        );
551
552        let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
553        actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
554
555        let passive_voice = match actual_has_vid {
556            Some(_) => any_self_ty_has_vid,
557            None => true,
558        };
559
560        let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path());
561        let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();
562        let has_lifetime = actual_has_vid.is_some();
563        let lifetime = actual_has_vid.unwrap_or_default();
564
565        let note_2 = if same_self_type {
566            ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime }
567        } else if passive_voice {
568            ActualImplExplNotes::ButActuallyImplementedForTy {
569                trait_path,
570                ty,
571                has_lifetime,
572                lifetime,
573            }
574        } else {
575            ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime }
576        };
577
578        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [note_1, note_2]))vec![note_1, note_2]
579    }
580}