Skip to content

Commit 58bdb08

Browse files
committed
Auto merge of #84299 - lcnr:const-generics-defaults-name-res, r=varkor
various const parameter defaults improvements Actually resolve names in const parameter defaults, fixing `struct Foo<const N: usize = { usize::MAX }>`. --- Split generic parameter ban rib for types and consts, allowing ```rust #![feature(const_generics_defaults)] struct Q; struct Foo<T = Q, const Q: usize = 3>(T); ``` --- Remove the type/const ordering restriction if `const_generics_defaults` is active, even if `const_generics` is not. allowing us to stabilize and test const param defaults separately. --- Check well formedness of const parameter defaults, eagerly emitting an error for `struct Foo<const N: usize = { 0 - 1 }>` --- Do not forbid const parameters in param defaults, allowing `struct Foo<const N: usize, T = [u8; N]>(T)` and `struct Foo<const N: usize, const M: usize = N>`. Note that this should not change anything which is stabilized, as on stable, type parameters must be in front of const parameters, which means that type parameter defaults are only allowed if no const parameters exist. We still forbid generic parameters inside of const param types. r? `@varkor` `@petrochenkov`
2 parents 06f0adb + d3e0d2f commit 58bdb08

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+386
-218
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ fn validate_generic_param_order(
754754
GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
755755
GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
756756
let ty = pprust::ty_to_string(ty);
757-
let unordered = sess.features_untracked().const_generics;
757+
let unordered = sess.features_untracked().unordered_const_ty_params();
758758
(ParamKindOrd::Const { unordered }, Some(format!("const {}: {}", param.ident, ty)))
759759
}
760760
};

compiler/rustc_feature/src/active.rs

+4
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ macro_rules! declare_features {
6363
_ => panic!("`{}` was not listed in `declare_features`", feature),
6464
}
6565
}
66+
67+
pub fn unordered_const_ty_params(&self) -> bool {
68+
self.const_generics || self.const_generics_defaults
69+
}
6670
}
6771
};
6872
}

compiler/rustc_hir/src/hir.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,9 @@ impl GenericArg<'_> {
296296
match self {
297297
GenericArg::Lifetime(_) => ast::ParamKindOrd::Lifetime,
298298
GenericArg::Type(_) => ast::ParamKindOrd::Type,
299-
GenericArg::Const(_) => ast::ParamKindOrd::Const { unordered: feats.const_generics },
299+
GenericArg::Const(_) => {
300+
ast::ParamKindOrd::Const { unordered: feats.unordered_const_ty_params() }
301+
}
300302
}
301303
}
302304
}

compiler/rustc_middle/src/ty/generics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl GenericParamDefKind {
3636
GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime,
3737
GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type,
3838
GenericParamDefKind::Const { .. } => {
39-
ast::ParamKindOrd::Const { unordered: tcx.features().const_generics }
39+
ast::ParamKindOrd::Const { unordered: tcx.features().unordered_const_ty_params() }
4040
}
4141
}
4242
}

compiler/rustc_resolve/src/diagnostics.rs

