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, ParamEnv, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized};
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::{
30    EiiDefkindMismatch, EiiDefkindMismatchStaticMutability, EiiDefkindMismatchStaticSafety,
31    EiiWithGenerics, LifetimesOrBoundsMismatchOnEii,
32};
33
34/// Checks whether the signature of some `external_impl`, matches
35/// the signature of `declaration`, which it is supposed to be compatible
36/// with in order to implement the item.
37pub(crate) fn compare_eii_function_types<'tcx>(
38    tcx: TyCtxt<'tcx>,
39    external_impl: LocalDefId,
40    foreign_item: DefId,
41    eii_name: Symbol,
42    eii_attr_span: Span,
43) -> Result<(), ErrorGuaranteed> {
44    check_eii_target(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?;
45    check_is_structurally_compatible(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?;
46
47    let external_impl_span = tcx.def_span(external_impl);
48    let cause = ObligationCause::new(
49        external_impl_span,
50        external_impl,
51        ObligationCauseCode::CompareEii { external_impl, declaration: foreign_item },
52    );
53
54    // FIXME(eii): even if we don't support generic functions, we should support explicit outlive bounds here
55    let param_env = tcx.param_env(foreign_item);
56
57    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
58    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
59
60    // We now need to check that the signature of the implementation is
61    // compatible with that of the declaration. We do this by
62    // checking that `impl_fty <: trait_fty`.
63    //
64    // FIXME: We manually instantiate the declaration here as we need
65    // to manually compute its implied bounds. Otherwise this could just
66    // be ocx.sub(impl_sig, trait_sig).
67
68    let mut wf_tys = FxIndexSet::default();
69    let norm_cause = ObligationCause::misc(external_impl_span, external_impl);
70
71    let declaration_sig = tcx.fn_sig(foreign_item).instantiate_identity().skip_norm_wip();
72    let declaration_sig = tcx.liberate_late_bound_regions(external_impl.into(), declaration_sig);
73    {
    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:73",
                        "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(73u32),
                        ::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);
74
75    let unnormalized_external_impl_sig = infcx.instantiate_binder_with_fresh_vars(
76        external_impl_span,
77        infer::BoundRegionConversionTime::HigherRankedType,
78        tcx.fn_sig(external_impl)
79            .instantiate(
80                tcx,
81                infcx.fresh_args_for_item(external_impl_span, external_impl.to_def_id()),
82            )
83            .skip_norm_wip(),
84    );
85    let external_impl_sig = ocx.normalize(
86        &norm_cause,
87        param_env,
88        Unnormalized::new_wip(unnormalized_external_impl_sig),
89    );
90    {
    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:90",
                        "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(90u32),
                        ::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);
91
92    // Next, add all inputs and output as well-formed tys. Importantly,
93    // we have to do this before normalization, since the normalized ty may
94    // not contain the input parameters. See issue #87748.
95    wf_tys.extend(declaration_sig.inputs_and_output.iter());
96    let declaration_sig =
97        ocx.normalize(&norm_cause, param_env, Unnormalized::new_wip(declaration_sig));
98    // We also have to add the normalized declaration
99    // as we don't normalize during implied bounds computation.
100    wf_tys.extend(external_impl_sig.inputs_and_output.iter());
101
102    // FIXME: Copied over from compare impl items, same issue:
103    // We'd want to keep more accurate spans than "the method signature" when
104    // processing the comparison between the trait and impl fn, but we sadly lose them
105    // and point at the whole signature when a trait bound or specific input or output
106    // type would be more appropriate. In other places we have a `Vec<Span>`
107    // corresponding to their `Vec<Predicate>`, but we don't have that here.
108    // Fixing this would improve the output of test `issue-83765.rs`.
109    let result = ocx.sup(&cause, param_env, declaration_sig, external_impl_sig);
110
111    if let Err(terr) = result {
112        {
    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:112",
                        "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(112u32),
                        ::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");
113
114        let emitted = report_eii_mismatch(
115            infcx,
116            cause,
117            param_env,
118            terr,
119            (foreign_item, declaration_sig),
120            (external_impl, external_impl_sig),
121            eii_attr_span,
122            eii_name,
123        );
124        return Err(emitted);
125    }
126
127    if !(declaration_sig, external_impl_sig).references_error() {
128        for ty in unnormalized_external_impl_sig.inputs_and_output {
129            ocx.register_obligation(traits::Obligation::new(
130                infcx.tcx,
131                cause.clone(),
132                param_env,
133                ty::ClauseKind::WellFormed(ty.into()),
134            ));
135        }
136    }
137
138    // Check that all obligations are satisfied by the implementation's
139    // version.
140    let errors = ocx.evaluate_obligations_error_on_ambiguity();
141    if !errors.is_empty() {
142        let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
143        return Err(reported);
144    }
145
146    // Finally, resolve all regions. This catches wily misuses of
147    // lifetime parameters.
148    let errors = infcx.resolve_regions(external_impl, param_env, wf_tys);
149    if !errors.is_empty() {
150        return Err(infcx
151            .tainted_by_errors()
152            .unwrap_or_else(|| infcx.err_ctxt().report_region_errors(external_impl, &errors)));
153    }
154
155    Ok(())
156}
157
158pub(crate) fn compare_eii_statics<'tcx>(
159    tcx: TyCtxt<'tcx>,
160    external_impl: LocalDefId,
161    external_impl_ty: Ty<'tcx>,
162    foreign_item: DefId,
163    eii_name: Symbol,
164    eii_attr_span: Span,
165) -> Result<(), ErrorGuaranteed> {
166    check_eii_target(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?;
167
168    let external_impl_span = tcx.def_span(external_impl);
169    let cause = ObligationCause::new(
170        external_impl_span,
171        external_impl,
172        ObligationCauseCode::CompareEii { external_impl, declaration: foreign_item },
173    );
174
175    let param_env = ParamEnv::empty();
176
177    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
178    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
179
180    let declaration_ty = tcx.type_of(foreign_item).instantiate_identity().skip_norm_wip();
181    {
    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:181",
                        "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(181u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::check::compare_eii"),
                        ::tracing_core::field::FieldSet::new(&["declaration_ty"],
                            ::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_ty)
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(?declaration_ty);
182
183    // FIXME: Copied over from compare impl items, same issue:
184    // We'd want to keep more accurate spans than "the method signature" when
185    // processing the comparison between the trait and impl fn, but we sadly lose them
186    // and point at the whole signature when a trait bound or specific input or output
187    // type would be more appropriate. In other places we have a `Vec<Span>`
188    // corresponding to their `Vec<Predicate>`, but we don't have that here.
189    // Fixing this would improve the output of test `issue-83765.rs`.
190    let result = ocx.sup(&cause, param_env, declaration_ty, external_impl_ty);
191
192    if let Err(terr) = result {
193        {
    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:193",
                        "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(193u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::check::compare_eii"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        "external_impl_ty", "declaration_ty", "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_ty)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&declaration_ty)
                                            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_ty, ?declaration_ty, ?terr, "sub_types failed");
194
195        let mut diag = {
    tcx.dcx().struct_span_err(cause.span,
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("static `{0}` has a type that is incompatible with the declaration of `#[{1}]`",
                            tcx.item_name(external_impl), eii_name))
                })).with_code(E0806)
}struct_span_code_err!(
196            tcx.dcx(),
197            cause.span,
198            E0806,
199            "static `{}` has a type that is incompatible with the declaration of `#[{eii_name}]`",
200            tcx.item_name(external_impl)
201        );
202        diag.span_note(eii_attr_span, "expected this because of this attribute");
203
204        return Err(diag.emit());
205    }
206
207    // Check that all obligations are satisfied by the implementation's
208    // version.
209    let errors = ocx.evaluate_obligations_error_on_ambiguity();
210    if !errors.is_empty() {
211        let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
212        return Err(reported);
213    }
214
215    // Finally, resolve all regions. This catches wily misuses of
216    // lifetime parameters.
217    let errors = infcx.resolve_regions(external_impl, param_env, []);
218    if !errors.is_empty() {
219        return Err(infcx
220            .tainted_by_errors()
221            .unwrap_or_else(|| infcx.err_ctxt().report_region_errors(external_impl, &errors)));
222    }
223
224    Ok(())
225}
226
227fn check_eii_target(
228    tcx: TyCtxt<'_>,
229    external_impl: LocalDefId,
230    foreign_item: DefId,
231    eii_name: Symbol,
232    eii_attr_span: Span,
233) -> Result<(), ErrorGuaranteed> {
234    // Error recovery can resolve the EII target to another value item with the same name,
235    // such as a tuple-struct constructor. Skip the comparison in that case and rely on the
236    // earlier name-resolution error instead of ICEing while building EII diagnostics.
237    // See <https://github.com/rust-lang/rust/issues/153502>.
238    if !tcx.is_foreign_item(foreign_item) {
239        return Err(tcx.dcx().delayed_bug("EII is a foreign item"));
240    }
241    let expected_kind = tcx.def_kind(foreign_item);
242    let actual_kind = tcx.def_kind(external_impl);
243
244    match expected_kind {
245        // Correct target
246        _ if expected_kind == actual_kind => Ok(()),
247        DefKind::Static { mutability: m1, safety: s1, .. }
248            if let DefKind::Static { mutability: m2, safety: s2, .. } = actual_kind =>
249        {
250            Err(if s1 != s2 {
251                tcx.dcx().emit_err(EiiDefkindMismatchStaticSafety { span: eii_attr_span, eii_name })
252            } else if m1 != m2 {
253                tcx.dcx()
254                    .emit_err(EiiDefkindMismatchStaticMutability { span: eii_attr_span, eii_name })
255            } else {
256                ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
257            })
258        }
259        // Not checked by attr target checking
260        DefKind::Fn | DefKind::Static { .. } => Err(tcx.dcx().emit_err(EiiDefkindMismatch {
261            span: eii_attr_span,
262            eii_name,
263            expected_kind: expected_kind.descr(foreign_item),
264        })),
265        // Checked by attr target checking
266        _ => Err(tcx.dcx().delayed_bug("Attribute should not be allowed by target checking")),
267    }
268}
269
270/// Checks a bunch of different properties of the impl/trait methods for
271/// compatibility, such as asyncness, number of argument, self receiver kind,
272/// and number of early- and late-bound generics.
273///
274/// Corresponds to `check_method_is_structurally_compatible` for impl method compatibility checks.
275fn check_is_structurally_compatible<'tcx>(
276    tcx: TyCtxt<'tcx>,
277    external_impl: LocalDefId,
278    declaration: DefId,
279    eii_name: Symbol,
280    eii_attr_span: Span,
281) -> Result<(), ErrorGuaranteed> {
282    check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
283    check_number_of_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
284    check_early_region_bounds(tcx, external_impl, declaration, eii_attr_span)?;
285    Ok(())
286}
287
288/// externally implementable items can't have generics
289fn check_no_generics<'tcx>(
290    tcx: TyCtxt<'tcx>,
291    external_impl: LocalDefId,
292    _declaration: DefId,
293    eii_name: Symbol,
294    eii_attr_span: Span,
295) -> Result<(), ErrorGuaranteed> {
296    let generics = tcx.generics_of(external_impl);
297    if generics.own_requires_monomorphization()
298        // When an EII implementation is automatically generated by the `#[eii]` macro,
299        // it will directly refer to the foreign item, not through a macro.
300        // We don't want to emit this error if it's an implementation that's generated by the `#[eii]` macro,
301        // since in that case it looks like a duplicate error: the declaration of the EII already can't contain generics.
302        // So, we check here if at least one of the eii impls has ImplResolution::Macro, which indicates it's
303        // not generated as part of the declaration.
304        && {
        {
            'done:
                {
                for i in
                    ::rustc_hir::attrs::HasAttrs::get_attrs(external_impl, &tcx)
                    {
                    #[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(_)))
305        )
306    {
307        tcx.dcx().emit_err(EiiWithGenerics {
308            span: tcx.def_span(external_impl),
309            attr: eii_attr_span,
310            eii_name,
311            impl_name: tcx.item_name(external_impl),
312        });
313    }
314
315    Ok(())
316}
317
318fn check_early_region_bounds<'tcx>(
319    tcx: TyCtxt<'tcx>,
320    external_impl: LocalDefId,
321    declaration: DefId,
322    eii_attr_span: Span,
323) -> Result<(), ErrorGuaranteed> {
324    let external_impl_generics = tcx.generics_of(external_impl.to_def_id());
325    let external_impl_params = external_impl_generics.own_counts().lifetimes;
326
327    let declaration_generics = tcx.generics_of(declaration);
328    let declaration_params = declaration_generics.own_counts().lifetimes;
329
330    let Err(CheckNumberOfEarlyBoundRegionsError { span, generics_span, bounds_span, where_span }) =
331        check_number_of_early_bound_regions(
332            tcx,
333            external_impl,
334            declaration,
335            external_impl_generics,
336            external_impl_params,
337            declaration_generics,
338            declaration_params,
339        )
340    else {
341        return Ok(());
342    };
343
344    let mut diag = tcx.dcx().create_err(LifetimesOrBoundsMismatchOnEii {
345        span,
346        ident: tcx.item_name(external_impl.to_def_id()),
347        generics_span,
348        bounds_span,
349        where_span,
350    });
351
352    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"));
353    return Err(diag.emit());
354}
355
356fn check_number_of_arguments<'tcx>(
357    tcx: TyCtxt<'tcx>,
358    external_impl: LocalDefId,
359    declaration: DefId,
360    eii_name: Symbol,
361    eii_attr_span: Span,
362) -> Result<(), ErrorGuaranteed> {
363    let external_impl_fty = tcx.fn_sig(external_impl);
364    let declaration_fty = tcx.fn_sig(declaration);
365    let declaration_number_args = declaration_fty.skip_binder().inputs().skip_binder().len();
366    let external_impl_number_args = external_impl_fty.skip_binder().inputs().skip_binder().len();
367
368    // if the number of args are equal, we're trivially done
369    if declaration_number_args == external_impl_number_args {
370        Ok(())
371    } else {
372        Err(report_number_of_arguments_mismatch(
373            tcx,
374            external_impl,
375            declaration,
376            eii_name,
377            eii_attr_span,
378            declaration_number_args,
379            external_impl_number_args,
380        ))
381    }
382}
383
384fn report_number_of_arguments_mismatch<'tcx>(
385    tcx: TyCtxt<'tcx>,
386    external_impl: LocalDefId,
387    declaration: DefId,
388    eii_name: Symbol,
389    eii_attr_span: Span,
390    declaration_number_args: usize,
391    external_impl_number_args: usize,
392) -> ErrorGuaranteed {
393    let external_impl_name = tcx.item_name(external_impl.to_def_id());
394
395    let declaration_span = declaration
396        .as_local()
397        .and_then(|def_id| {
398            let declaration_sig = get_declaration_sig(tcx, def_id).expect("foreign item sig");
399            let pos = declaration_number_args.saturating_sub(1);
400            declaration_sig.decl.inputs.get(pos).map(|arg| {
401                if pos == 0 {
402                    arg.span
403                } else {
404                    arg.span.with_lo(declaration_sig.decl.inputs[0].span.lo())
405                }
406            })
407        })
408        .or_else(|| tcx.hir_span_if_local(declaration))
409        .unwrap_or_else(|| tcx.def_span(declaration));
410
411    let (_, external_impl_sig, _, _) = &tcx.hir_expect_item(external_impl).expect_fn();
412    let pos = external_impl_number_args.saturating_sub(1);
413    let impl_span = external_impl_sig
414        .decl
415        .inputs
416        .get(pos)
417        .map(|arg| {
418            if pos == 0 {
419                arg.span
420            } else {
421                arg.span.with_lo(external_impl_sig.decl.inputs[0].span.lo())
422            }
423        })
424        .unwrap_or_else(|| tcx.def_span(external_impl));
425
426    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!(
427        tcx.dcx(),
428        impl_span,
429        E0806,
430        "`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}",
431        potentially_plural_count(external_impl_number_args, "parameter"),
432        declaration_number_args
433    );
434
435    err.span_label(
436        declaration_span,
437        ::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")),
438    );
439
440    err.span_label(
441        impl_span,
442        ::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!(
443            "expected {}, found {}",
444            potentially_plural_count(declaration_number_args, "parameter"),
445            external_impl_number_args
446        ),
447    );
448
449    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"));
450
451    err.emit()
452}
453
454fn report_eii_mismatch<'tcx>(
455    infcx: &InferCtxt<'tcx>,
456    mut cause: ObligationCause<'tcx>,
457    param_env: ty::ParamEnv<'tcx>,
458    terr: TypeError<'tcx>,
459    (declaration_did, declaration_sig): (DefId, ty::FnSig<'tcx>),
460    (external_impl_did, external_impl_sig): (LocalDefId, ty::FnSig<'tcx>),
461    eii_attr_span: Span,
462    eii_name: Symbol,
463) -> ErrorGuaranteed {
464    let tcx = infcx.tcx;
465    let (impl_err_span, trait_err_span, external_impl_name) =
466        extract_spans_for_error_reporting(infcx, terr, &cause, declaration_did, external_impl_did);
467
468    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!(
469        tcx.dcx(),
470        impl_err_span,
471        E0806,
472        "function `{}` has a type that is incompatible with the declaration of `#[{eii_name}]`",
473        external_impl_name
474    );
475
476    diag.span_note(eii_attr_span, "expected this because of this attribute");
477
478    match &terr {
479        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
480            if declaration_sig.inputs().len() == *i {
481                // Suggestion to change output type. We do not suggest in `async` functions
482                // to avoid complex logic or incorrect output.
483                if let ItemKind::Fn { sig, .. } = &tcx.hir_expect_item(external_impl_did).kind
484                    && !sig.header.asyncness.is_async()
485                {
486                    let msg = "change the output type to match the declaration";
487                    let ap = Applicability::MachineApplicable;
488                    match sig.decl.output {
489                        hir::FnRetTy::DefaultReturn(sp) => {
490                            let sugg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" -> {0}",
                declaration_sig.output()))
    })format!(" -> {}", declaration_sig.output());
491                            diag.span_suggestion_verbose(sp, msg, sugg, ap);
492                        }
493                        hir::FnRetTy::Return(hir_ty) => {
494                            let sugg = declaration_sig.output();
495                            diag.span_suggestion_verbose(hir_ty.span, msg, sugg, ap);
496                        }
497                    };
498                };
499            } else if let Some(trait_ty) = declaration_sig.inputs().get(*i) {
500                diag.span_suggestion_verbose(
501                    impl_err_span,
502                    "change the parameter type to match the declaration",
503                    trait_ty,
504                    Applicability::MachineApplicable,
505                );
506            }
507        }
508        _ => {}
509    }
510
511    cause.span = impl_err_span;
512    infcx.err_ctxt().note_type_err(
513        &mut diag,
514        &cause,
515        trait_err_span.map(|sp| (sp, Cow::from("type in declaration"), false)),
516        Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
517            expected: ty::Binder::dummy(declaration_sig),
518            found: ty::Binder::dummy(external_impl_sig),
519        }))),
520        terr,
521        false,
522        None,
523    );
524
525    diag.emit()
526}
527
528#[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(528u32),
                                    ::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))]
