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, 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    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(&[{
                                            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);
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(&[{
                                            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);
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",
                                        {
                                            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");
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 let TraitErrors::HasErrors(errors) = errors {
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(&[{
                                            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);
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",
                                        {
                                            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");
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 let TraitErrors::HasErrors(errors) = errors {
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_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::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }
    }.is_some()find_attr!(tcx, external_impl, EiiImpl(i) if matches!(i.resolution, EiiImplResolution::Macro(_)))
305    {
306        tcx.dcx().emit_err(EiiWithGenerics {
307            span: tcx.def_span(external_impl),
308            attr: eii_attr_span,
309            eii_name,
310            impl_name: tcx.item_name(external_impl),
311        });
312    }
313
314    Ok(())
315}
316
317fn check_early_region_bounds<'tcx>(
318    tcx: TyCtxt<'tcx>,
319    external_impl: LocalDefId,
320    declaration: DefId,
321    eii_attr_span: Span,
322) -> Result<(), ErrorGuaranteed> {
323    let external_impl_generics = tcx.generics_of(external_impl.to_def_id());
324    let external_impl_params = external_impl_generics.own_counts().lifetimes;
325
326    let declaration_generics = tcx.generics_of(declaration);
327    let declaration_params = declaration_generics.own_counts().lifetimes;
328
329    let Err(CheckNumberOfEarlyBoundRegionsError { span, generics_span, bounds_span, where_span }) =
330        check_number_of_early_bound_regions(
331            tcx,
332            external_impl,
333            declaration,
334            external_impl_generics,
335            external_impl_params,
336            declaration_generics,
337            declaration_params,
338        )
339    else {
340        return Ok(());
341    };
342
343    let mut diag = tcx.dcx().create_err(LifetimesOrBoundsMismatchOnEii {
344        span,
345        ident: tcx.item_name(external_impl.to_def_id()),
346        generics_span,
347        bounds_span,
348        where_span,
349    });
350
351    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"));
352    return Err(diag.emit());
353}
354
355fn check_number_of_arguments<'tcx>(
356    tcx: TyCtxt<'tcx>,
357    external_impl: LocalDefId,
358    declaration: DefId,
359    eii_name: Symbol,
360    eii_attr_span: Span,
361) -> Result<(), ErrorGuaranteed> {
362    let external_impl_fty = tcx.fn_sig(external_impl);
363    let declaration_fty = tcx.fn_sig(declaration);
364    let declaration_number_args = declaration_fty.skip_binder().inputs().skip_binder().len();
365    let external_impl_number_args = external_impl_fty.skip_binder().inputs().skip_binder().len();
366
367    // if the number of args are equal, we're trivially done
368    if declaration_number_args == external_impl_number_args {
369        Ok(())
370    } else {
371        Err(report_number_of_arguments_mismatch(
372            tcx,
373            external_impl,
374            declaration,
375            eii_name,
376            eii_attr_span,
377            declaration_number_args,
378            external_impl_number_args,
379        ))
380    }
381}
382
383fn report_number_of_arguments_mismatch<'tcx>(
384    tcx: TyCtxt<'tcx>,
385    external_impl: LocalDefId,
386    declaration: DefId,
387    eii_name: Symbol,
388    eii_attr_span: Span,
389    declaration_number_args: usize,
390    external_impl_number_args: usize,
391) -> ErrorGuaranteed {
392    let external_impl_name = tcx.item_name(external_impl.to_def_id());
393
394    let declaration_span = declaration
395        .as_local()
396        .and_then(|def_id| {
397            let declaration_sig = get_declaration_sig(tcx, def_id).expect("foreign item sig");
398            let pos = declaration_number_args.saturating_sub(1);
399            declaration_sig.decl.inputs.get(pos).map(|arg| {
400                if pos == 0 {
401                    arg.span
402                } else {
403                    arg.span.with_lo(declaration_sig.decl.inputs[0].span.lo())
404                }
405            })
406        })
407        .or_else(|| tcx.hir_span_if_local(declaration))
408        .unwrap_or_else(|| tcx.def_span(declaration));
409
410    let (_, external_impl_sig, _, _) = &tcx.hir_expect_item(external_impl).expect_fn();
411    let pos = external_impl_number_args.saturating_sub(1);
412    let impl_span = external_impl_sig
413        .decl
414        .inputs
415        .get(pos)
416        .map(|arg| {
417            if pos == 0 {
418                arg.span
419            } else {
420                arg.span.with_lo(external_impl_sig.decl.inputs[0].span.lo())
421            }
422        })
423        .unwrap_or_else(|| tcx.def_span(external_impl));
424
425    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!(
426        tcx.dcx(),
427        impl_span,
428        E0806,
429        "`{external_impl_name}` has {} but #[{eii_name}] requires it to have {}",
430        potentially_plural_count(external_impl_number_args, "parameter"),
431        declaration_number_args
432    );
433
434    err.span_label(
435        declaration_span,
436        ::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")),
437    );
438
439    err.span_label(
440        impl_span,
441        ::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!(
442            "expected {}, found {}",
443            potentially_plural_count(declaration_number_args, "parameter"),
444            external_impl_number_args
445        ),
446    );
447
448    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"));
449
450    err.emit()
451}
452
453fn report_eii_mismatch<'tcx>(
454    infcx: &InferCtxt<'tcx>,
455    mut cause: ObligationCause<'tcx>,
456    param_env: ty::ParamEnv<'tcx>,
457    terr: TypeError<'tcx>,
458    (declaration_did, declaration_sig): (DefId, ty::FnSig<'tcx>),
459    (external_impl_did, external_impl_sig): (LocalDefId, ty::FnSig<'tcx>),
460    eii_attr_span: Span,
461    eii_name: Symbol,
462) -> ErrorGuaranteed {
463    let tcx = infcx.tcx;
464    let (impl_err_span, trait_err_span, external_impl_name) =
465        extract_spans_for_error_reporting(infcx, terr, &cause, declaration_did, external_impl_did);
466
467    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!(
468        tcx.dcx(),
469        impl_err_span,
470        E0806,
471        "function `{}` has a type that is incompatible with the declaration of `#[{eii_name}]`",
472        external_impl_name
473    );
474
475    diag.span_note(eii_attr_span, "expected this because of this attribute");
476
477    match &terr {
478        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
479            if declaration_sig.inputs().len() == *i {
480                // Suggestion to change output type. We do not suggest in `async` functions
481                // to avoid complex logic or incorrect output.
482                if let ItemKind::Fn { sig, .. } = &tcx.hir_expect_item(external_impl_did).kind
483                    && !sig.header.asyncness.is_async()
484                {
485                    let msg = "change the output type to match the declaration";
486                    let ap = Applicability::MachineApplicable;
487                    match sig.decl.output {
488                        hir::FnRetTy::DefaultReturn(sp) => {
489                            let sugg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" -> {0}",
                declaration_sig.output()))
    })format!(" -> {}", declaration_sig.output());
490                            diag.span_suggestion_verbose(sp, msg, sugg, ap);
491                        }
492                        hir::FnRetTy::Return(hir_ty) => {
493                            let sugg = declaration_sig.output();
494                            diag.span_suggestion_verbose(hir_ty.span, msg, sugg, ap);
495                        }
496                    };
497                };
498            } else if let Some(trait_ty) = declaration_sig.inputs().get(*i) {
499                diag.span_suggestion_verbose(
500                    impl_err_span,
501                    "change the parameter type to match the declaration",
502                    trait_ty,
503                    Applicability::MachineApplicable,
504                );
505            }
506        }
507        _ => {}
508    }
509
510    cause.span = impl_err_span;
511    infcx.err_ctxt().note_type_err(
512        &mut diag,
513        &cause,
514        trait_err_span.map(|sp| (sp, Cow::from("type in declaration"), false)),
515        Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
516            expected: ty::Binder::dummy(declaration_sig),
517            found: ty::Binder::dummy(external_impl_sig),
518        }))),
519        terr,
520        false,
521        None,
522    );
523
524    diag.emit()
525}
526
527#[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(527u32),
                                    ::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))]
