From 65256717f2b3a6cb2d4f84e834941d7433ff5e15 Mon Sep 17 00:00:00 2001 From: kadmin Date: Sat, 30 Jan 2021 03:45:18 +0000 Subject: [PATCH] Add better diagnostic for missing where clause Previously, it's not clear what exactly should be added in the suggested where clause, so this adds an example to demonstrate. --- .../src/traits/const_evaluatable.rs | 30 +++++++++++-------- .../cross_crate_predicate.stderr | 8 ++--- .../different-fn.stderr | 2 +- .../const_evaluatable/needs_where_clause.rs | 14 +++++++++ .../needs_where_clause.stderr | 14 +++++++++ .../ui/const_evaluatable/no_where_clause.rs | 29 ++++++++++++++++++ .../const_evaluatable/no_where_clause.stderr | 14 +++++++++ 7 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/const_evaluatable/needs_where_clause.rs create mode 100644 src/test/ui/const_evaluatable/needs_where_clause.stderr create mode 100644 src/test/ui/const_evaluatable/no_where_clause.rs create mode 100644 src/test/ui/const_evaluatable/no_where_clause.stderr diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index b587ed6487e3c..5240df6cf1e30 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -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(()); @@ -100,15 +95,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 => { diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr index 8a298b47fffa7..92547ca4796a4 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr @@ -4,7 +4,7 @@ error: unconstrained generic constant LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: consider adding a `where` bound for this expression +help: try adding a `where` bound using this expression: where [u8; std::mem::size_of::() - 1]: Sized --> $DIR/auxiliary/const_evaluatable_lib.rs:6:10 | LL | [u8; std::mem::size_of::() - 1]: Sized, @@ -16,7 +16,7 @@ error: unconstrained generic constant LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: consider adding a `where` bound for this expression +help: try adding a `where` bound using this expression: where [u8; std::mem::size_of::() - 1]: Sized --> $DIR/auxiliary/const_evaluatable_lib.rs:4:27 | LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] @@ -28,7 +28,7 @@ error: unconstrained generic constant LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: consider adding a `where` bound for this expression +help: try adding a `where` bound using this expression: where [u8; std::mem::size_of::() - 1]: Sized --> $DIR/auxiliary/const_evaluatable_lib.rs:6:10 | LL | [u8; std::mem::size_of::() - 1]: Sized, @@ -40,7 +40,7 @@ error: unconstrained generic constant LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: consider adding a `where` bound for this expression +help: try adding a `where` bound using this expression: where [u8; std::mem::size_of::() - 1]: Sized --> $DIR/auxiliary/const_evaluatable_lib.rs:4:27 | LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr index 1f6dddb04e56c..00efb61000401 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr @@ -4,7 +4,7 @@ error: unconstrained generic constant LL | [0; size_of::>()] | ^^^^^^^^^^^^^^^^^^^ | -help: consider adding a `where` bound for this expression +help: try adding a `where` bound using this expression: where [u8; size_of::>()]: Sized --> $DIR/different-fn.rs:10:9 | LL | [0; size_of::>()] diff --git a/src/test/ui/const_evaluatable/needs_where_clause.rs b/src/test/ui/const_evaluatable/needs_where_clause.rs new file mode 100644 index 0000000000000..498a2ae753361 --- /dev/null +++ b/src/test/ui/const_evaluatable/needs_where_clause.rs @@ -0,0 +1,14 @@ +#![crate_type = "lib"] +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +const fn complex_maths(n : usize) -> usize { + 2 * n + 1 +} + +struct Example { + a: [f32; N], + b: [f32; complex_maths::(N)], + //~^ ERROR unconstrained + c: T, +} diff --git a/src/test/ui/const_evaluatable/needs_where_clause.stderr b/src/test/ui/const_evaluatable/needs_where_clause.stderr new file mode 100644 index 0000000000000..e991c508c03f3 --- /dev/null +++ b/src/test/ui/const_evaluatable/needs_where_clause.stderr @@ -0,0 +1,14 @@ +error: unconstrained generic constant + --> $DIR/needs_where_clause.rs:11:6 + | +LL | b: [f32; complex_maths::(N)], + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try adding a `where` bound using this expression: where [u8; complex_maths::(N)]: Sized + --> $DIR/needs_where_clause.rs:11:12 + | +LL | b: [f32; complex_maths::(N)], + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const_evaluatable/no_where_clause.rs b/src/test/ui/const_evaluatable/no_where_clause.rs new file mode 100644 index 0000000000000..12f4a22038ef7 --- /dev/null +++ b/src/test/ui/const_evaluatable/no_where_clause.rs @@ -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 { + a: [f32; N], + b: [f32; complex_maths(N)], + //~^ ERROR unconstrained generic +} + +impl Example { + 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::() + self.b.iter().sum::() + } +} + +fn main() {} diff --git a/src/test/ui/const_evaluatable/no_where_clause.stderr b/src/test/ui/const_evaluatable/no_where_clause.stderr new file mode 100644 index 0000000000000..65100909e53d5 --- /dev/null +++ b/src/test/ui/const_evaluatable/no_where_clause.stderr @@ -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 +