diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a43e373415ab7..11cd408000c93 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2174,28 +2174,51 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Case 2. Reference to a variant constructor. DefKind::Ctor(CtorOf::Variant, ..) | DefKind::Variant => { let (generics_def_id, index) = if let Some(self_ty) = self_ty { + // We have something like `::Variant`. + let adt_def = self.probe_adt(span, self_ty).unwrap(); debug_assert!(adt_def.is_enum()); + + // FIXME: Stating that the last segment (here: `Variant`) is allowed to have + // generic args is a lie! We should set the index to `None` instead as it's + // the *self type* that's allowed to have args. + // HIR typeck's `instantiate_value_path` actually contains a special case to + // reject args on `DefKind::Ctor` segments (see `is_alias_variant_ctor`). + // Using `None` here for this should allow us to get rid of that workaround. + // + // (For additional context, `DefKind::Variant` segments never actually reach + // this branch as they're interpreted as `TypeRelative` paths whose lowering + // routines manually reject args on them). + (adt_def.did(), last) - } else if last >= 1 && segments[last - 1].args.is_some() { - // Everything but the penultimate segment should have no - // parameters at all. - let mut def_id = def_id; + } else if let [.., second_to_last, _] = segments + && second_to_last.args.is_some() + && let Res::Def(DefKind::Enum, _) = second_to_last.res + { + // We have something like `module::Enum::<…>::Variant`. + // No segment other than the penultimate one is allowed to have generic args. + + // We had to check that the second to last segment actually referred to an enum + // since at this stage it could very well refer to a module in which case we + // certainly don't want to allow generic args on it! // `DefKind::Ctor` -> `DefKind::Variant` - if let DefKind::Ctor(..) = kind { - def_id = tcx.parent(def_id); - } + let def_id = match kind { + DefKind::Ctor(..) => tcx.parent(def_id), + _ => def_id, + }; // `DefKind::Variant` -> `DefKind::Enum` let enum_def_id = tcx.parent(def_id); + (enum_def_id, last - 1) } else { + // We have something like `module::Enum::Variant` or `module::Variant`. + // No segment other than the final one is allowed to have generic args. + // FIXME: lint here recommending `Enum::<...>::Variant` form // instead of `Enum::Variant::<...>` form. - // Everything but the final segment should have no - // parameters at all. let generics = tcx.generics_of(def_id); // Variant and struct constructors use the // generics of their parent type definition. diff --git a/tests/ui/enum/enum-variant-generic-args-in-module-segment.rs b/tests/ui/enum/enum-variant-generic-args-in-module-segment.rs new file mode 100644 index 0000000000000..0b14426983f9c --- /dev/null +++ b/tests/ui/enum/enum-variant-generic-args-in-module-segment.rs @@ -0,0 +1,19 @@ +// Test that we don't assume that the penultimate segment of an enum variant path refers to the +// enum just because it has generic arguments. +// +// We once used to accept the code below interpreting `module::::Variant` +// as `module::Variant::` basically. +// +// issue: + +enum Enum { Variant, Carry(T) } + +mod module { pub(super) use super::Enum::Variant; } + +fn main() { + let _ = module::::Variant; + //~^ ERROR type arguments are not allowed on module `module` + + let _ = self::module::<()>::Variant {}; + //~^ ERROR type arguments are not allowed on module `module` +} diff --git a/tests/ui/enum/enum-variant-generic-args-in-module-segment.stderr b/tests/ui/enum/enum-variant-generic-args-in-module-segment.stderr new file mode 100644 index 0000000000000..fa44f28ebe65e --- /dev/null +++ b/tests/ui/enum/enum-variant-generic-args-in-module-segment.stderr @@ -0,0 +1,19 @@ +error[E0109]: type arguments are not allowed on module `module` + --> $DIR/enum-variant-generic-args-in-module-segment.rs:14:22 + | +LL | let _ = module::::Variant; + | ------ ^^^ type argument not allowed + | | + | not allowed on module `module` + +error[E0109]: type arguments are not allowed on module `module` + --> $DIR/enum-variant-generic-args-in-module-segment.rs:17:28 + | +LL | let _ = self::module::<()>::Variant {}; + | ------ ^^ type argument not allowed + | | + | not allowed on module `module` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0109`.