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

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