-11
Original file line numberDiff line numberDiff line change
@@ -472,17 +472,6 @@ impl<'a> Resolver<'a> {
472472
);
473473
err
474474
}
475-
ResolutionError::ParamInAnonConstInTyDefault(name) => {
476-
let mut err = self.session.struct_span_err(
477-
span,
478-
"constant values inside of type parameter defaults must not depend on generic parameters",
479-
);
480-
err.span_label(
481-
span,
482-
format!("the anonymous constant must not depend on the parameter `{}`", name),
483-
);
484-
err
485-
}
486475
ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => {
487476
let mut err = self.session.struct_span_err(
488477
span,

compiler/rustc_resolve/src/late.rs

+40-29
Original file line numberDiff line numberDiff line change
@@ -555,18 +555,23 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
555555
// provide previous type parameters as they're built. We
556556
// put all the parameters on the ban list and then remove
557557
// them one by one as they are processed and become available.
558-
let mut default_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
559-
let mut found_default = false;
560-
default_ban_rib.bindings.extend(generics.params.iter().filter_map(
561-
|param| match param.kind {
562-
GenericParamKind::Type { default: Some(_), .. }
563-
| GenericParamKind::Const { default: Some(_), .. } => {
564-
found_default = true;
565-
Some((Ident::with_dummy_span(param.ident.name), Res::Err))
558+
let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
559+
let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
560+
for param in generics.params.iter() {
561+
match param.kind {
562+
GenericParamKind::Type { .. } => {
563+
forward_ty_ban_rib
564+
.bindings
565+
.insert(Ident::with_dummy_span(param.ident.name), Res::Err);
566566
}
567-
_ => None,
568-
},
569-
));
567+
GenericParamKind::Const { .. } => {
568+
forward_const_ban_rib
569+
.bindings
570+
.insert(Ident::with_dummy_span(param.ident.name), Res::Err);
571+
}
572+
GenericParamKind::Lifetime => {}
573+
}
574+
}
570575

571576
// rust-lang/rust#61631: The type `Self` is essentially
572577
// another type parameter. For ADTs, we consider it
@@ -579,7 +584,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
579584
// such as in the case of `trait Add<Rhs = Self>`.)
580585
if self.diagnostic_metadata.current_self_item.is_some() {
581586
// (`Some` if + only if we are in ADT's generics.)
582-
default_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
587+
forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
583588
}
584589

585590
for param in &generics.params {
@@ -591,32 +596,38 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
591596
}
592597

593598
if let Some(ref ty) = default {
594-
self.ribs[TypeNS].push(default_ban_rib);
595-
self.with_rib(ValueNS, ForwardGenericParamBanRibKind, |this| {
596-
// HACK: We use an empty `ForwardGenericParamBanRibKind` here which
597-
// is only used to forbid the use of const parameters inside of
598-
// type defaults.
599-
//
600-
// While the rib name doesn't really fit here, it does allow us to use the same
601-
// code for both const and type parameters.
602-
this.visit_ty(ty);
603-
});
604-
default_ban_rib = self.ribs[TypeNS].pop().unwrap();
599+
self.ribs[TypeNS].push(forward_ty_ban_rib);
600+
self.ribs[ValueNS].push(forward_const_ban_rib);
601+
self.visit_ty(ty);
602+
forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
603+
forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
605604
}
606605

607606
// Allow all following defaults to refer to this type parameter.
608-
default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
607+
forward_ty_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
609608
}
610-
GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
611-
// FIXME(const_generics_defaults): handle `default` value here
612-
for bound in &param.bounds {
613-
self.visit_param_bound(bound);
614-
}
609+
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
610+
// Const parameters can't have param bounds.
611+
assert!(param.bounds.is_empty());
612+
615613
self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
616614
self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
617615
self.visit_ty(ty);
618616
self.ribs[TypeNS].pop().unwrap();
619617
self.ribs[ValueNS].pop().unwrap();
618+
619+
if let Some(ref expr) = default {
620+
self.ribs[TypeNS].push(forward_ty_ban_rib);
621+
self.ribs[ValueNS].push(forward_const_ban_rib);
622+
self.visit_anon_const(expr);
623+
forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
624+
forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
625+
}
626+
627+
// Allow all following defaults to refer to this const parameter.
628+
forward_const_ban_rib
629+
.bindings
630+
.remove(&Ident::with_dummy_span(param.ident.name));
620631
}
621632
}
622633
}

compiler/rustc_resolve/src/lib.rs

