improve wf check for const param defaults
This commit is contained in:
parent
7cb1dcd488
commit
312b4fdfd2
@ -728,20 +728,36 @@ fn check_where_clauses<'tcx, 'fcx>(
|
||||
//
|
||||
// Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
|
||||
for param in &generics.params {
|
||||
if let GenericParamDefKind::Type { .. } = param.kind {
|
||||
if is_our_default(¶m) {
|
||||
let ty = fcx.tcx.type_of(param.def_id);
|
||||
// Ignore dependent defaults -- that is, where the default of one type
|
||||
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
|
||||
// be sure if it will error or not as user might always specify the other.
|
||||
if !ty.needs_subst() {
|
||||
match param.kind {
|
||||
GenericParamDefKind::Type { .. } => {
|
||||
if is_our_default(¶m) {
|
||||
let ty = fcx.tcx.type_of(param.def_id);
|
||||
// Ignore dependent defaults -- that is, where the default of one type
|
||||
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
|
||||
// be sure if it will error or not as user might always specify the other.
|
||||
if !ty.needs_subst() {
|
||||
fcx.register_wf_obligation(
|
||||
ty.into(),
|
||||
fcx.tcx.def_span(param.def_id),
|
||||
ObligationCauseCode::MiscObligation,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
GenericParamDefKind::Const { .. } => {
|
||||
// FIXME(const_generics_defaults): Figure out if this
|
||||
// is the behavior we want, see the comment further below.
|
||||
if is_our_default(¶m) {
|
||||
let default_ct = tcx.const_param_default(param.def_id);
|
||||
fcx.register_wf_obligation(
|
||||
ty.into(),
|
||||
default_ct.into(),
|
||||
fcx.tcx.def_span(param.def_id),
|
||||
ObligationCauseCode::MiscObligation,
|
||||
);
|
||||
}
|
||||
}
|
||||
// Doesn't have defaults.
|
||||
GenericParamDefKind::Lifetime => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -774,14 +790,25 @@ fn check_where_clauses<'tcx, 'fcx>(
|
||||
fcx.tcx.mk_param_from_def(param)
|
||||
}
|
||||
GenericParamDefKind::Const { .. } => {
|
||||
// FIXME(const_generics_defaults): I(@lcnr) feel like always
|
||||
// using the const parameter is the right choice here, even
|
||||
// if it needs substs.
|
||||
//
|
||||
// Before stabilizing this we probably want to get some tests
|
||||
// where this makes a difference and figure out what's the exact
|
||||
// behavior we want here.
|
||||
|
||||
// If the param has a default, ...
|
||||
if is_our_default(param) {
|
||||
let default_ct = tcx.const_param_default(param.def_id);
|
||||
// Const params currently have to be concrete.
|
||||
assert!(!default_ct.needs_subst());
|
||||
default_ct.into()
|
||||
} else {
|
||||
fcx.tcx.mk_param_from_def(param)
|
||||
// ... and it's not a dependent default, ...
|
||||
if !default_ct.needs_subst() {
|
||||
// ... then substitute it with the default.
|
||||
return default_ct.into();
|
||||
}
|
||||
}
|
||||
|
||||
fcx.tcx.mk_param_from_def(param)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-generic-default-expr.rs:6:47
|
||||
--> $DIR/complex-generic-default-expr.rs:10:47
|
||||
|
|
||||
LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
|
||||
| ^ cannot perform const operation using `N`
|
||||
@ -8,7 +8,7 @@ LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-generic-default-expr.rs:9:62
|
||||
--> $DIR/complex-generic-default-expr.rs:13:62
|
||||
|
|
||||
LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
|
||||
| ^ cannot perform const operation using `T`
|
||||
|
@ -1,4 +1,8 @@
|
||||
// revisions: full min
|
||||
// revisions: min
|
||||
// FIXME(const_generics): add the `full` revision,
|
||||
// currently causes an ICE as we don't supply substs to
|
||||
// anon consts in the parameter listing, as that would
|
||||
// cause that anon const to reference itself.
|
||||
#![cfg_attr(full, feature(const_generics))]
|
||||
#![feature(const_generics_defaults)]
|
||||
#![allow(incomplete_features)]
|
||||
@ -8,6 +12,6 @@
|
||||
|
||||
struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
|
||||
//[min]~^ ERROR generic parameters may not be used in const operations
|
||||
//[full]~^^ ERROR the size for values of type `T` cannot be known at compilation time
|
||||
//[full]~^^ ERROR the size for values of type `T` cannot be known at compilation time
|
||||
|
||||
fn main() {}
|
||||
|
@ -0,0 +1,14 @@
|
||||
// run-pass
|
||||
#![feature(const_generics_defaults)]
|
||||
#![allow(incomplete_features)]
|
||||
struct Foo<const N: usize, const M: usize = N>([u8; N], [u8; M]);
|
||||
|
||||
fn foo<const N: usize>() -> Foo<N> {
|
||||
let x = [0; N];
|
||||
Foo(x, x)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let val = foo::<13>();
|
||||
assert_eq!(val.0, val.1);
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
// run-pass
|
||||
#![feature(const_generics_defaults)]
|
||||
#![allow(incomplete_features)]
|
||||
// FIXME(const_generics_defaults): while we can allow this,
|
||||
// we probably won't easily allow this with more complex const operations.
|
||||
//
|
||||
// So we have to make a conscious decision here when stabilizing a relaxed parameter ordering.
|
||||
struct Foo<const N: usize, T = [u8; N]>(T);
|
||||
|
||||
impl<const N: usize> Foo<N> {
|
||||
fn new() -> Self {
|
||||
Foo([0; N])
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(Foo::new().0, [0; 10]);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
#![feature(const_generics_defaults)]
|
||||
#![allow(incomplete_features)]
|
||||
struct Foo<const N: u8 = { 255 + 1 }>;
|
||||
//~^ ERROR evaluation of constant value failed
|
||||
fn main() {}
|
@ -0,0 +1,9 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/default-param-wf-concrete.rs:3:28
|
||||
|
|
||||
LL | struct Foo<const N: u8 = { 255 + 1 }>;
|
||||
| ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
@ -11,4 +11,3 @@ trait Foo<const KIND: bool = true> {}
|
||||
fn foo<const SIZE: usize = 5>() {}
|
||||
|
||||
struct Range<const FROM: usize = 0, const LEN: usize = 0, const TO: usize = FROM>;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user