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