Skip to main content

rustc_hir_analysis/check/
compare_eii.rs

1//! This module is very similar to `compare_impl_item`.
2//! Most logic is taken from there,
3//! since in a very similar way we're comparing some declaration of a signature to an implementation.
4//! The major difference is that we don't bother with self types, since for EIIs we're comparing freestanding item.
5
6use std::borrow::Cow;
7use std::iter;
8
9use rustc_data_structures::fx::FxIndexSet;
10use rustc_errors::{Applicability, E0806, struct_span_code_err};
11use rustc_hir::attrs::EiiImplResolution;
12use rustc_hir::def_id::{DefId, LocalDefId};
13use rustc_hir::{self as hir, FnSig, HirId, ItemKind, find_attr};
14use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
15use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
16use rustc_middle::ty::error::{ExpectedFound, TypeError};
17use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode};
18use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
19use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
20use rustc_trait_selection::regions::InferCtxtRegionExt;
21use rustc_trait_selection::traits::{self, ObligationCtxt};
22use tracing::{debug, instrument};
23
24use super::potentially_plural_count;
25use crate::check::compare_impl_item::{
26    CheckNumberOfEarlyBoundRegionsError, check_number_of_early_bound_regions,
27};
28use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii};
29
30/// Checks whether the signature of some `external_impl`, matches
31/// the signature of `declaration`, which it is supposed to be compatible
32/// with in order to implement the item.
33pub(crate) fn compare_eii_function_types<'tcx>(
34    tcx: TyCtxt<'tcx>,
35    external_impl: LocalDefId,
36    foreign_item: DefId,
37    eii_name: Symbol,
38    eii_attr_span: Span,
39) -> Result<(), ErrorGuaranteed> {
40    check_is_structurally_compatible(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?;
41
42    let external_impl_span = tcx.def_span(external_impl);
43    let cause = ObligationCause::new(
44        external_impl_span,
45        external_impl,
46        ObligationCauseCode::CompareEii { external_impl, declaration: foreign_item },
47    );
48
49    // FIXME(eii): even if we don't support generic functions, we should support explicit outlive bounds here
50    let param_env = tcx.param_env(foreign_item);
51
52    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
53    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
54
55    // We now need to check that the signature of the implementation is
56    // compatible with that of the declaration. We do this by
57    // checking that `impl_fty <: trait_fty`.
58    //
59    // FIXME: We manually instantiate the declaration here as we need
60    // to manually compute its implied bounds. Otherwise this could just
61    // be ocx.sub(impl_sig, trait_sig).
62
63    let mut wf_tys = FxIndexSet::default();
64    let norm_cause = ObligationCause::misc(external_impl_span, external_impl);
65
66    let declaration_sig = tcx.fn_sig(foreign_item).instantiate_identity();
67    let declaration_sig = tcx.liberate_late_bound_regions(external_impl.into(), declaration_sig);
68    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/check/compare_eii.rs:68",
                        "rustc_hir_analysis::check::compare_eii",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/check/compare_eii.rs"),
                        ::tracing_core::__macro_support::Option::Some(68u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::check::compare_eii"),
                        ::tracing_core::field::FieldSet::new(&["declaration_sig"],
                            ::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(&declaration_sig)
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(?declaration_sig);
69
70    let unnormalized_external_impl_sig = infcx.instantiate_binder_with_fresh_vars(
71        external_impl_span,
72        infer::BoundRegionConversionTime::HigherRankedType,
73        tcx.fn_sig(external_impl).instantiate(
74            tcx,
75            infcx.fresh_args_for_item(external_impl_span, external_impl.to_def_id()),
76        ),
77    );
78    let external_impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_external_impl_sig);
79    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/check/compare_eii.rs:79",
                        "rustc_hir_analysis::check::compare_eii",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/check/compare_eii.rs"),
                        ::tracing_core::__macro_support::Option::Some(79u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::check::compare_eii"),
                        ::tracing_core::field::FieldSet::new(&["external_impl_sig"],
                            ::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(&external_impl_sig)
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(?external_impl_sig);
80
81    // Next, add all inputs and output as well-formed tys. Importantly,
82    // we have to do this before normalization, since the normalized ty may
83    // not contain the input parameters. See issue #87748.
84    wf_tys.extend(declaration_sig.inputs_and_output.iter());
85    let declaration_sig = ocx.normalize(&norm_cause, param_env, declaration_sig);
86    // We also have to add the normalized declaration
87    // as we don't normalize during implied bounds computation.
88    wf_tys.extend(external_impl_sig.inputs_and_output.iter());
89
90    // FIXME: Copied over from compare impl items, same issue:
91    // We'd want to keep more accurate spans than "the method signature" when
92    // processing the comparison between the trait and impl fn, but we sadly lose them
93    // and point at the whole signature when a trait bound or specific input or output
94    // type would be more appropriate. In other places we have a `Vec<Span>`
95    // corresponding to their `Vec<Predicate>`, but we don't have that here.
96    // Fixing this would improve the output of test `issue-83765.rs`.
97    let result = ocx.sup(&cause, param_env, declaration_sig, external_impl_sig);
98
99    if let Err(terr) = result {
100        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/check/compare_eii.rs:100",
                        "rustc_hir_analysis::check::compare_eii",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/check/compare_eii.rs"),
                        ::tracing_core::__macro_support::Option::Some(100u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::check::compare_eii"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        "external_impl_sig", "declaration_sig", "terr"],
                            ::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!("sub_types failed")
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&external_impl_sig)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&declaration_sig)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&terr) as
                                            &dyn Value))])
            });
    } else { ; }
};debug!(?external_impl_sig, ?declaration_sig, ?terr, "sub_types failed");
101
102        let emitted = report_eii_mismatch(
103            infcx,
104            cause,
105            param_env,
106            terr,
107            (foreign_item, declaration_sig),
108            (external_impl, external_impl_sig),
109            eii_attr_span,
110            eii_name,
111        );
112        return Err(emitted);
113    }
114
115    if !(declaration_sig, external_impl_sig).references_error() {
116        for ty in unnormalized_external_impl_sig.inputs_and_output {
117            ocx.register_obligation(traits::Obligation::new(
118                infcx.tcx,
119                cause.clone(),
120                param_env,
121                ty::ClauseKind::WellFormed(ty.into()),
122            ));
123        }
124    }
125
126    // Check that all obligations are satisfied by the implementation's
127    // version.
128    let errors = ocx.evaluate_obligations_error_on_ambiguity();
129    if !errors.is_empty() {
130        let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
131        return Err(reported);
132    }
133
134    // Finally, resolve all regions. This catches wily misuses of
135    // lifetime parameters.
136    let errors = infcx.resolve_regions(external_impl, param_env, wf_tys);
137    if !errors.is_empty() {
138        return Err(infcx
139            .tainted_by_errors()
140            .unwrap_or_else(|| infcx.err_ctxt().report_region_errors(external_impl, &errors)));
141    }
142
143    Ok(())
144}
145
146/// Checks a bunch of different properties of the impl/trait methods for
147/// compatibility, such as asyncness, number of argument, self receiver kind,
148/// and number of early- and late-bound generics.
149///
150/// Corresponds to `check_method_is_structurally_compatible` for impl method compatibility checks.
151fn check_is_structurally_compatible<'tcx>(
152    tcx: TyCtxt<'tcx>,
153    external_impl: LocalDefId,
154    declaration: DefId,
155    eii_name: Symbol,
156    eii_attr_span: Span,
157) -> Result<(), ErrorGuaranteed> {
158    check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
159    check_number_of_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
160    check_early_region_bounds(tcx, external_impl, declaration, eii_attr_span)?;
161    Ok(())
162}
163
164/// externally implementable items can't have generics
165fn check_no_generics<'tcx>(
166    tcx: TyCtxt<'tcx>,
167    external_impl: LocalDefId,
168    _declaration: DefId,
169    eii_name: Symbol,
170    eii_attr_span: Span,
171) -> Result<(), ErrorGuaranteed> {
172    let generics = tcx.generics_of(external_impl);
173    if generics.own_requires_monomorphization()
174        // When an EII implementation is automatically generated by the `#[eii]` macro,
175        // it will directly refer to the foreign item, not through a macro.
176        // We don't want to emit this error if it's an implementation that's generated by the `#[eii]` macro,
177        // since in that case it looks like a duplicate error: the declaration of the EII already can't contain generics.
178        // So, we check here if at least one of the eii impls has ImplResolution::Macro, which indicates it's
179        // not generated as part of the declaration.
180        && {

        #[allow(deprecated)]
        {
            {
                'done:
                    {
                    for i in tcx.get_all_attrs(external_impl) {
                        #[allow(unused_imports)]
                        use rustc_hir::attrs::AttributeKind::*;
                        let i: &rustc_hir::Attribute = i;
                        match i {
                            rustc_hir::Attribute::Parsed(EiiImpls(impls)) if
                                impls.iter().any(|i|
                                        #[allow(non_exhaustive_omitted_patterns)] match i.resolution
                                            {
                                            EiiImplResolution::Macro(_) => true,
                                            _ => false,
                                        }) => {
                                break 'done Some(());
                            }
                            rustc_hir::Attribute::Unparsed(..) =>
                                {}
                                #[deny(unreachable_patterns)]
                                _ => {}
                        }
                    }
                    None
                }
            }
        }
    }.is_some()find_attr!(tcx, external_impl, EiiImpls(impls) if impls.iter().any(|i| matches!(i.resolution, EiiImplResolution::Macro(_)))
181        )
182    {
183        tcx.dcx().emit_err(EiiWithGenerics {
184            span: tcx.def_span(external_impl),
185            attr: eii_attr_span,
186            eii_name,
187            impl_name: tcx.item_name(external_impl),
188        });
189    }
190
191    Ok(())
192}
193
194fn check_early_region_bounds<'tcx>(
195    tcx: TyCtxt<'tcx>,
196    external_impl: LocalDefId,
197    declaration: DefId,
198    eii_attr_span: Span,
199) -> Result<(), ErrorGuaranteed> {
200    let external_impl_generics = tcx.generics_of(external_impl.to_def_id());
201    let external_impl_params = external_impl_generics.own_counts().lifetimes;
202
203    let declaration_generics = tcx.generics_of(declaration);
204    let declaration_params = declaration_generics.own_counts().lifetimes;
205
206    let Err(CheckNumberOfEarlyBoundRegionsError { span, generics_span, bounds_span, where_span }) =
207        check_number_of_early_bound_regions(
208            tcx,
209            external_impl,
210            declaration,
211            external_impl_generics,
212            external_impl_params,
213            declaration_generics,
214            declaration_params,
215        )
216    else {
217        return Ok(());
218    };
219
220    let mut diag = tcx.dcx().create_err(LifetimesOrBoundsMismatchOnEii {
221        span,
222        ident: tcx.item_name(external_impl.to_def_id()),
223        generics_span,
224        bounds_span,
225        where_span,
226    });
227
228    diag.span_label(eii_attr_span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("required because of this attribute"))
    })format!("required because of this attribute"));
