Rollup merge of #81544 - JulianKnodt:sat_where, r=lcnr
Add better diagnostic for unbounded Abst. Const ~~In the case where a generic abst. const requires a trivial where bound: `where TypeWithConst<const_fn(N)>: ,`, instead of requiring a where bound, just check that only consts are being substituted in to skip over where check.~~ ~~This is pretty sketchy, but I think it works. Presumably, if there is checking for type bounds added later, it can first check nested requirements, and see if they're satisfied by the current `ParamEnv`.~~ Changed the diagnostic to add a better example, which is more practical than what was previously proposed. r? ```@lcnr```
This commit is contained in:
commit
3aed8b17a8
7 changed files with 93 additions and 18 deletions
|
@ -16,8 +16,7 @@ use rustc_infer::infer::InferCtxt;
|
|||
use rustc_middle::mir::abstract_const::{Node, NodeId};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::subst::{Subst, SubstsRef};
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::def_id::{DefId, LocalDefId};
|
||||
|
@ -43,10 +42,6 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
|||
for pred in param_env.caller_bounds() {
|
||||
match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::ConstEvaluatable(b_def, b_substs) => {
|
||||
debug!(
|
||||
"is_const_evaluatable: caller_bound={:?}, {:?}",
|
||||
b_def, b_substs
|
||||
);
|
||||
if b_def == def && b_substs == substs {
|
||||
debug!("is_const_evaluatable: caller_bound ~~> ok");
|
||||
return Ok(());
|
||||
|
@ -113,15 +108,24 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
|||
}
|
||||
FailureKind::MentionsParam => {
|
||||
// FIXME(const_evaluatable_checked): Better error message.
|
||||
infcx
|
||||
.tcx
|
||||
.sess
|
||||
.struct_span_err(span, "unconstrained generic constant")
|
||||
.span_help(
|
||||
let mut err =
|
||||
infcx.tcx.sess.struct_span_err(span, "unconstrained generic constant");
|
||||
let const_span = tcx.def_span(def.did);
|
||||
// FIXME(const_evaluatable_checked): Update this suggestion once
|
||||
// explicit const evaluatable bounds are implemented.
|
||||
if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(const_span)
|
||||
{
|
||||
err.span_help(
|
||||
tcx.def_span(def.did),
|
||||
&format!("try adding a `where` bound using this expression: where [u8; {}]: Sized", snippet),
|
||||
);
|
||||
} else {
|
||||
err.span_help(
|
||||
const_span,
|
||||
"consider adding a `where` bound for this expression",
|
||||
)
|
||||
.emit();
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
return Err(ErrorHandled::Reported(ErrorReported));
|
||||
}
|
||||
FailureKind::Concrete => {
|
||||
|
|
|
@ -4,7 +4,7 @@ error: unconstrained generic constant
|
|||
LL | let _ = const_evaluatable_lib::test1::<T>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider adding a `where` bound for this expression
|
||||
help: try adding a `where` bound using this expression: where [u8; std::mem::size_of::<T>() - 1]: Sized
|
||||
--> $DIR/auxiliary/const_evaluatable_lib.rs:6:10
|
||||
|
|
||||
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
|
||||
|
@ -16,7 +16,7 @@ error: unconstrained generic constant
|
|||
LL | let _ = const_evaluatable_lib::test1::<T>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider adding a `where` bound for this expression
|
||||
help: try adding a `where` bound using this expression: where [u8; std::mem::size_of::<T>() - 1]: Sized
|
||||
--> $DIR/auxiliary/const_evaluatable_lib.rs:4:27
|
||||
|
|
||||
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
|
||||
|
@ -28,7 +28,7 @@ error: unconstrained generic constant
|
|||
LL | let _ = const_evaluatable_lib::test1::<T>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider adding a `where` bound for this expression
|
||||
help: try adding a `where` bound using this expression: where [u8; std::mem::size_of::<T>() - 1]: Sized
|
||||
--> $DIR/auxiliary/const_evaluatable_lib.rs:6:10
|
||||
|
|
||||
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
|
||||
|
@ -40,7 +40,7 @@ error: unconstrained generic constant
|
|||
LL | let _ = const_evaluatable_lib::test1::<T>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider adding a `where` bound for this expression
|
||||
help: try adding a `where` bound using this expression: where [u8; std::mem::size_of::<T>() - 1]: Sized
|
||||
--> $DIR/auxiliary/const_evaluatable_lib.rs:4:27
|
||||
|
|
||||
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
|
||||
|
|
|
@ -4,7 +4,7 @@ error: unconstrained generic constant
|
|||
LL | [0; size_of::<Foo<T>>()]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider adding a `where` bound for this expression
|
||||
help: try adding a `where` bound using this expression: where [u8; size_of::<Foo<T>>()]: Sized
|
||||
--> $DIR/different-fn.rs:10:9
|
||||
|
|
||||
LL | [0; size_of::<Foo<T>>()]
|
||||
|
|
14
src/test/ui/const_evaluatable/needs_where_clause.rs
Normal file
14
src/test/ui/const_evaluatable/needs_where_clause.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
#![crate_type = "lib"]
|
||||
#![feature(const_generics, const_evaluatable_checked)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
const fn complex_maths<T>(n : usize) -> usize {
|
||||
2 * n + 1
|
||||
}
|
||||
|
||||
struct Example<T, const N: usize> {
|
||||
a: [f32; N],
|
||||
b: [f32; complex_maths::<T>(N)],
|
||||
//~^ ERROR unconstrained
|
||||
c: T,
|
||||
}
|
14
src/test/ui/const_evaluatable/needs_where_clause.stderr
Normal file
14
src/test/ui/const_evaluatable/needs_where_clause.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error: unconstrained generic constant
|
||||
--> $DIR/needs_where_clause.rs:11:6
|
||||
|
|
||||
LL | b: [f32; complex_maths::<T>(N)],
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try adding a `where` bound using this expression: where [u8; complex_maths::<T>(N)]: Sized
|
||||
--> $DIR/needs_where_clause.rs:11:12
|
||||
|
|
||||
LL | b: [f32; complex_maths::<T>(N)],
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
29
src/test/ui/const_evaluatable/no_where_clause.rs
Normal file
29
src/test/ui/const_evaluatable/no_where_clause.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
#![feature(const_generics, const_evaluatable_checked)]
|
||||
#![allow(incomplete_features, unused)]
|
||||
|
||||
const fn complex_maths(n : usize) -> usize {
|
||||
2 * n + 1
|
||||
}
|
||||
|
||||
pub struct Example<const N: usize> {
|
||||
a: [f32; N],
|
||||
b: [f32; complex_maths(N)],
|
||||
//~^ ERROR unconstrained generic
|
||||
}
|
||||
|
||||
impl<const N: usize> Example<N> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
a: [0.; N],
|
||||
b: [0.; complex_maths(N)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Example<2> {
|
||||
pub fn sum(&self) -> f32 {
|
||||
self.a.iter().sum::<f32>() + self.b.iter().sum::<f32>()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
14
src/test/ui/const_evaluatable/no_where_clause.stderr
Normal file
14
src/test/ui/const_evaluatable/no_where_clause.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error: unconstrained generic constant
|
||||
--> $DIR/no_where_clause.rs:10:6
|
||||
|
|
||||
LL | b: [f32; complex_maths(N)],
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try adding a `where` bound using this expression: where [u8; complex_maths(N)]: Sized
|
||||
--> $DIR/no_where_clause.rs:10:12
|
||||
|
|
||||
LL | b: [f32; complex_maths(N)],
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Add table
Reference in a new issue