@@ -380,24 +380,44 @@ pub trait GenericArgsLowerer<'a, 'tcx> {
380380 ) -> ty:: GenericArg < ' tcx > ;
381381}
382382
383- struct ForbidMCGParamUsesFolder < ' tcx > {
383+ /// Context in which `ForbidParamUsesFolder` is being used, to emit appropriate diagnostics.
384+ enum ForbidParamContext {
385+ /// Anon const in a const argument position.
386+ ConstArgument ,
387+ /// Enum discriminant expression.
388+ EnumDiscriminant ,
389+ }
390+
391+ struct ForbidParamUsesFolder < ' tcx > {
384392 tcx : TyCtxt < ' tcx > ,
385393 anon_const_def_id : LocalDefId ,
386394 span : Span ,
387395 is_self_alias : bool ,
396+ context : ForbidParamContext ,
388397}
389398
390- impl < ' tcx > ForbidMCGParamUsesFolder < ' tcx > {
399+ impl < ' tcx > ForbidParamUsesFolder < ' tcx > {
391400 fn error ( & self ) -> ErrorGuaranteed {
392- let msg = if self . is_self_alias {
393- "generic `Self` types are currently not permitted in anonymous constants"
394- } else if self . tcx . features ( ) . generic_const_args ( ) {
395- "generic parameters in const blocks are only allowed as the direct value of a `type const`"
396- } else {
397- "generic parameters may not be used in const operations"
401+ let msg = match self . context {
402+ ForbidParamContext :: EnumDiscriminant if self . is_self_alias => {
403+ "generic `Self` types are not permitted in enum discriminant values"
404+ }
405+ ForbidParamContext :: EnumDiscriminant => {
406+ "generic parameters may not be used in enum discriminant values"
407+ }
408+ ForbidParamContext :: ConstArgument if self . is_self_alias => {
409+ "generic `Self` types are currently not permitted in anonymous constants"
410+ }
411+ ForbidParamContext :: ConstArgument => {
412+ if self . tcx . features ( ) . generic_const_args ( ) {
413+ "generic parameters in const blocks are only allowed as the direct value of a `type const`"
414+ } else {
415+ "generic parameters may not be used in const operations"
416+ }
417+ }
398418 } ;
399419 let mut diag = self . tcx . dcx ( ) . struct_span_err ( self . span , msg) ;
400- if self . is_self_alias {
420+ if self . is_self_alias && matches ! ( self . context , ForbidParamContext :: ConstArgument ) {
401421 let anon_const_hir_id: HirId = HirId :: make_owner ( self . anon_const_def_id ) ;
402422 let parent_impl = self . tcx . hir_parent_owner_iter ( anon_const_hir_id) . find_map (
403423 |( _, node) | match node {
@@ -411,18 +431,20 @@ impl<'tcx> ForbidMCGParamUsesFolder<'tcx> {
411431 diag. span_note ( impl_. self_ty . span , "not a concrete type" ) ;
412432 }
413433 }
414- if self . tcx . features ( ) . min_generic_const_args ( ) {
434+ if matches ! ( self . context, ForbidParamContext :: ConstArgument )
435+ && self . tcx . features ( ) . min_generic_const_args ( )
436+ {
415437 if !self . tcx . features ( ) . generic_const_args ( ) {
416438 diag. help ( "add `#![feature(generic_const_args)]` to allow generic expressions as the RHS of const items" ) ;
417439 } else {
418440 diag. help ( "consider factoring the expression into a `type const` item and use it as the const argument instead" ) ;
419441 }
420- } ;
442+ }
421443 diag. emit ( )
422444 }
423445}
424446
425- impl < ' tcx > ty:: TypeFolder < TyCtxt < ' tcx > > for ForbidMCGParamUsesFolder < ' tcx > {
447+ impl < ' tcx > ty:: TypeFolder < TyCtxt < ' tcx > > for ForbidParamUsesFolder < ' tcx > {
426448 fn cx ( & self ) -> TyCtxt < ' tcx > {
427449 self . tcx
428450 }
@@ -464,37 +486,80 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
464486 && tcx. def_kind ( parent_def_id) == DefKind :: AnonConst
465487 && let ty:: AnonConstKind :: MCG = tcx. anon_const_kind ( parent_def_id)
466488 {
467- let folder = ForbidMCGParamUsesFolder {
489+ let folder = ForbidParamUsesFolder {
468490 tcx,
469491 anon_const_def_id : parent_def_id,
470492 span,
471493 is_self_alias : false ,
494+ context : ForbidParamContext :: ConstArgument ,
472495 } ;
473496 return Err ( folder. error ( ) ) ;
474497 }
475498 Ok ( ( ) )
476499 }
477500
501+ /// Returns the `ForbidParamContext` for the current anon const if it is a context that
502+ /// forbids uses of generic parameters. `None` if the current item is not such a context.
503+ ///
504+ /// Name resolution handles most invalid generic parameter uses in these contexts, but it
505+ /// cannot reject `Self` that aliases a generic type, nor generic parameters introduced by
506+ /// type-dependent name resolution (e.g. `<Self as Trait>::Assoc` resolving to a type that
507+ /// contains params). Those cases are handled by `check_param_uses_if_mcg`.
508+ fn anon_const_forbids_generic_params ( & self ) -> Option < ForbidParamContext > {
509+ let tcx = self . tcx ( ) ;
510+ let parent_def_id = self . item_def_id ( ) ;
511+
512+ // Inline consts and closures can be nested inside anon consts that forbid generic
513+ // params (e.g. an enum discriminant). Walk up the def parent chain to find the
514+ // nearest enclosing AnonConst and use that to determine the context.
515+ let anon_const_def_id = match tcx. def_kind ( parent_def_id) {
516+ DefKind :: AnonConst => parent_def_id,
517+ DefKind :: InlineConst | DefKind :: Closure => {
518+ let root = tcx. typeck_root_def_id ( parent_def_id. into ( ) ) ;
519+ match tcx. def_kind ( root) {
520+ DefKind :: AnonConst => root. expect_local ( ) ,
521+ _ => return None ,
522+ }
523+ }
524+ _ => return None ,
525+ } ;
526+
527+ match tcx. anon_const_kind ( anon_const_def_id) {
528+ ty:: AnonConstKind :: MCG => Some ( ForbidParamContext :: ConstArgument ) ,
529+ ty:: AnonConstKind :: NonTypeSystem => {
530+ // NonTypeSystem anon consts only have accessible generic parameters in specific
531+ // positions (ty patterns and field defaults — see `generics_of`). In all other
532+ // positions (e.g. enum discriminants) generic parameters are not in scope.
533+ if tcx. generics_of ( anon_const_def_id) . count ( ) == 0 {
534+ Some ( ForbidParamContext :: EnumDiscriminant )
535+ } else {
536+ None
537+ }
538+ }
539+ ty:: AnonConstKind :: GCE
540+ | ty:: AnonConstKind :: GCA
541+ | ty:: AnonConstKind :: RepeatExprCount => None ,
542+ }
543+ }
544+
478545 /// Check for uses of generic parameters that are not in scope due to this being
479- /// in a non-generic anon const context.
546+ /// in a non-generic anon const context (e.g. MCG or an enum discriminant).
547+ ///
548+ /// Name resolution rejects most invalid uses, but cannot handle `Self` aliasing a
549+ /// generic type or generic parameters introduced by type-dependent name resolution.
480550 #[ must_use = "need to use transformed output" ]
481551 fn check_param_uses_if_mcg < T > ( & self , term : T , span : Span , is_self_alias : bool ) -> T
482552 where
483553 T : ty:: TypeFoldable < TyCtxt < ' tcx > > ,
484554 {
485555 let tcx = self . tcx ( ) ;
486- let parent_def_id = self . item_def_id ( ) ;
487- if tcx. def_kind ( parent_def_id) == DefKind :: AnonConst
488- && let ty:: AnonConstKind :: MCG = tcx. anon_const_kind ( parent_def_id)
556+ if let Some ( context) = self . anon_const_forbids_generic_params ( )
489557 // Fast path if contains no params/escaping bound vars.
490558 && ( term. has_param ( ) || term. has_escaping_bound_vars ( ) )
491559 {
492- let mut folder = ForbidMCGParamUsesFolder {
493- tcx,
494- anon_const_def_id : parent_def_id,
495- span,
496- is_self_alias,
497- } ;
560+ let anon_const_def_id = self . item_def_id ( ) ;
561+ let mut folder =
562+ ForbidParamUsesFolder { tcx, anon_const_def_id, span, is_self_alias, context } ;
498563 term. fold_with ( & mut folder)
499564 } else {
500565 term
0 commit comments