+8-50
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,6 @@ enum ResolutionError<'a> {
239239
ForwardDeclaredTyParam, // FIXME(const_generics_defaults)
240240
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
241241
ParamInTyOfConstParam(Symbol),
242-
/// constant values inside of type parameter defaults must not depend on generic parameters.
243-
ParamInAnonConstInTyDefault(Symbol),
244242
/// generic parameters must not be used inside const evaluations.
245243
///
246244
/// This error is only emitted when using `min_const_generics`.
@@ -2672,26 +2670,18 @@ impl<'a> Resolver<'a> {
26722670
}
26732671
}
26742672
Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
2675-
let mut in_ty_param_default = false;
26762673
for rib in ribs {
2677-
let has_generic_params = match rib.kind {
2674+
let has_generic_params: HasGenericParams = match rib.kind {
26782675
NormalRibKind
26792676
| ClosureOrAsyncRibKind
26802677
| AssocItemRibKind
26812678
| ModuleRibKind(..)
2682-
| MacroDefinition(..) => {
2679+
| MacroDefinition(..)
2680+
| ForwardGenericParamBanRibKind => {
26832681
// Nothing to do. Continue.
26842682
continue;
26852683
}
26862684

2687-
// We only forbid constant items if we are inside of type defaults,
2688-
// for example `struct Foo<T, U = [u8; std::mem::size_of::<T>()]>`
2689-
ForwardGenericParamBanRibKind => {
2690-
// FIXME(const_generic_defaults): we may need to distinguish between
2691-
// being in type parameter defaults and const parameter defaults
2692-
in_ty_param_default = true;
2693-
continue;
2694-
}
26952685
ConstantItemRibKind(trivial, _) => {
26962686
let features = self.session.features_untracked();
26972687
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
@@ -2720,19 +2710,7 @@ impl<'a> Resolver<'a> {
27202710
}
27212711
}
27222712

2723-
if in_ty_param_default {
2724-
if record_used {
2725-
self.report_error(
2726-
span,
2727-
ResolutionError::ParamInAnonConstInTyDefault(
2728-
rib_ident.name,
2729-
),
2730-
);
2731-
}
2732-
return Res::Err;
2733-
} else {
2734-
continue;
2735-
}
2713+
continue;
27362714
}
27372715

27382716
// This was an attempt to use a type parameter outside its scope.
@@ -2770,23 +2748,15 @@ impl<'a> Resolver<'a> {
27702748
ribs.next();
27712749
}
27722750

2773-
let mut in_ty_param_default = false;
27742751
for rib in ribs {
27752752
let has_generic_params = match rib.kind {
27762753
NormalRibKind
27772754
| ClosureOrAsyncRibKind
27782755
| AssocItemRibKind
27792756
| ModuleRibKind(..)
2780-
| MacroDefinition(..) => continue,
2781-
2782-
// We only forbid constant items if we are inside of type defaults,
2783-
// for example `struct Foo<T, U = [u8; std::mem::size_of::<T>()]>`
2784-
ForwardGenericParamBanRibKind => {
2785-
// FIXME(const_generic_defaults): we may need to distinguish between
2786-
// being in type parameter defaults and const parameter defaults
2787-
in_ty_param_default = true;
2788-
continue;
2789-
}
2757+
| MacroDefinition(..)
2758+
| ForwardGenericParamBanRibKind => continue,
2759+
27902760
ConstantItemRibKind(trivial, _) => {
27912761
let features = self.session.features_untracked();
27922762
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
@@ -2808,19 +2778,7 @@ impl<'a> Resolver<'a> {
28082778
return Res::Err;
28092779
}
28102780

2811-
if in_ty_param_default {
2812-
if record_used {
2813-
self.report_error(
2814-
span,
2815-
ResolutionError::ParamInAnonConstInTyDefault(
2816-
rib_ident.name,
2817-
),
2818-
);
2819-
}
2820-
return Res::Err;
2821-
} else {
2822-
continue;
2823-
}
2781+
continue;
28242782
}
28252783

28262784
ItemRibKind(has_generic_params) => has_generic_params,

compiler/rustc_typeck/src/astconv/generics.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
286286
ParamKindOrd::Const {
287287
unordered: tcx
288288
.features()
289-
.const_generics,
289+
.unordered_const_ty_params(),
290290
}
291291
}
292292
},
@@ -309,7 +309,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
309309
GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
310310
GenericArg::Type(_) => ParamKindOrd::Type,
311311
GenericArg::Const(_) => ParamKindOrd::Const {
312-
unordered: tcx.features().const_generics,
312+
unordered: tcx
313+
.features()
314+
.unordered_const_ty_params(),
313315
},
314316
}),
315317
Some(&format!(

compiler/rustc_typeck/src/astconv/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
513513
GenericParamDefKind::Const { has_default } => {
514514
let ty = tcx.at(self.span).type_of(param.def_id);
515515
if !infer_args && has_default {
516-
tcx.const_param_default(param.def_id).into()
516+
tcx.const_param_default(param.def_id)
517+
.subst_spanned(tcx, substs.unwrap(), Some(self.span))
518+
.into()
517519
} else {
518520
if infer_args {
519521
self.astconv.ct_infer(ty, Some(param), self.span).into()

compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1446,7 +1446,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14461446
}
14471447
GenericParamDefKind::Const { has_default, .. } => {
14481448
if !infer_args && has_default {
1449-
tcx.const_param_default(param.def_id).into()
1449+
tcx.const_param_default(param.def_id)
1450+
.subst_spanned(tcx, substs.unwrap(), Some(self.span))
1451+
.into()
14501452
} else {
14511453
self.fcx.var_for_def(self.span, param)
14521454
}

compiler/rustc_typeck/src/check/wfcheck.rs

+40-13
Original file line numberDiff line numberDiff line change
@@ -728,20 +728,36 @@ fn check_where_clauses<'tcx, 'fcx>(
728728
//
729729
// Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
730730
for param in &generics.params {
731-
if let GenericParamDefKind::Type { .. } = param.kind {
732-
if is_our_default(&param) {
733-
let ty = fcx.tcx.type_of(param.def_id);
734-
// Ignore dependent defaults -- that is, where the default of one type
735-
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
736-
// be sure if it will error or not as user might always specify the other.
737-
if !ty.needs_subst() {
731+
match param.kind {
732+
GenericParamDefKind::Type { .. } => {
733+
if is_our_default(&param) {
734+
let ty = fcx.tcx.type_of(param.def_id);
735+
// Ignore dependent defaults -- that is, where the default of one type
736+
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
737+
// be sure if it will error or not as user might always specify the other.
738+
if !ty.needs_subst() {
739+
fcx.register_wf_obligation(
740+
ty.into(),
741+
fcx.tcx.def_span(param.def_id),
742+
ObligationCauseCode::MiscObligation,
743+
);
744+
}
745+
}
746+
}
747+
GenericParamDefKind::Const { .. } => {
748+
// FIXME(const_generics_defaults): Figure out if this
749+
// is the behavior we want, see the comment further below.
750+
if is_our_default(&param) {
751+
let default_ct = tcx.const_param_default(param.def_id);
738752
fcx.register_wf_obligation(
739-
ty.into(),
753+
default_ct.into(),
740754
fcx.tcx.def_span(param.def_id),
741755
ObligationCauseCode::MiscObligation,
742756
);
743757
}
744758
}
759+
// Doesn't have defaults.
760+
GenericParamDefKind::Lifetime => {}
745761
}
746762
}
747763

@@ -774,14 +790,25 @@ fn check_where_clauses<'tcx, 'fcx>(
774790
fcx.tcx.mk_param_from_def(param)
775791
}
776792
GenericParamDefKind::Const { .. } => {
793+
// FIXME(const_generics_defaults): I(@lcnr) feel like always
794+
// using the const parameter is the right choice here, even
795+
// if it needs substs.
796+
//
797+
// Before stabilizing this we probably want to get some tests
798+
// where this makes a difference and figure out what's the exact
799+
// behavior we want here.
800+
801+
// If the param has a default, ...
777802
if is_our_default(param) {
778803
let default_ct = tcx.const_param_default(param.def_id);
779-
// Const params currently have to be concrete.
780-
assert!(!default_ct.needs_subst());
781-
default_ct.into()
782-
} else {
783-
fcx.tcx.mk_param_from_def(param)
804+
// ... and it's not a dependent default, ...
805+
if !default_ct.needs_subst() {
806+
// ... then substitute it with the default.
807+
return default_ct.into();
808+
}
784809
}
810+
811+
fcx.tcx.mk_param_from_def(param)
785812
}
786813
}
787814
});

0 commit comments

Comments
 (0)