Skip to content

Commit 3aed8b1

Browse files
authored
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```
2 parents 76be6bb + 6525671 commit 3aed8b1

File tree

7 files changed

+93
-18
lines changed

7 files changed

+93
-18
lines changed

compiler/rustc_trait_selection/src/traits/const_evaluatable.rs

+17-13
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ use rustc_infer::infer::InferCtxt;
1616
use rustc_middle::mir::abstract_const::{Node, NodeId};
1717
use rustc_middle::mir::interpret::ErrorHandled;
1818
use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
19-
use rustc_middle::ty::subst::Subst;
20-
use rustc_middle::ty::subst::SubstsRef;
19+
use rustc_middle::ty::subst::{Subst, SubstsRef};
2120
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
2221
use rustc_session::lint;
2322
use rustc_span::def_id::{DefId, LocalDefId};
@@ -43,10 +42,6 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
4342
for pred in param_env.caller_bounds() {
4443
match pred.kind().skip_binder() {
4544
ty::PredicateKind::ConstEvaluatable(b_def, b_substs) => {
46-
debug!(
47-
"is_const_evaluatable: caller_bound={:?}, {:?}",
48-
b_def, b_substs
49-
);
5045
if b_def == def && b_substs == substs {
5146
debug!("is_const_evaluatable: caller_bound ~~> ok");
5247
return Ok(());
@@ -113,15 +108,24 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
113108
}
114109
FailureKind::MentionsParam => {
115110
// FIXME(const_evaluatable_checked): Better error message.
116-
infcx
117-
.tcx
118-
.sess
119-
.struct_span_err(span, "unconstrained generic constant")
120-
.span_help(
111+
let mut err =
112+
infcx.tcx.sess.struct_span_err(span, "unconstrained generic constant");
113+
let const_span = tcx.def_span(def.did);
114+
// FIXME(const_evaluatable_checked): Update this suggestion once
115+
// explicit const evaluatable bounds are implemented.
116+
if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(const_span)
117+
{
118+
err.span_help(
121119
tcx.def_span(def.did),
120+
&format!("try adding a `where` bound using this expression: where [u8; {}]: Sized", snippet),
121+
);
122+
} else {
123+
err.span_help(
124+
const_span,
122125
"consider adding a `where` bound for this expression",
123-
)
124-
.emit();
126+
);
127+
}
128+
err.emit();
125129
return Err(ErrorHandled::Reported(ErrorReported));
126130
}
127131
FailureKind::Concrete => {

src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: unconstrained generic constant
44
LL | let _ = const_evaluatable_lib::test1::<T>();
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
help: consider adding a `where` bound for this expression
7+
help: try adding a `where` bound using this expression: where [u8; std::mem::size_of::<T>() - 1]: Sized
88
--> $DIR/auxiliary/const_evaluatable_lib.rs:6:10
99
|
1010
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
@@ -16,7 +16,7 @@ error: unconstrained generic constant
1616
LL | let _ = const_evaluatable_lib::test1::<T>();
1717
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1818
|
19-
help: consider adding a `where` bound for this expression
19+
help: try adding a `where` bound using this expression: where [u8; std::mem::size_of::<T>() - 1]: Sized
2020
--> $DIR/auxiliary/const_evaluatable_lib.rs:4:27
2121
|
2222
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
@@ -28,7 +28,7 @@ error: unconstrained generic constant
2828
LL | let _ = const_evaluatable_lib::test1::<T>();
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3030
|
31-
help: consider adding a `where` bound for this expression
31+
help: try adding a `where` bound using this expression: where [u8; std::mem::size_of::<T>() - 1]: Sized
3232
--> $DIR/auxiliary/const_evaluatable_lib.rs:6:10
3333
|
3434
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
@@ -40,7 +40,7 @@ error: unconstrained generic constant
4040
LL | let _ = const_evaluatable_lib::test1::<T>();
4141
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4242
|
43-
help: consider adding a `where` bound for this expression
43+
help: try adding a `where` bound using this expression: where [u8; std::mem::size_of::<T>() - 1]: Sized
4444
--> $DIR/auxiliary/const_evaluatable_lib.rs:4:27
4545
|
4646
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]

src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: unconstrained generic constant
44
LL | [0; size_of::<Foo<T>>()]
55
| ^^^^^^^^^^^^^^^^^^^
66
|
7-
help: consider adding a `where` bound for this expression
7+
help: try adding a `where` bound using this expression: where [u8; size_of::<Foo<T>>()]: Sized
88
--> $DIR/different-fn.rs:10:9
99
|
1010
LL | [0; size_of::<Foo<T>>()]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![crate_type = "lib"]
2+
#![feature(const_generics, const_evaluatable_checked)]
3+
#![allow(incomplete_features)]
4+
5+
const fn complex_maths<T>(n : usize) -> usize {
6+
2 * n + 1
7+
}
8+
9+
struct Example<T, const N: usize> {
10+
a: [f32; N],
11+
b: [f32; complex_maths::<T>(N)],
12+
//~^ ERROR unconstrained
13+
c: T,
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: unconstrained generic constant
2+
--> $DIR/needs_where_clause.rs:11:6
3+
|
4+
LL | b: [f32; complex_maths::<T>(N)],
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
help: try adding a `where` bound using this expression: where [u8; complex_maths::<T>(N)]: Sized
8+
--> $DIR/needs_where_clause.rs:11:12
9+
|
10+
LL | b: [f32; complex_maths::<T>(N)],
11+
| ^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to previous error
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#![feature(const_generics, const_evaluatable_checked)]
2+
#![allow(incomplete_features, unused)]
3+
4+
const fn complex_maths(n : usize) -> usize {
5+
2 * n + 1
6+
}
7+
8+
pub struct Example<const N: usize> {
9+
a: [f32; N],
10+
b: [f32; complex_maths(N)],
11+
//~^ ERROR unconstrained generic
12+
}
13+
14+
impl<const N: usize> Example<N> {
15+
pub fn new() -> Self {
16+
Self {
17+
a: [0.; N],
18+
b: [0.; complex_maths(N)],
19+
}
20+
}
21+
}
22+
23+
impl Example<2> {
24+
pub fn sum(&self) -> f32 {
25+
self.a.iter().sum::<f32>() + self.b.iter().sum::<f32>()
26+
}
27+
}
28+
29+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: unconstrained generic constant
2+
--> $DIR/no_where_clause.rs:10:6
3+
|
4+
LL | b: [f32; complex_maths(N)],
5+
| ^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
help: try adding a `where` bound using this expression: where [u8; complex_maths(N)]: Sized
8+
--> $DIR/no_where_clause.rs:10:12
9+
|
10+
LL | b: [f32; complex_maths(N)],
11+
| ^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to previous error
14+

0 commit comments

Comments
 (0)