From 312b4fdfd281a5ebd740acaf88cc82c47225be23 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sun, 18 Apr 2021 15:14:17 +0200 Subject: [PATCH] improve wf check for const param defaults --- compiler/rustc_typeck/src/check/wfcheck.rs | 53 ++++++++++++++----- .../complex-generic-default-expr.min.stderr | 4 +- .../defaults/complex-generic-default-expr.rs | 8 ++- .../defaults/const-param-as-default-value.rs | 14 +++++ .../defaults/const-param-in-ty-defaults.rs | 18 +++++++ .../defaults/default-param-wf-concrete.rs | 5 ++ .../defaults/default-param-wf-concrete.stderr | 9 ++++ .../defaults/pretty-printing-ast.rs | 1 - 8 files changed, 94 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/const-generics/defaults/const-param-as-default-value.rs create mode 100644 src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs create mode 100644 src/test/ui/const-generics/defaults/default-param-wf-concrete.rs create mode 100644 src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 887cc42a1dd..26871d6f028 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -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., ``). 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., ``). 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) } } }); diff --git a/src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr b/src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr index d50a0a61d49..7d51e9aa0f3 100644 --- a/src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr +++ b/src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr @@ -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; | ^ cannot perform const operation using `N` @@ -8,7 +8,7 @@ LL | struct Foo; = 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); | ^ cannot perform const operation using `T` diff --git a/src/test/ui/const-generics/defaults/complex-generic-default-expr.rs b/src/test/ui/const-generics/defaults/complex-generic-default-expr.rs index 1c25fda8d30..a1c04b5e7c3 100644 --- a/src/test/ui/const-generics/defaults/complex-generic-default-expr.rs +++ b/src/test/ui/const-generics/defaults/complex-generic-default-expr.rs @@ -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); //[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() {} diff --git a/src/test/ui/const-generics/defaults/const-param-as-default-value.rs b/src/test/ui/const-generics/defaults/const-param-as-default-value.rs new file mode 100644 index 00000000000..d9cab34327e --- /dev/null +++ b/src/test/ui/const-generics/defaults/const-param-as-default-value.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics_defaults)] +#![allow(incomplete_features)] +struct Foo([u8; N], [u8; M]); + +fn foo() -> Foo { + let x = [0; N]; + Foo(x, x) +} + +fn main() { + let val = foo::<13>(); + assert_eq!(val.0, val.1); +} diff --git a/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs b/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs new file mode 100644 index 00000000000..e3d78fe2ee0 --- /dev/null +++ b/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs @@ -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(T); + +impl Foo { + fn new() -> Self { + Foo([0; N]) + } +} + +fn main() { + assert_eq!(Foo::new().0, [0; 10]); +} diff --git a/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs b/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs new file mode 100644 index 00000000000..4bb56c6a1c0 --- /dev/null +++ b/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs @@ -0,0 +1,5 @@ +#![feature(const_generics_defaults)] +#![allow(incomplete_features)] +struct Foo; +//~^ ERROR evaluation of constant value failed +fn main() {} diff --git a/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr b/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr new file mode 100644 index 00000000000..8464ea98bf6 --- /dev/null +++ b/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/default-param-wf-concrete.rs:3:28 + | +LL | struct Foo; + | ^^^^^^^ 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`. diff --git a/src/test/ui/const-generics/defaults/pretty-printing-ast.rs b/src/test/ui/const-generics/defaults/pretty-printing-ast.rs index 12a92a10476..7a57950dfc9 100644 --- a/src/test/ui/const-generics/defaults/pretty-printing-ast.rs +++ b/src/test/ui/const-generics/defaults/pretty-printing-ast.rs @@ -11,4 +11,3 @@ trait Foo {} fn foo() {} struct Range; -