529fn extract_spans_for_error_reporting<'tcx>(
530    infcx: &infer::InferCtxt<'tcx>,
531    terr: TypeError<'_>,
532    cause: &ObligationCause<'tcx>,
533    declaration: DefId,
534    external_impl: LocalDefId,
535) -> (Span, Option<Span>, Ident) {
536    let tcx = infcx.tcx;
537    let (mut external_impl_args, external_impl_name) = {
538        let item = tcx.hir_expect_item(external_impl);
539        let (ident, sig, _, _) = item.expect_fn();
540        (sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())), ident)
541    };
542
543    let declaration_args = declaration.as_local().map(|def_id| {
544        if let Some(sig) = get_declaration_sig(tcx, def_id) {
545            sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
546        } else {
547            panic!("expected {def_id:?} to be a foreign function");
548        }
549    });
550
551    match terr {
552        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => (
553            external_impl_args.nth(i).unwrap(),
554            declaration_args.and_then(|mut args| args.nth(i)),
555            external_impl_name,
556        ),
557        _ => (
558            cause.span,
559            tcx.hir_span_if_local(declaration).or_else(|| Some(tcx.def_span(declaration))),
560            external_impl_name,
561        ),
562    }
563}
564
565fn get_declaration_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<&'tcx FnSig<'tcx>> {
566    let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id);
567    tcx.hir_fn_sig_by_hir_id(hir_id)
568}