Explain that in paths generics can't be set on both the enum and the variant

```
error[E0109]: type arguments are not allowed on enum `Enum` and tuple variant `TSVariant`
  --> $DIR/enum-variant-generic-args.rs:54:12
   |
LL |     Enum::<()>::TSVariant::<()>(());
   |     ----   ^^   ---------   ^^ type argument not allowed
   |     |           |
   |     |           not allowed on tuple variant `TSVariant`
   |     not allowed on enum `Enum`
   |
   = note: generic arguments are not allowed on both an enum and its variant's path segments simultaneously; they are only valid in one place or the other
help: remove the generics arguments from one of the path segments
   |
LL -     Enum::<()>::TSVariant::<()>(());
LL +     Enum::<()>::TSVariant(());
   |
```

Fix #93993.
This commit is contained in:
Esteban Küber 2024-12-31 18:51:36 +00:00
parent 06a24e98c6
commit 1b98d0ed13
6 changed files with 94 additions and 42 deletions

View File

@ -614,9 +614,10 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
if !infer_replacements.is_empty() { if !infer_replacements.is_empty() {
diag.multipart_suggestion( diag.multipart_suggestion(
format!( format!(
"try replacing `_` with the type{} in the corresponding trait method signature", "try replacing `_` with the type{} in the corresponding trait method \
rustc_errors::pluralize!(infer_replacements.len()), signature",
), rustc_errors::pluralize!(infer_replacements.len()),
),
infer_replacements, infer_replacements,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );

View File

@ -6,7 +6,7 @@ use rustc_errors::{
Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err,
}; };
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::fast_reject::{TreatParams, simplify_type}; use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
@ -1027,7 +1027,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self, &self,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone, segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone, args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
err_extend: GenericsArgsErrExtend<'_>, err_extend: GenericsArgsErrExtend<'a>,
) -> ErrorGuaranteed { ) -> ErrorGuaranteed {
#[derive(PartialEq, Eq, Hash)] #[derive(PartialEq, Eq, Hash)]
enum ProhibitGenericsArg { enum ProhibitGenericsArg {
@ -1047,23 +1047,27 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}; };
}); });
let segments: Vec<_> = match err_extend {
GenericsArgsErrExtend::DefVariant(segments) => segments.iter().collect(),
_ => segments.collect(),
};
let types_and_spans: Vec<_> = segments let types_and_spans: Vec<_> = segments
.clone() .iter()
.flat_map(|segment| { .flat_map(|segment| {
if segment.args().args.is_empty() { if segment.args().args.is_empty() {
None None
} else { } else {
Some(( Some((
match segment.res { match segment.res {
hir::def::Res::PrimTy(ty) => { Res::PrimTy(ty) => {
format!("{} `{}`", segment.res.descr(), ty.name()) format!("{} `{}`", segment.res.descr(), ty.name())
} }
hir::def::Res::Def(_, def_id) Res::Def(_, def_id)
if let Some(name) = self.tcx().opt_item_name(def_id) => if let Some(name) = self.tcx().opt_item_name(def_id) =>
{ {
format!("{} `{name}`", segment.res.descr()) format!("{} `{name}`", segment.res.descr())
} }
hir::def::Res::Err => "this type".to_string(), Res::Err => "this type".to_string(),
_ => segment.res.descr().to_string(), _ => segment.res.descr().to_string(),
}, },
segment.ident.span, segment.ident.span,
@ -1074,11 +1078,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let this_type = listify(&types_and_spans, |(t, _)| t.to_string()) let this_type = listify(&types_and_spans, |(t, _)| t.to_string())
.expect("expected one segment to deny"); .expect("expected one segment to deny");
let arg_spans: Vec<Span> = segments let arg_spans: Vec<Span> =
.clone() segments.iter().flat_map(|segment| segment.args().args).map(|arg| arg.span()).collect();
.flat_map(|segment| segment.args().args)
.map(|arg| arg.span())
.collect();
let mut kinds = Vec::with_capacity(4); let mut kinds = Vec::with_capacity(4);
prohibit_args.iter().for_each(|arg| match arg { prohibit_args.iter().for_each(|arg| match arg {
@ -1103,7 +1104,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
for (what, span) in types_and_spans { for (what, span) in types_and_spans {
err.span_label(span, format!("not allowed on {what}")); err.span_label(span, format!("not allowed on {what}"));
} }
generics_args_err_extend(self.tcx(), segments, &mut err, err_extend); generics_args_err_extend(self.tcx(), segments.into_iter(), &mut err, err_extend);
err.emit() err.emit()
} }
@ -1400,7 +1401,7 @@ pub enum GenericsArgsErrExtend<'tcx> {
}, },
SelfTyParam(Span), SelfTyParam(Span),
Param(DefId), Param(DefId),
DefVariant, DefVariant(&'tcx [hir::PathSegment<'tcx>]),
None, None,
} }
@ -1408,7 +1409,7 @@ fn generics_args_err_extend<'a>(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone, segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
err: &mut Diag<'_>, err: &mut Diag<'_>,
err_extend: GenericsArgsErrExtend<'_>, err_extend: GenericsArgsErrExtend<'a>,
) { ) {
match err_extend { match err_extend {
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => { GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => {
@ -1496,6 +1497,32 @@ fn generics_args_err_extend<'a>(
]; ];
err.multipart_suggestion_verbose(msg, suggestion, Applicability::MaybeIncorrect); err.multipart_suggestion_verbose(msg, suggestion, Applicability::MaybeIncorrect);
} }
GenericsArgsErrExtend::DefVariant(segments) => {
let args: Vec<Span> = segments
.iter()
.filter_map(|segment| match segment.res {
Res::Def(
DefKind::Ctor(CtorOf::Variant, _) | DefKind::Variant | DefKind::Enum,
_,
) => segment.args().span_ext().map(|s| s.with_lo(segment.ident.span.hi())),
_ => None,
})
.collect();
if args.len() > 1
&& let Some(span) = args.into_iter().last()
{
let msg = "generic arguments are not allowed on both an enum and its variant's \
path segments simultaneously; they are only valid in one place or the \
other";
err.note(msg);
err.span_suggestion_verbose(
span,
"remove the generics arguments from one of the path segments",
String::new(),
Applicability::MaybeIncorrect,
);
}
}
GenericsArgsErrExtend::PrimTy(prim_ty) => { GenericsArgsErrExtend::PrimTy(prim_ty) => {
let name = prim_ty.name_str(); let name = prim_ty.name_str();
for segment in segments { for segment in segments {
@ -1512,9 +1539,6 @@ fn generics_args_err_extend<'a>(
GenericsArgsErrExtend::OpaqueTy => { GenericsArgsErrExtend::OpaqueTy => {
err.note("`impl Trait` types can't have type parameters"); err.note("`impl Trait` types can't have type parameters");
} }
GenericsArgsErrExtend::DefVariant => {
err.note("enum variants can't have type parameters");
}
GenericsArgsErrExtend::Param(def_id) => { GenericsArgsErrExtend::Param(def_id) => {
let span = tcx.def_ident_span(def_id).unwrap(); let span = tcx.def_ident_span(def_id).unwrap();
let kind = tcx.def_descr(def_id); let kind = tcx.def_descr(def_id);

View File

@ -1694,7 +1694,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
pub fn prohibit_generic_args<'a>( pub fn prohibit_generic_args<'a>(
&self, &self,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone, segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
err_extend: GenericsArgsErrExtend<'_>, err_extend: GenericsArgsErrExtend<'a>,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let args_visitors = segments.clone().flat_map(|segment| segment.args().args); let args_visitors = segments.clone().flat_map(|segment| segment.args().args);
let mut result = Ok(()); let mut result = Ok(());
@ -1911,7 +1911,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
path.segments.iter().enumerate().filter_map(|(index, seg)| { path.segments.iter().enumerate().filter_map(|(index, seg)| {
if !indices.contains(&index) { Some(seg) } else { None } if !indices.contains(&index) { Some(seg) } else { None }
}), }),
GenericsArgsErrExtend::DefVariant, GenericsArgsErrExtend::DefVariant(&path.segments),
); );
let GenericPathSegment(def_id, index) = generic_segments.last().unwrap(); let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();

View File

@ -1043,12 +1043,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut user_self_ty = None; let mut user_self_ty = None;
let mut is_alias_variant_ctor = false; let mut is_alias_variant_ctor = false;
let mut err_extend = GenericsArgsErrExtend::None;
match res { match res {
Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) if let Some(self_ty) = self_ty => { Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) if let Some(self_ty) = self_ty => {
let adt_def = self_ty.normalized.ty_adt_def().unwrap(); let adt_def = self_ty.normalized.ty_adt_def().unwrap();
user_self_ty = user_self_ty =
Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty: self_ty.raw }); Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty: self_ty.raw });
is_alias_variant_ctor = true; is_alias_variant_ctor = true;
err_extend = GenericsArgsErrExtend::DefVariant(segments);
}
Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => {
err_extend = GenericsArgsErrExtend::DefVariant(segments);
} }
Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
let assoc_item = tcx.associated_item(def_id); let assoc_item = tcx.associated_item(def_id);
@ -1095,7 +1100,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
segments.iter().enumerate().filter_map(|(index, seg)| { segments.iter().enumerate().filter_map(|(index, seg)| {
if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None } if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None }
}), }),
GenericsArgsErrExtend::None, err_extend,
); );
if let Res::Local(hid) = res { if let Res::Local(hid) = res {

View File

@ -52,7 +52,7 @@ fn main() {
// Tuple struct variant // Tuple struct variant
Enum::<()>::TSVariant::<()>(()); Enum::<()>::TSVariant::<()>(());
//~^ ERROR type arguments are not allowed on tuple variant `TSVariant` [E0109] //~^ ERROR type arguments are not allowed on enum `Enum` and tuple variant `TSVariant` [E0109]
Alias::TSVariant::<()>(()); Alias::TSVariant::<()>(());
//~^ ERROR type arguments are not allowed on this type [E0109] //~^ ERROR type arguments are not allowed on this type [E0109]
@ -70,7 +70,7 @@ fn main() {
// Struct variant // Struct variant
Enum::<()>::SVariant::<()> { v: () }; Enum::<()>::SVariant::<()> { v: () };
//~^ ERROR type arguments are not allowed on variant `SVariant` [E0109] //~^ ERROR type arguments are not allowed on enum `Enum` and variant `SVariant` [E0109]
Alias::SVariant::<()> { v: () }; Alias::SVariant::<()> { v: () };
//~^ ERROR type arguments are not allowed on this type [E0109] //~^ ERROR type arguments are not allowed on this type [E0109]
@ -88,7 +88,7 @@ fn main() {
// Unit variant // Unit variant
Enum::<()>::UVariant::<()>; Enum::<()>::UVariant::<()>;
//~^ ERROR type arguments are not allowed on unit variant `UVariant` [E0109] //~^ ERROR type arguments are not allowed on enum `Enum` and unit variant `UVariant` [E0109]
Alias::UVariant::<()>; Alias::UVariant::<()>;
//~^ ERROR type arguments are not allowed on this type [E0109] //~^ ERROR type arguments are not allowed on this type [E0109]

View File

@ -278,13 +278,21 @@ LL | Self::<()>::UVariant::<()>;
| | | |
| not allowed on this type | not allowed on this type
error[E0109]: type arguments are not allowed on tuple variant `TSVariant` error[E0109]: type arguments are not allowed on enum `Enum` and tuple variant `TSVariant`
--> $DIR/enum-variant-generic-args.rs:54:29 --> $DIR/enum-variant-generic-args.rs:54:12
| |
LL | Enum::<()>::TSVariant::<()>(()); LL | Enum::<()>::TSVariant::<()>(());
| --------- ^^ type argument not allowed | ---- ^^ --------- ^^ type argument not allowed
| | | | |
| not allowed on tuple variant `TSVariant` | | not allowed on tuple variant `TSVariant`
| not allowed on enum `Enum`
|
= note: generic arguments are not allowed on both an enum and its variant's path segments simultaneously; they are only valid in one place or the other
help: remove the generics arguments from one of the path segments
|
LL - Enum::<()>::TSVariant::<()>(());
LL + Enum::<()>::TSVariant(());
|
error[E0109]: type arguments are not allowed on this type error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:57:24 --> $DIR/enum-variant-generic-args.rs:57:24
@ -346,15 +354,21 @@ LL | AliasFixed::<()>::TSVariant::<()>(());
| | | |
| not allowed on this type | not allowed on this type
error[E0109]: type arguments are not allowed on variant `SVariant` error[E0109]: type arguments are not allowed on enum `Enum` and variant `SVariant`
--> $DIR/enum-variant-generic-args.rs:72:28 --> $DIR/enum-variant-generic-args.rs:72:12
| |
LL | Enum::<()>::SVariant::<()> { v: () }; LL | Enum::<()>::SVariant::<()> { v: () };
| -------- ^^ type argument not allowed | ---- ^^ -------- ^^ type argument not allowed
| | | | |
| not allowed on variant `SVariant` | | not allowed on variant `SVariant`
| not allowed on enum `Enum`
|
= note: generic arguments are not allowed on both an enum and its variant's path segments simultaneously; they are only valid in one place or the other
help: remove the generics arguments from one of the path segments
|
LL - Enum::<()>::SVariant::<()> { v: () };
LL + Enum::<()>::SVariant { v: () };
| |
= note: enum variants can't have type parameters
error[E0109]: type arguments are not allowed on this type error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:75:23 --> $DIR/enum-variant-generic-args.rs:75:23
@ -444,13 +458,21 @@ LL - AliasFixed::<()>::SVariant::<()> { v: () };
LL + AliasFixed::<()>::SVariant { v: () }; LL + AliasFixed::<()>::SVariant { v: () };
| |
error[E0109]: type arguments are not allowed on unit variant `UVariant` error[E0109]: type arguments are not allowed on enum `Enum` and unit variant `UVariant`
--> $DIR/enum-variant-generic-args.rs:90:28 --> $DIR/enum-variant-generic-args.rs:90:12
| |
LL | Enum::<()>::UVariant::<()>; LL | Enum::<()>::UVariant::<()>;
| -------- ^^ type argument not allowed | ---- ^^ -------- ^^ type argument not allowed
| | | | |
| not allowed on unit variant `UVariant` | | not allowed on unit variant `UVariant`
| not allowed on enum `Enum`
|
= note: generic arguments are not allowed on both an enum and its variant's path segments simultaneously; they are only valid in one place or the other
help: remove the generics arguments from one of the path segments
|
LL - Enum::<()>::UVariant::<()>;
LL + Enum::<()>::UVariant;
|
error[E0109]: type arguments are not allowed on this type error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:93:23 --> $DIR/enum-variant-generic-args.rs:93:23