Skip to content

Commit

Permalink
refactor constant evaluation error reporting
Browse files Browse the repository at this point in the history
Refactor constant evaluation to use a single error reporting function
that reports a type-error-like message.

Also, unify all error codes with the "constant evaluation error" message
to just E0080, and similarly for a few other duplicate codes. The old
situation was a total mess, and now that we have *something* we can
further iterate on the UX.
  • Loading branch information
arielb1 committed Jul 20, 2016
1 parent b7017d6 commit 7966739
Show file tree
Hide file tree
Showing 55 changed files with 506 additions and 376 deletions.
1 change: 1 addition & 0 deletions src/librustc_const_eval/Cargo.toml
Expand Up @@ -14,6 +14,7 @@ serialize = { path = "../libserialize" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_errors = { path = "../librustc_errors" }
syntax = { path = "../libsyntax" }
graphviz = { path = "../libgraphviz" }
syntax_pos = { path = "../libsyntax_pos" }
55 changes: 23 additions & 32 deletions src/librustc_const_eval/check_match.rs
Expand Up @@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal;
use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals};
use ::{const_expr_to_pat, lookup_const_by_id};
use ::EvalHint::ExprTypeChecked;
use eval::report_const_eval_err;
use rustc::hir::def::*;
use rustc::hir::def_id::{DefId};
use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
Expand All @@ -42,6 +43,7 @@ use syntax_pos::{Span, DUMMY_SP};
use rustc::hir::fold::{Folder, noop_fold_pat};
use rustc::hir::print::pat_to_string;
use syntax::ptr::P;
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::FnvHashMap;

pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
Expand Down Expand Up @@ -279,13 +281,7 @@ fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
Ok(_) => {}

Err(err) => {
let mut diag = struct_span_err!(cx.tcx.sess, err.span, E0471,
"constant evaluation error: {}",
err.description());
if !p.span.contains(err.span) {
diag.span_note(p.span, "in pattern here");
}
diag.emit();
report_const_eval_err(cx.tcx, &err, p.span, "pattern").emit();
}
}
}
Expand Down Expand Up @@ -838,22 +834,19 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us
}
}

fn range_covered_by_constructor(ctor: &Constructor,
from: &ConstVal, to: &ConstVal) -> Option<bool> {
fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
ctor: &Constructor,
from: &ConstVal, to: &ConstVal)
-> Result<bool, ErrorReported> {
let (c_from, c_to) = match *ctor {
ConstantValue(ref value) => (value, value),
ConstantRange(ref from, ref to) => (from, to),
Single => return Some(true),
Single => return Ok(true),
_ => bug!()
};
let cmp_from = compare_const_vals(c_from, from);
let cmp_to = compare_const_vals(c_to, to);
match (cmp_from, cmp_to) {
(Some(cmp_from), Some(cmp_to)) => {
Some(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
}
_ => None
}
let cmp_from = compare_const_vals(tcx, span, c_from, from)?;
let cmp_to = compare_const_vals(tcx, span, c_to, to)?;
Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
}

fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
Expand Down Expand Up @@ -965,27 +958,25 @@ pub fn specialize<'a, 'b, 'tcx>(
Some(vec![(pat, Some(mt.ty))])
} else {
let expr_value = eval_const_expr(cx.tcx, &expr);
match range_covered_by_constructor(constructor, &expr_value, &expr_value) {
Some(true) => Some(vec![]),
Some(false) => None,
None => {
span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms");
None
}
match range_covered_by_constructor(
cx.tcx, expr.span, constructor, &expr_value, &expr_value
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
Err(ErrorReported) => None,
}
}
}

PatKind::Range(ref from, ref to) => {
let from_value = eval_const_expr(cx.tcx, &from);
let to_value = eval_const_expr(cx.tcx, &to);
match range_covered_by_constructor(constructor, &from_value, &to_value) {
Some(true) => Some(vec![]),
Some(false) => None,
None => {
span_err!(cx.tcx.sess, pat_span, E0299, "mismatched types between arms");
None
}
match range_covered_by_constructor(
cx.tcx, pat_span, constructor, &from_value, &to_value
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
Err(ErrorReported) => None,
}
}

Expand Down
42 changes: 22 additions & 20 deletions src/librustc_const_eval/diagnostics.rs
Expand Up @@ -551,44 +551,46 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases.
See also https://github.com/rust-lang/rust/issues/14587
"##,

E0306: r##"
In an array literal `[x; N]`, `N` is the number of elements in the array. This
must be an unsigned integer. Erroneous code example:
E0080: r##"
This error indicates that the compiler was unable to sensibly evaluate an
constant expression that had to be evaluated. Attempting to divide by 0
or causing integer overflow are two ways to induce this error. For example:
```compile_fail
let x = [0i32; true]; // error: expected positive integer for repeat count,
// found boolean
enum Enum {
X = (1 << 500),
Y = (1 / 0)
}
```
Working example:
Ensure that the expressions given can be evaluated as the desired integer type.
See the FFI section of the Reference for more information about using a custom
integer type:
```
let x = [0i32; 2];
```
https://doc.rust-lang.org/reference.html#ffi-attributes
"##,

E0307: r##"
The length of an array is part of its type. For this reason, this length must
be a compile-time constant. Erroneous code example:

E0306: r##"
In an array literal `[x; N]`, `N` is the number of elements in the array. This
must be an unsigned integer. Erroneous code example:
```compile_fail
let len = 10;
let x = [0i32; len]; // error: expected constant integer for repeat count,
// found variable
let x = [0i32; true]; // error: expected positive integer for repeat count,
// found boolean
```
Working example:
```
let x = [0i32; 10];
let x = [0i32; 2];
```
"##,

}


register_diagnostics! {
E0298, // mismatched types between arms
E0299, // mismatched types between arms
E0471, // constant evaluation error: ..
E0298, // cannot compare constants
// E0299, // mismatched types between arms
// E0471, // constant evaluation error (in pattern)
}

0 comments on commit 7966739

Please sign in to comment.