Skip to main content

rustc_hir_analysis/check/
compare_eii.rs

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

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: (Span, Option<Span>, Ident) =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            let tcx = infcx.tcx;
            let (mut external_impl_args, external_impl_name) =
                {
                    let item = tcx.hir_expect_item(external_impl);
                    let (ident, sig, _, _) = item.expect_fn();
                    (sig.decl.inputs.iter().map(|t|
                                    t.span).chain(iter::once(sig.decl.output.span())), ident)
                };
            let declaration_args =
                declaration.as_local().map(|def_id|
                        {
                            if let Some(sig) = get_declaration_sig(tcx, def_id) {
                                sig.decl.inputs.iter().map(|t|
                                            t.span).chain(iter::once(sig.decl.output.span()))
                            } else {
                                {
                                    ::core::panicking::panic_fmt(format_args!("expected {0:?} to be a foreign function",
                                            def_id));
                                };
                            }
                        });
            match terr {
                TypeError::ArgumentMutability(i) |
                    TypeError::ArgumentSorts(ExpectedFound { .. }, i) =>
                    (external_impl_args.nth(i).unwrap(),
                        declaration_args.and_then(|mut args| args.nth(i)),
                        external_impl_name),
                _ =>
                    (cause.span,
                        tcx.hir_span_if_local(declaration).or_else(||
                                Some(tcx.def_span(declaration))), external_impl_name),
            }
        }
    }
}#[instrument(level = "debug", skip(infcx))]
522fn extract_spans_for_error_reporting<'tcx>(
523    infcx: &infer::InferCtxt<'tcx>,
524    terr: TypeError<'_>,
525    cause: &ObligationCause<'tcx>,
526    declaration: DefId,
527    external_impl: LocalDefId,
528) -> (Span, Option<Span>, Ident) {
529    let tcx = infcx.tcx;
530    let (mut external_impl_args, external_impl_name) = {
531        let item = tcx.hir_expect_item(external_impl);
532        let (ident, sig, _, _) = item.expect_fn();
533        (sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())), ident)
534    };
535
536    let declaration_args = declaration.as_local().map(|def_id| {
537        if let Some(sig) = get_declaration_sig(tcx, def_id) {
538            sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
539        } else {
540            panic!("expected {def_id:?} to be a foreign function");
541        }
542    });
543
544    match terr {
545        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => (
546            external_impl_args.nth(i).unwrap(),
547            declaration_args.and_then(|mut args| args.nth(i)),
548            external_impl_name,
549        ),
550        _ => (
551            cause.span,
552            tcx.hir_span_if_local(declaration).or_else(|| Some(tcx.def_span(declaration))),
553            external_impl_name,
554        ),
555    }
556}
557
558fn get_declaration_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<&'tcx FnSig<'tcx>> {
559    let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id);
560    tcx.hir_fn_sig_by_hir_id(hir_id)
561}