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