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::abstract_const::{Node, NodeId};
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
|
use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
|
||||||
use rustc_middle::ty::subst::Subst;
|
use rustc_middle::ty::subst::{Subst, SubstsRef};
|
||||||
use rustc_middle::ty::subst::SubstsRef;
|
|
||||||
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_span::def_id::{DefId, LocalDefId};
|
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() {
|
for pred in param_env.caller_bounds() {
|
||||||
match pred.kind().skip_binder() {
|
match pred.kind().skip_binder() {
|
||||||
ty::PredicateKind::ConstEvaluatable(b_def, b_substs) => {
|
ty::PredicateKind::ConstEvaluatable(b_def, b_substs) => {
|
||||||
debug!(
|
|
||||||
"is_const_evaluatable: caller_bound={:?}, {:?}",
|
|
||||||
b_def, b_substs
|
|
||||||
);
|
|
||||||
if b_def == def && b_substs == substs {
|
if b_def == def && b_substs == substs {
|
||||||
debug!("is_const_evaluatable: caller_bound ~~> ok");
|
debug!("is_const_evaluatable: caller_bound ~~> ok");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -113,15 +108,24 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
||||||
}
|
}
|
||||||
FailureKind::MentionsParam => {
|
FailureKind::MentionsParam => {
|
||||||
// FIXME(const_evaluatable_checked): Better error message.
|
// FIXME(const_evaluatable_checked): Better error message.
|
||||||
infcx
|
let mut err =
|
||||||
.tcx
|
infcx.tcx.sess.struct_span_err(span, "unconstrained generic constant");
|
||||||
.sess
|
let const_span = tcx.def_span(def.did);
|
||||||
.struct_span_err(span, "unconstrained generic constant")
|
// FIXME(const_evaluatable_checked): Update this suggestion once
|
||||||
.span_help(
|
// 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),
|
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",
|
"consider adding a `where` bound for this expression",
|
||||||
)
|
);
|
||||||
.emit();
|
}
|
||||||
|
err.emit();
|
||||||
return Err(ErrorHandled::Reported(ErrorReported));
|
return Err(ErrorHandled::Reported(ErrorReported));
|
||||||
}
|
}
|
||||||
FailureKind::Concrete => {
|
FailureKind::Concrete => {
|
||||||
|
|
|
@ -4,7 +4,7 @@ error: unconstrained generic constant
|
||||||
LL | let _ = const_evaluatable_lib::test1::<T>();
|
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
|
--> $DIR/auxiliary/const_evaluatable_lib.rs:6:10
|
||||||
|
|
|
|
||||||
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
|
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
|
||||||
|
@ -16,7 +16,7 @@ error: unconstrained generic constant
|
||||||
LL | let _ = const_evaluatable_lib::test1::<T>();
|
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
|
--> $DIR/auxiliary/const_evaluatable_lib.rs:4:27
|
||||||
|
|
|
|
||||||
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
|
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>();
|
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
|
--> $DIR/auxiliary/const_evaluatable_lib.rs:6:10
|
||||||
|
|
|
|
||||||
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
|
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
|
||||||
|
@ -40,7 +40,7 @@ error: unconstrained generic constant
|
||||||
LL | let _ = const_evaluatable_lib::test1::<T>();
|
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
|
--> $DIR/auxiliary/const_evaluatable_lib.rs:4:27
|
||||||
|
|
|
|
||||||
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
|
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>>()]
|
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
|
--> $DIR/different-fn.rs:10:9
|
||||||
|
|
|
|
||||||
LL | [0; size_of::<Foo<T>>()]
|
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
Add a link
Reference in a new issue