mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
ensure generics are still properly reported on EII *implementations*, and test this
This commit is contained in:
@@ -165,6 +165,11 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
|
||||
hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
|
||||
.label = parameter captured again here
|
||||
|
||||
hir_analysis_eii_with_generics =
|
||||
`{$impl_name}` cannot have generic parameters other than lifetimes
|
||||
.label = required by this attribute
|
||||
.help = `#[{$eii_name}]` marks the implementation of an "externally implementable item"
|
||||
|
||||
hir_analysis_empty_specialization = specialization impl does not specialize any associated items
|
||||
.note = impl is a specialization of this impl
|
||||
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{Applicability, E0806, struct_span_code_err};
|
||||
use rustc_hir::attrs::{AttributeKind, EiiImplResolution};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{self as hir, FnSig, HirId, ItemKind};
|
||||
use rustc_hir::{self as hir, FnSig, HirId, ItemKind, find_attr};
|
||||
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
@@ -24,7 +25,7 @@
|
||||
use crate::check::compare_impl_item::{
|
||||
CheckNumberOfEarlyBoundRegionsError, check_number_of_early_bound_regions,
|
||||
};
|
||||
use crate::errors::LifetimesOrBoundsMismatchOnEii;
|
||||
use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii};
|
||||
|
||||
/// Checks whether the signature of some `external_impl`, matches
|
||||
/// the signature of `declaration`, which it is supposed to be compatible
|
||||
@@ -154,11 +155,44 @@ fn check_is_structurally_compatible<'tcx>(
|
||||
eii_name: Symbol,
|
||||
eii_attr_span: Span,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
|
||||
check_number_of_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
|
||||
check_early_region_bounds(tcx, external_impl, declaration, eii_attr_span)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// externally implementable items can't have generics
|
||||
fn check_no_generics<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
external_impl: LocalDefId,
|
||||
_declaration: DefId,
|
||||
eii_name: Symbol,
|
||||
eii_attr_span: Span,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let generics = tcx.generics_of(external_impl);
|
||||
if generics.own_requires_monomorphization()
|
||||
// When an EII implementation is automatically generated by the `#[eii]` macro,
|
||||
// it will directly refer to the foreign item, not through a macro.
|
||||
// We don't want to emit this error if it's an implementation that's generated by the `#[eii]` macro,
|
||||
// since in that case it looks like a duplicate error: the declaration of the EII already can't contain generics.
|
||||
// So, we check here if at least one of the eii impls has ImplResolution::Macro, which indicates it's
|
||||
// not generated as part of the declaration.
|
||||
&& find_attr!(
|
||||
tcx.get_all_attrs(external_impl),
|
||||
AttributeKind::EiiImpls(impls) if impls.iter().any(|i| matches!(i.resolution, EiiImplResolution::Macro(_)))
|
||||
)
|
||||
{
|
||||
tcx.dcx().emit_err(EiiWithGenerics {
|
||||
span: tcx.def_span(external_impl),
|
||||
attr: eii_attr_span,
|
||||
eii_name,
|
||||
impl_name: tcx.item_name(external_impl),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_early_region_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
external_impl: LocalDefId,
|
||||
|
||||
@@ -1652,3 +1652,15 @@ pub(crate) struct LifetimesOrBoundsMismatchOnEii {
|
||||
pub bounds_span: Vec<Span>,
|
||||
pub ident: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_eii_with_generics)]
|
||||
#[help]
|
||||
pub(crate) struct EiiWithGenerics {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub attr: Span,
|
||||
pub eii_name: Symbol,
|
||||
pub impl_name: Symbol,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
//@ check-fail
|
||||
// Check that type parameters on EIIs are properly rejected.
|
||||
// Specifically a regression test for https://github.com/rust-lang/rust/issues/149983.
|
||||
#![feature(extern_item_impls)]
|
||||
|
||||
#[eii]
|
||||
fn foo();
|
||||
|
||||
#[foo]
|
||||
fn foo_impl<T>() {}
|
||||
//~^ ERROR `foo_impl` cannot have generic parameters other than lifetimes
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,12 @@
|
||||
error: `foo_impl` cannot have generic parameters other than lifetimes
|
||||
--> $DIR/generic_implementation.rs:10:1
|
||||
|
|
||||
LL | #[foo]
|
||||
| ------ required by this attribute
|
||||
LL | fn foo_impl<T>() {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: `#[foo]` marks the implementation of an "externally implementable item"
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
Reference in New Issue
Block a user