229    return Err(diag.emit());
230}
231
232fn check_number_of_arguments<'tcx>(
233    tcx: TyCtxt<'tcx>,
234    external_impl: LocalDefId,
235    declaration: DefId,
236    eii_name: Symbol,
237    eii_attr_span: Span,
238) -> Result<(), ErrorGuaranteed> {
239    let external_impl_fty = tcx.fn_sig(external_impl);
240    let declaration_fty = tcx.fn_sig(declaration);
241    let declaration_number_args = declaration_fty.skip_binder().inputs().skip_binder().len();
242    let external_impl_number_args = external_impl_fty.skip_binder().inputs().skip_binder().len();
243
244    // if the number of args are equal, we're trivially done
245    if declaration_number_args == external_impl_number_args {
246        Ok(())
247    } else {
248        Err(report_number_of_arguments_mismatch(
249            tcx,
250            external_impl,
251            declaration,
252            eii_name,
253            eii_attr_span,
254            declaration_number_args,
255            external_impl_number_args,
256        ))
257    }
258}
259
260fn report_number_of_arguments_mismatch<'tcx>(
261    tcx: TyCtxt<'tcx>,
262    external_impl: LocalDefId,
263    declaration: DefId,
264    eii_name: Symbol,
265    eii_attr_span: Span,
266    declaration_number_args: usize,
267    external_impl_number_args: usize,
268) -> ErrorGuaranteed {
269    let external_impl_name = tcx.item_name(external_impl.to_def_id());
270
271    let declaration_span = declaration
272        .as_local()
273        .and_then(|def_id| {
274            let declaration_sig = get_declaration_sig(tcx, def_id).expect("foreign item sig");
275            let pos = declaration_number_args.saturating_sub(1);
276            declaration_sig.decl.inputs.get(pos).map(|arg| {
277                if pos == 0 {
278                    arg.span
279                } else {
280                    arg.span.with_lo(declaration_sig.decl.inputs[0].span.lo())
281                }
282            })
283        })
284        .or_else(|| tcx.hir_span_if_local(declaration))
285        .unwrap_or_else(|| tcx.def_span(declaration));
286
287    let (_, external_impl_sig, _, _) = &tcx.hir_expect_item(external_impl).expect_fn();
288    let pos = external_impl_number_args.saturating_sub(1);
289    let impl_span = external_impl_sig
290        .decl
291        .inputs
292        .get(pos)
293        .map(|arg| {
294            if pos == 0 {
295                arg.span
296            } else {
297                arg.span.with_lo(external_impl_sig.decl.inputs[0].span.lo())
298            }
299        })
300        .unwrap_or_else(|| tcx.def_span(external_impl));
301
302    let mut err = {
    tcx.dcx().struct_span_err(impl_span,
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`{2}` has {0} but #[{3}] requires it to have {1}",
                            potentially_plural_count(external_impl_number_args,
                                "parameter"), declaration_number_args, external_impl_name,
                            eii_name))
                })).with_code(E0806)
}struct_span_code_err!(
303        tcx.dcx(),
304        impl_span,
305        E0806,
306        "`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}",
307        potentially_plural_count(external_impl_number_args, "parameter"),
308        declaration_number_args
309    );
310
311    err.span_label(
312        declaration_span,
313        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("requires {0}",
                potentially_plural_count(declaration_number_args,
                    "parameter")))
    })format!("requires {}", potentially_plural_count(declaration_number_args, "parameter")),
