Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,9 +614,10 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
if !infer_replacements.is_empty() {
diag.multipart_suggestion(
format!(
"try replacing `_` with the type{} in the corresponding trait method signature",
rustc_errors::pluralize!(infer_replacements.len()),
),
"try replacing `_` with the type{} in the corresponding trait method \
signature",
rustc_errors::pluralize!(infer_replacements.len()),
),
infer_replacements,
Applicability::MachineApplicable,
);
Expand Down
55 changes: 38 additions & 17 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rustc_errors::{
Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err,
};
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_middle::bug;
use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
Expand Down Expand Up @@ -1027,7 +1027,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
err_extend: GenericsArgsErrExtend<'_>,
err_extend: GenericsArgsErrExtend<'a>,
) -> ErrorGuaranteed {
#[derive(PartialEq, Eq, Hash)]
enum ProhibitGenericsArg {
Expand All @@ -1047,23 +1047,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};
});

let segments: Vec<_> = segments.collect();
let types_and_spans: Vec<_> = segments
.clone()
.iter()
.flat_map(|segment| {
if segment.args().args.is_empty() {
None
} else {
Some((
match segment.res {
hir::def::Res::PrimTy(ty) => {
Res::PrimTy(ty) => {
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) =>
{
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.ident.span,
Expand All @@ -1074,11 +1075,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let this_type = listify(&types_and_spans, |(t, _)| t.to_string())
.expect("expected one segment to deny");

let arg_spans: Vec<Span> = segments
.clone()
.flat_map(|segment| segment.args().args)
.map(|arg| arg.span())
.collect();
let arg_spans: Vec<Span> =
segments.iter().flat_map(|segment| segment.args().args).map(|arg| arg.span()).collect();

let mut kinds = Vec::with_capacity(4);
prohibit_args.iter().for_each(|arg| match arg {
Expand All @@ -1103,7 +1101,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
for (what, span) in types_and_spans {
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()
}

Expand Down Expand Up @@ -1400,15 +1398,15 @@ pub enum GenericsArgsErrExtend<'tcx> {
},
SelfTyParam(Span),
Param(DefId),
DefVariant,
DefVariant(&'tcx [hir::PathSegment<'tcx>]),
None,
}

fn generics_args_err_extend<'a>(
tcx: TyCtxt<'_>,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
err: &mut Diag<'_>,
err_extend: GenericsArgsErrExtend<'_>,
err_extend: GenericsArgsErrExtend<'a>,
) {
match err_extend {
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => {
Expand Down Expand Up @@ -1496,6 +1494,32 @@ fn generics_args_err_extend<'a>(
];
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()
{
err.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",
);
err.span_suggestion_verbose(
span,
"remove the generics arguments from one of the path segments",
String::new(),
Applicability::MaybeIncorrect,
);
}
}
GenericsArgsErrExtend::PrimTy(prim_ty) => {
let name = prim_ty.name_str();
for segment in segments {
Expand All @@ -1512,9 +1536,6 @@ fn generics_args_err_extend<'a>(
GenericsArgsErrExtend::OpaqueTy => {
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) => {
let span = tcx.def_ident_span(def_id).unwrap();
let kind = tcx.def_descr(def_id);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1694,7 +1694,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
pub fn prohibit_generic_args<'a>(
&self,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
err_extend: GenericsArgsErrExtend<'_>,
err_extend: GenericsArgsErrExtend<'a>,
) -> Result<(), ErrorGuaranteed> {
let args_visitors = segments.clone().flat_map(|segment| segment.args().args);
let mut result = Ok(());
Expand Down Expand Up @@ -1911,7 +1911,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
path.segments.iter().enumerate().filter_map(|(index, seg)| {
if !indices.contains(&index) { Some(seg) } else { None }
}),
GenericsArgsErrExtend::DefVariant,
GenericsArgsErrExtend::DefVariant(&path.segments),
);

let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1043,12 +1043,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

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

if let Res::Local(hid) = res {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,13 @@ LL | Enum::<()>::TSVariant::<()>(());
| --------- ^^ type argument not allowed
| |
| not allowed on tuple variant `TSVariant`
|
= 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
--> $DIR/enum-variant-generic-args.rs:57:24
Expand Down Expand Up @@ -354,7 +361,12 @@ LL | Enum::<()>::SVariant::<()> { v: () };
| |
| not allowed on variant `SVariant`
|
= note: enum variants can't have type parameters
= 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: () };
|

error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:75:23
Expand Down Expand Up @@ -451,6 +463,13 @@ LL | Enum::<()>::UVariant::<()>;
| -------- ^^ type argument not allowed
| |
| not allowed on unit variant `UVariant`
|
= 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
--> $DIR/enum-variant-generic-args.rs:93:23
Expand Down
Loading