Skip to content

Commit 312b4fd

Browse files
committed
improve wf check for const param defaults
1 parent 7cb1dcd commit 312b4fd

8 files changed

+94
-18
lines changed

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
});

src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: generic parameters may not be used in const operations
2-
--> $DIR/complex-generic-default-expr.rs:6:47
2+
--> $DIR/complex-generic-default-expr.rs:10:47
33
|
44
LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
55
| ^ cannot perform const operation using `N`
@@ -8,7 +8,7 @@ LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
88
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
99

1010
error: generic parameters may not be used in const operations
11-
--> $DIR/complex-generic-default-expr.rs:9:62
11+
--> $DIR/complex-generic-default-expr.rs:13:62
1212
|
1313
LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
1414
| ^ cannot perform const operation using `T`
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
// revisions: full min
1+
// revisions: min
2+
// FIXME(const_generics): add the `full` revision,
3+
// currently causes an ICE as we don't supply substs to
4+
// anon consts in the parameter listing, as that would
5+
// cause that anon const to reference itself.
26
#![cfg_attr(full, feature(const_generics))]
37
#![feature(const_generics_defaults)]
48
#![allow(incomplete_features)]
@@ -8,6 +12,6 @@ struct Foo<const N: usize, const M: usize = { N + 1 }>;
812

913
struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
1014
//[min]~^ ERROR generic parameters may not be used in const operations
11-
//[full]~^^ ERROR the size for values of type `T` cannot be known at compilation time
15+
//[full]~^^ ERROR the size for values of type `T` cannot be known at compilation time
1216

1317
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-pass
2+
#![feature(const_generics_defaults)]
3+
#![allow(incomplete_features)]
4+
struct Foo<const N: usize, const M: usize = N>([u8; N], [u8; M]);
5+
6+
fn foo<const N: usize>() -> Foo<N> {
7+
let x = [0; N];
8+
Foo(x, x)
9+
}
10+
11+
fn main() {
12+
let val = foo::<13>();
13+
assert_eq!(val.0, val.1);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// run-pass
2+
#![feature(const_generics_defaults)]
3+
#![allow(incomplete_features)]
4+
// FIXME(const_generics_defaults): while we can allow this,
5+
// we probably won't easily allow this with more complex const operations.
6+
//
7+
// So we have to make a conscious decision here when stabilizing a relaxed parameter ordering.
8+
struct Foo<const N: usize, T = [u8; N]>(T);
9+
10+
impl<const N: usize> Foo<N> {
11+
fn new() -> Self {
12+
Foo([0; N])
13+
}
14+
}
15+
16+
fn main() {
17+
assert_eq!(Foo::new().0, [0; 10]);
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(const_generics_defaults)]
2+
#![allow(incomplete_features)]
3+
struct Foo<const N: u8 = { 255 + 1 }>;
4+
//~^ ERROR evaluation of constant value failed
5+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0080]: evaluation of constant value failed
2+
--> $DIR/default-param-wf-concrete.rs:3:28
3+
|
4+
LL | struct Foo<const N: u8 = { 255 + 1 }>;
5+
| ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0080`.

src/test/ui/const-generics/defaults/pretty-printing-ast.rs

-1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,3 @@ trait Foo<const KIND: bool = true> {}
1111
fn foo<const SIZE: usize = 5>() {}
1212

1313
struct Range<const FROM: usize = 0, const LEN: usize = 0, const TO: usize = FROM>;
14-

0 commit comments

Comments
 (0)