528fn extract_spans_for_error_reporting<'tcx>(
529    infcx: &infer::InferCtxt<'tcx>,
530    terr: TypeError<'_>,
531    cause: &ObligationCause<'tcx>,
532    declaration: DefId,
533    external_impl: LocalDefId,
534) -> (Span, Option<Span>, Ident) {
535    let tcx = infcx.tcx;
536    let (mut external_impl_args, external_impl_name) = {
537        let item = tcx.hir_expect_item(external_impl);
538        let (ident, sig, _, _) = item.expect_fn();
539        (sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())), ident)
540    };
541
542    let declaration_args = declaration.as_local().map(|def_id| {
543        if let Some(sig) = get_declaration_sig(tcx, def_id) {
544            sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
545        } else {
546            panic!("expected {def_id:?} to be a foreign function");
547        }
548    });
549
550    match terr {
551        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => (
552            external_impl_args.nth(i).unwrap(),
553            declaration_args.and_then(|mut args| args.nth(i)),
554            external_impl_name,
555        ),
556        _ => (
557            cause.span,
558            tcx.hir_span_if_local(declaration).or_else(|| Some(tcx.def_span(declaration))),
559            external_impl_name,
560        ),
561    }
562}
563
564fn get_declaration_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<&'tcx FnSig<'tcx>> {
565    let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id);
566    tcx.hir_fn_sig_by_hir_id(hir_id)
567}