1use 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
34pub(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 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 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 wf_tys.extend(declaration_sig.inputs_and_output.iter());
90 let declaration_sig = ocx.normalize(&norm_cause, param_env, declaration_sig);
91 wf_tys.extend(external_impl_sig.inputs_and_output.iter());
94
95 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 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 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 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 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 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 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 _ 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 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 _ => Err(tcx.dcx().delayed_bug("Attribute should not be allowed by target checking")),
260 }
261}
262
263fn 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
281fn 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 && {
{
'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 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 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}