Skip to content

Commit

Permalink
Rollup merge of rust-lang#81544 - JulianKnodt:sat_where, r=lcnr
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
m-ou-se committed Feb 2, 2021
2 parents a262bc1 + 6525671 commit 7fa357d
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 18 deletions.
30 changes: 17 additions & 13 deletions compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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(());
Expand Down Expand Up @@ -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 => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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]
Expand All @@ -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,
Expand All @@ -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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>>()]
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/const_evaluatable/needs_where_clause.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions src/test/ui/const_evaluatable/needs_where_clause.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 29 additions & 0 deletions src/test/ui/const_evaluatable/no_where_clause.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions src/test/ui/const_evaluatable/no_where_clause.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 7fa357d

Please sign in to comment.