314    );
315
316    err.span_label(
317        impl_span,
318        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("expected {0}, found {1}",
                potentially_plural_count(declaration_number_args,
                    "parameter"), external_impl_number_args))
    })format!(
319            "expected {}, found {}",
320            potentially_plural_count(declaration_number_args, "parameter"),
321            external_impl_number_args
322        ),
323    );
324
325    err.span_label(eii_attr_span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("required because of this attribute"))
    })format!("required because of this attribute"));
326
327    err.emit()
328}
329
330fn report_eii_mismatch<'tcx>(
331    infcx: &InferCtxt<'tcx>,
332    mut cause: ObligationCause<'tcx>,
333    param_env: ty::ParamEnv<'tcx>,
334    terr: TypeError<'tcx>,
335    (declaration_did, declaration_sig): (DefId, ty::FnSig<'tcx>),
336    (external_impl_did, external_impl_sig): (LocalDefId, ty::FnSig<'tcx>),
337    eii_attr_span: Span,
338    eii_name: Symbol,
339) -> ErrorGuaranteed {
340    let tcx = infcx.tcx;
341    let (impl_err_span, trait_err_span, external_impl_name) =
342        extract_spans_for_error_reporting(infcx, terr, &cause, declaration_did, external_impl_did);
343
344    let mut diag = {
    tcx.dcx().struct_span_err(impl_err_span,
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("function `{0}` has a type that is incompatible with the declaration of `#[{1}]`",
                            external_impl_name, eii_name))
                })).with_code(E0806)
}struct_span_code_err!(
345        tcx.dcx(),
346        impl_err_span,
347        E0806,
348        "function `{}` has a type that is incompatible with the declaration of `#[{eii_name}]`",
349        external_impl_name
350    );
351
352    diag.span_note(eii_attr_span, "expected this because of this attribute");
353
354    match &terr {
355        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
356            if declaration_sig.inputs().len() == *i {
357                // Suggestion to change output type. We do not suggest in `async` functions
358                // to avoid complex logic or incorrect output.
359                if let ItemKind::Fn { sig, .. } = &tcx.hir_expect_item(external_impl_did).kind
360                    && !sig.header.asyncness.is_async()
361                {
362                    let msg = "change the output type to match the declaration";
363                    let ap = Applicability::MachineApplicable;
364                    match sig.decl.output {
365                        hir::FnRetTy::DefaultReturn(sp) => {
366                            let sugg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" -> {0}",
                declaration_sig.output()))
    })format!(" -> {}", declaration_sig.output());
367                            diag.span_suggestion_verbose(sp, msg, sugg, ap);
368                        }
369                        hir::FnRetTy::Return(hir_ty) => {
370                            let sugg = declaration_sig.output();
371                            diag.span_suggestion_verbose(hir_ty.span, msg, sugg, ap);
372                        }
373                    };
374                };
375            } else if let Some(trait_ty) = declaration_sig.inputs().get(*i) {
376                diag.span_suggestion_verbose(
377                    impl_err_span,
378                    "change the parameter type to match the declaration",
379                    trait_ty,
380                    Applicability::MachineApplicable,
381                );
382            }
383        }
384        _ => {}
385    }
386
387    cause.span = impl_err_span;
388    infcx.err_ctxt().note_type_err(
389        &mut diag,
390        &cause,
391        trait_err_span.map(|sp| (sp, Cow::from("type in declaration"), false)),
392        Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
393            expected: ty::Binder::dummy(declaration_sig),
394            found: ty::Binder::dummy(external_impl_sig),
395        }))),
396        terr,
397        false,
398        None,
399    );
400
401    diag.emit()
402}
403
404#[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("extract_spans_for_error_reporting",
                                    "rustc_hir_analysis::check::compare_eii",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/check/compare_eii.rs"),
                                    ::tracing_core::__macro_support::Option::Some(404u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::check::compare_eii"),
                                    ::tracing_core::field::FieldSet::new(&["terr", "cause",
                                                    "declaration", "external_impl"],
                                        ::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(&terr)
                                                            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(&declaration)
                                                            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(&external_impl)
                                                            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: (Span, Option<Span>, Ident) =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            let tcx = infcx.tcx;
            let (mut external_impl_args, external_impl_name) =
                {
                    let item = tcx.hir_expect_item(external_impl);
                    let (ident, sig, _, _) = item.expect_fn();
                    (sig.decl.inputs.iter().map(|t|
                                    t.span).chain(iter::once(sig.decl.output.span())), ident)
                };
            let declaration_args =
                declaration.as_local().map(|def_id|
                        {
                            if let Some(sig) = get_declaration_sig(tcx, def_id) {
                                sig.decl.inputs.iter().map(|t|
                                            t.span).chain(iter::once(sig.decl.output.span()))
                            } else {
                                {
                                    ::core::panicking::panic_fmt(format_args!("expected {0:?} to be a foreign function",
                                            def_id));
                                };
                            }
                        });
            match terr {
                TypeError::ArgumentMutability(i) |
                    TypeError::ArgumentSorts(ExpectedFound { .. }, i) =>
                    (external_impl_args.nth(i).unwrap(),
                        declaration_args.and_then(|mut args| args.nth(i)),
                        external_impl_name),
                _ =>
                    (cause.span,
                        tcx.hir_span_if_local(declaration).or_else(||
                                Some(tcx.def_span(declaration))), external_impl_name),
            }
        }
    }
}#[instrument(level = "debug", skip(infcx))]
405fn extract_spans_for_error_reporting<'tcx>(
406    infcx: &infer::InferCtxt<'tcx>,
407    terr: TypeError<'_>,
408    cause: &ObligationCause<'tcx>,
409    declaration: DefId,
410    external_impl: LocalDefId,
411) -> (Span, Option<Span>, Ident) {
412    let tcx = infcx.tcx;
413    let (mut external_impl_args, external_impl_name) = {
414        let item = tcx.hir_expect_item(external_impl);
415        let (ident, sig, _, _) = item.expect_fn();
416        (sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())), ident)
417    };
418
419    let declaration_args = declaration.as_local().map(|def_id| {
420        if let Some(sig) = get_declaration_sig(tcx, def_id) {
421            sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
422        } else {
423            panic!("expected {def_id:?} to be a foreign function");
424        }
425    });
426
427    match terr {
428        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => (
429            external_impl_args.nth(i).unwrap(),
430            declaration_args.and_then(|mut args| args.nth(i)),
431            external_impl_name,
432        ),
433        _ => (
434            cause.span,
435            tcx.hir_span_if_local(declaration).or_else(|| Some(tcx.def_span(declaration))),
436            external_impl_name,
437        ),
438    }
439}
440
441fn get_declaration_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<&'tcx FnSig<'tcx>> {
442    let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id);
443    tcx.hir_fn_sig_by_hir_id(hir_id)
444}