Auto merge of #34907 - arielb1:found-parse-error, r=nikomatsakis
Centralize and clean type error reporting Refactors the code that handles type errors to be cleaner and fixes various edge cases. This made the already-bad "type mismatch resolving" error message somewhat uglier. I want to fix that in another commit before this PR is merged. Fixes #31173 r? @jonathandturner, cc @nikomatsakis
This commit is contained in:
commit
f2e59cc6aa
85 changed files with 1017 additions and 844 deletions
|
|
@ -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" }
|
||||
|
|
@ -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};
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>,
|
||||
|
|
@ -965,13 +958,12 @@ 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -979,13 +971,12 @@ pub fn specialize<'a, 'b, 'tcx>(
|
|||
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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -551,6 +551,26 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases.
|
|||
See also https://github.com/rust-lang/rust/issues/14587
|
||||
"##,
|
||||
|
||||
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
|
||||
enum Enum {
|
||||
X = (1 << 500),
|
||||
Y = (1 / 0)
|
||||
}
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
https://doc.rust-lang.org/reference.html#ffi-attributes
|
||||
"##,
|
||||
|
||||
|
||||
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:
|
||||
|
|
@ -566,29 +586,11 @@ Working example:
|
|||
let x = [0i32; 2];
|
||||
```
|
||||
"##,
|
||||
|
||||
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:
|
||||
|
||||
```compile_fail
|
||||
let len = 10;
|
||||
let x = [0i32; len]; // error: expected constant integer for repeat count,
|
||||
// found variable
|
||||
```
|
||||
|
||||
Working example:
|
||||
|
||||
```
|
||||
let x = [0i32; 10];
|
||||
```
|
||||
"##,
|
||||
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ use rustc::hir::pat_util::def_to_path;
|
|||
use rustc::ty::{self, Ty, TyCtxt, subst};
|
||||
use rustc::ty::util::IntTypeExt;
|
||||
use rustc::traits::ProjectionMode;
|
||||
use rustc::util::common::ErrorReported;
|
||||
use rustc::util::nodemap::NodeMap;
|
||||
use rustc::lint;
|
||||
|
||||
|
|
@ -43,6 +44,7 @@ use std::cmp::Ordering;
|
|||
use std::collections::hash_map::Entry::Vacant;
|
||||
|
||||
use rustc_const_math::*;
|
||||
use rustc_errors::{DiagnosticBuilder, check_old_school};
|
||||
|
||||
macro_rules! math {
|
||||
($e:expr, $op:expr) => {
|
||||
|
|
@ -338,20 +340,71 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
Ok(P(hir::Pat { id: expr.id, node: pat, span: span }))
|
||||
}
|
||||
|
||||
pub fn report_const_eval_err<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
err: &ConstEvalErr,
|
||||
primary_span: Span,
|
||||
primary_kind: &str)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
{
|
||||
let mut err = err;
|
||||
while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err {
|
||||
err = i_err;
|
||||
}
|
||||
|
||||
let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
|
||||
note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag);
|
||||
diag
|
||||
}
|
||||
|
||||
pub fn fatal_const_eval_err<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
err: &ConstEvalErr,
|
||||
primary_span: Span,
|
||||
primary_kind: &str)
|
||||
-> !
|
||||
{
|
||||
report_const_eval_err(tcx, err, primary_span, primary_kind).emit();
|
||||
tcx.sess.abort_if_errors();
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub fn note_const_eval_err<'a, 'tcx>(
|
||||
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
err: &ConstEvalErr,
|
||||
primary_span: Span,
|
||||
primary_kind: &str,
|
||||
diag: &mut DiagnosticBuilder)
|
||||
{
|
||||
match err.description() {
|
||||
ConstEvalErrDescription::Simple(message) => {
|
||||
if check_old_school() {
|
||||
diag.note(&message);
|
||||
} else {
|
||||
diag.span_label(err.span, &message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !primary_span.contains(err.span) {
|
||||
diag.span_note(primary_span,
|
||||
&format!("for {} here", primary_kind));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
e: &Expr) -> ConstVal {
|
||||
match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
|
||||
Ok(r) => r,
|
||||
// non-const path still needs to be a fatal error, because enums are funky
|
||||
Err(s) => {
|
||||
report_const_eval_err(tcx, &s, e.span, "expression").emit();
|
||||
match s.kind {
|
||||
NonConstPath |
|
||||
UnimplementedConstVal(_) => tcx.sess.span_fatal(s.span, &s.description()),
|
||||
_ => {
|
||||
tcx.sess.span_err(s.span, &s.description());
|
||||
Dummy
|
||||
}
|
||||
UnimplementedConstVal(_) => tcx.sess.abort_if_errors(),
|
||||
_ => {}
|
||||
}
|
||||
Dummy
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -400,6 +453,7 @@ pub enum ErrKind {
|
|||
IntermediateUnsignedNegative,
|
||||
/// Expected, Got
|
||||
TypeMismatch(String, ConstInt),
|
||||
|
||||
BadType(ConstVal),
|
||||
ErroneousReferencedConstant(Box<ConstEvalErr>),
|
||||
CharCast(ConstInt),
|
||||
|
|
@ -411,57 +465,79 @@ impl From<ConstMathErr> for ErrKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ConstEvalErrDescription<'a> {
|
||||
Simple(Cow<'a, str>),
|
||||
}
|
||||
|
||||
impl<'a> ConstEvalErrDescription<'a> {
|
||||
/// Return a one-line description of the error, for lints and such
|
||||
pub fn into_oneline(self) -> Cow<'a, str> {
|
||||
match self {
|
||||
ConstEvalErrDescription::Simple(simple) => simple,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstEvalErr {
|
||||
pub fn description(&self) -> Cow<str> {
|
||||
pub fn description(&self) -> ConstEvalErrDescription {
|
||||
use self::ErrKind::*;
|
||||
use self::ConstEvalErrDescription::*;
|
||||
|
||||
macro_rules! simple {
|
||||
($msg:expr) => ({ Simple($msg.into_cow()) });
|
||||
($fmt:expr, $($arg:tt)+) => ({
|
||||
Simple(format!($fmt, $($arg)+).into_cow())
|
||||
})
|
||||
}
|
||||
|
||||
match self.kind {
|
||||
CannotCast => "can't cast this type".into_cow(),
|
||||
CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(),
|
||||
InvalidOpForInts(_) => "can't do this op on integrals".into_cow(),
|
||||
InvalidOpForBools(_) => "can't do this op on bools".into_cow(),
|
||||
InvalidOpForFloats(_) => "can't do this op on floats".into_cow(),
|
||||
InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
|
||||
InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
|
||||
NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(),
|
||||
NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(),
|
||||
CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(),
|
||||
CannotCast => simple!("can't cast this type"),
|
||||
CannotCastTo(s) => simple!("can't cast this type to {}", s),
|
||||
InvalidOpForInts(_) => simple!("can't do this op on integrals"),
|
||||
InvalidOpForBools(_) => simple!("can't do this op on bools"),
|
||||
InvalidOpForFloats(_) => simple!("can't do this op on floats"),
|
||||
InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"),
|
||||
InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"),
|
||||
NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
|
||||
NotOn(ref const_val) => simple!("not on {}", const_val.description()),
|
||||
CallOn(ref const_val) => simple!("call on {}", const_val.description()),
|
||||
|
||||
MissingStructField => "nonexistent struct field".into_cow(),
|
||||
NonConstPath => "non-constant path in constant expression".into_cow(),
|
||||
MissingStructField => simple!("nonexistent struct field"),
|
||||
NonConstPath => simple!("non-constant path in constant expression"),
|
||||
UnimplementedConstVal(what) =>
|
||||
format!("unimplemented constant expression: {}", what).into_cow(),
|
||||
UnresolvedPath => "unresolved path in constant expression".into_cow(),
|
||||
ExpectedConstTuple => "expected constant tuple".into_cow(),
|
||||
ExpectedConstStruct => "expected constant struct".into_cow(),
|
||||
TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
|
||||
IndexedNonVec => "indexing is only supported for arrays".into_cow(),
|
||||
IndexNegative => "indices must be non-negative integers".into_cow(),
|
||||
IndexNotInt => "indices must be integers".into_cow(),
|
||||
simple!("unimplemented constant expression: {}", what),
|
||||
UnresolvedPath => simple!("unresolved path in constant expression"),
|
||||
ExpectedConstTuple => simple!("expected constant tuple"),
|
||||
ExpectedConstStruct => simple!("expected constant struct"),
|
||||
TupleIndexOutOfBounds => simple!("tuple index out of bounds"),
|
||||
IndexedNonVec => simple!("indexing is only supported for arrays"),
|
||||
IndexNegative => simple!("indices must be non-negative integers"),
|
||||
IndexNotInt => simple!("indices must be integers"),
|
||||
IndexOutOfBounds { len, index } => {
|
||||
format!("index out of bounds: the len is {} but the index is {}",
|
||||
len, index).into_cow()
|
||||
simple!("index out of bounds: the len is {} but the index is {}",
|
||||
len, index)
|
||||
}
|
||||
RepeatCountNotNatural => "repeat count must be a natural number".into_cow(),
|
||||
RepeatCountNotInt => "repeat count must be integers".into_cow(),
|
||||
RepeatCountNotNatural => simple!("repeat count must be a natural number"),
|
||||
RepeatCountNotInt => simple!("repeat count must be integers"),
|
||||
|
||||
MiscBinaryOp => "bad operands for binary".into_cow(),
|
||||
MiscCatchAll => "unsupported constant expr".into_cow(),
|
||||
IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(),
|
||||
Math(ref err) => err.description().into_cow(),
|
||||
MiscBinaryOp => simple!("bad operands for binary"),
|
||||
MiscCatchAll => simple!("unsupported constant expr"),
|
||||
IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
|
||||
Math(ref err) => Simple(err.description().into_cow()),
|
||||
|
||||
IntermediateUnsignedNegative => "during the computation of an unsigned a negative \
|
||||
number was encountered. This is most likely a bug in\
|
||||
the constant evaluator".into_cow(),
|
||||
IntermediateUnsignedNegative => simple!(
|
||||
"during the computation of an unsigned a negative \
|
||||
number was encountered. This is most likely a bug in\
|
||||
the constant evaluator"),
|
||||
|
||||
TypeMismatch(ref expected, ref got) => {
|
||||
format!("mismatched types: expected `{}`, found `{}`",
|
||||
expected, got.description()).into_cow()
|
||||
simple!("expected {}, found {}", expected, got.description())
|
||||
},
|
||||
BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(),
|
||||
ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(),
|
||||
BadType(ref i) => simple!("value of wrong type: {:?}", i),
|
||||
ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
|
||||
CharCast(ref got) => {
|
||||
format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow()
|
||||
simple!("only `u8` can be cast as `char`, not `{}`", got.description())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -1199,8 +1275,10 @@ fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>, span: Span) -> ConstFl
|
|||
})
|
||||
}
|
||||
|
||||
pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
|
||||
match (a, b) {
|
||||
pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
|
||||
-> Result<Ordering, ErrorReported>
|
||||
{
|
||||
let result = match (a, b) {
|
||||
(&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
|
||||
(&Float(a), &Float(b)) => a.try_cmp(b).ok(),
|
||||
(&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
|
||||
|
|
@ -1208,62 +1286,82 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
|
|||
(&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
|
||||
(&Char(a), &Char(ref b)) => Some(a.cmp(b)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
match result {
|
||||
Some(result) => Ok(result),
|
||||
None => {
|
||||
// FIXME: can this ever be reached?
|
||||
span_err!(tcx.sess, span, E0298,
|
||||
"type mismatch comparing {} and {}",
|
||||
a.description(),
|
||||
b.description());
|
||||
Err(ErrorReported)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compare_lit_exprs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
span: Span,
|
||||
a: &Expr,
|
||||
b: &Expr) -> Option<Ordering> {
|
||||
b: &Expr) -> Result<Ordering, ErrorReported> {
|
||||
let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
tcx.sess.span_err(a.span, &e.description());
|
||||
return None;
|
||||
report_const_eval_err(tcx, &e, a.span, "expression").emit();
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
};
|
||||
let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
tcx.sess.span_err(b.span, &e.description());
|
||||
return None;
|
||||
report_const_eval_err(tcx, &e, b.span, "expression").emit();
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
};
|
||||
compare_const_vals(&a, &b)
|
||||
compare_const_vals(tcx, span, &a, &b)
|
||||
}
|
||||
|
||||
|
||||
/// Returns the repeat count for a repeating vector expression.
|
||||
pub fn eval_repeat_count<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
count_expr: &hir::Expr) -> usize {
|
||||
/// Returns the value of the length-valued expression
|
||||
pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
count_expr: &hir::Expr,
|
||||
reason: &str)
|
||||
-> Result<usize, ErrorReported>
|
||||
{
|
||||
let hint = UncheckedExprHint(tcx.types.usize);
|
||||
match eval_const_expr_partial(tcx, count_expr, hint, None) {
|
||||
Ok(Integral(Usize(count))) => {
|
||||
let val = count.as_u64(tcx.sess.target.uint_type);
|
||||
assert_eq!(val as usize as u64, val);
|
||||
val as usize
|
||||
Ok(val as usize)
|
||||
},
|
||||
Ok(const_val) => {
|
||||
span_err!(tcx.sess, count_expr.span, E0306,
|
||||
"expected positive integer for repeat count, found {}",
|
||||
"expected usize for {}, found {}",
|
||||
reason,
|
||||
const_val.description());
|
||||
0
|
||||
Err(ErrorReported)
|
||||
}
|
||||
Err(err) => {
|
||||
let err_msg = match count_expr.node {
|
||||
let mut diag = report_const_eval_err(
|
||||
tcx, &err, count_expr.span, reason);
|
||||
|
||||
match count_expr.node {
|
||||
hir::ExprPath(None, hir::Path {
|
||||
global: false,
|
||||
ref segments,
|
||||
..
|
||||
}) if segments.len() == 1 =>
|
||||
format!("found variable"),
|
||||
_ => match err.kind {
|
||||
MiscCatchAll => format!("but found {}", err.description()),
|
||||
_ => format!("but {}", err.description())
|
||||
}) if segments.len() == 1 => {
|
||||
if let Some(Def::Local(..)) = tcx.expect_def_or_none(count_expr.id) {
|
||||
diag.note(&format!("`{}` is a variable", segments[0].name));
|
||||
}
|
||||
}
|
||||
};
|
||||
span_err!(tcx.sess, count_expr.span, E0307,
|
||||
"expected constant integer for repeat count, {}", err_msg);
|
||||
0
|
||||
_ => {}
|
||||
}
|
||||
|
||||
diag.emit();
|
||||
Err(ErrorReported)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#[macro_use] extern crate rustc;
|
||||
extern crate rustc_back;
|
||||
extern crate rustc_const_math;
|
||||
extern crate rustc_errors;
|
||||
extern crate graphviz;
|
||||
extern crate syntax_pos;
|
||||
extern crate serialize as rustc_serialize; // used by deriving
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue