1 // Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use self::ConstVal::*;
12 pub use rustc_const_math::ConstInt;
16 use hir::def_id::DefId;
18 use ty::subst::Substs;
19 use util::common::ErrorReported;
20 use rustc_const_math::*;
22 use graphviz::IntoCow;
23 use errors::DiagnosticBuilder;
24 use syntax::symbol::InternedString;
29 use std::collections::BTreeMap;
32 pub type EvalResult<'tcx> = Result<ConstVal<'tcx>, ConstEvalErr<'tcx>>;
34 #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
35 pub enum ConstVal<'tcx> {
43 Function(DefId, &'tcx Substs<'tcx>),
44 Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
45 Tuple(Vec<ConstVal<'tcx>>),
46 Array(Vec<ConstVal<'tcx>>),
47 Repeat(Box<ConstVal<'tcx>>, u64),
50 impl<'tcx> ConstVal<'tcx> {
51 pub fn description(&self) -> &'static str {
53 Float(f) => f.description(),
54 Integral(i) => i.description(),
55 Str(_) => "string literal",
56 ByteStr(_) => "byte string literal",
59 Variant(_) => "enum variant",
60 Struct(_) => "struct",
62 Function(..) => "function definition",
64 Repeat(..) => "repeat",
68 pub fn to_const_int(&self) -> Option<ConstInt> {
70 ConstVal::Integral(i) => Some(i),
71 ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)),
72 ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
78 #[derive(Clone, Debug)]
79 pub struct ConstEvalErr<'tcx> {
81 pub kind: ErrKind<'tcx>,
84 #[derive(Clone, Debug)]
85 pub enum ErrKind<'tcx> {
88 NegateOn(ConstVal<'tcx>),
89 NotOn(ConstVal<'tcx>),
92 UnimplementedConstVal(&'static str),
97 IndexOutOfBounds { len: u64, index: u64 },
105 ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
110 impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
111 fn from(err: ConstMathErr) -> ErrKind<'tcx> {
113 ConstMathErr::UnsignedNegation => ErrKind::TypeckError,
114 _ => ErrKind::Math(err)
119 #[derive(Clone, Debug)]
120 pub enum ConstEvalErrDescription<'a> {
121 Simple(Cow<'a, str>),
124 impl<'a> ConstEvalErrDescription<'a> {
125 /// Return a one-line description of the error, for lints and such
126 pub fn into_oneline(self) -> Cow<'a, str> {
128 ConstEvalErrDescription::Simple(simple) => simple,
133 impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
134 pub fn description(&self) -> ConstEvalErrDescription {
135 use self::ErrKind::*;
136 use self::ConstEvalErrDescription::*;
138 macro_rules! simple {
139 ($msg:expr) => ({ Simple($msg.into_cow()) });
140 ($fmt:expr, $($arg:tt)+) => ({
141 Simple(format!($fmt, $($arg)+).into_cow())
146 CannotCast => simple!("can't cast this type"),
147 NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
148 NotOn(ref const_val) => simple!("not on {}", const_val.description()),
150 MissingStructField => simple!("nonexistent struct field"),
151 NonConstPath => simple!("non-constant path in constant expression"),
152 UnimplementedConstVal(what) =>
153 simple!("unimplemented constant expression: {}", what),
154 ExpectedConstTuple => simple!("expected constant tuple"),
155 ExpectedConstStruct => simple!("expected constant struct"),
156 IndexedNonVec => simple!("indexing is only supported for arrays"),
157 IndexNotUsize => simple!("indices must be of type `usize`"),
158 IndexOutOfBounds { len, index } => {
159 simple!("index out of bounds: the len is {} but the index is {}",
163 MiscBinaryOp => simple!("bad operands for binary"),
164 MiscCatchAll => simple!("unsupported constant expr"),
165 IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
166 Math(ref err) => Simple(err.description().into_cow()),
168 ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
170 TypeckError => simple!("type-checking failed"),
174 pub fn struct_error(&self,
175 tcx: TyCtxt<'a, 'gcx, 'tcx>,
178 -> DiagnosticBuilder<'gcx>
181 while let &ConstEvalErr {
182 kind: ErrKind::ErroneousReferencedConstant(box ref i_err), ..
187 let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
188 err.note(tcx, primary_span, primary_kind, &mut diag);
193 _tcx: TyCtxt<'a, 'gcx, 'tcx>,
196 diag: &mut DiagnosticBuilder)
198 match self.description() {
199 ConstEvalErrDescription::Simple(message) => {
200 diag.span_label(self.span, &message);
204 if !primary_span.contains(self.span) {
205 diag.span_note(primary_span,
206 &format!("for {} here", primary_kind));
211 tcx: TyCtxt<'a, 'gcx, 'tcx>,
215 if let ErrKind::TypeckError = self.kind {
218 self.struct_error(tcx, primary_span, primary_kind).emit();
222 /// Returns the value of the length-valued expression
223 pub fn eval_length(tcx: TyCtxt,
226 -> Result<usize, ErrorReported>
228 let count_expr = &tcx.hir.body(count).value;
229 let count_def_id = tcx.hir.body_owner_def_id(count);
230 let substs = Substs::empty();
231 match tcx.at(count_expr.span).const_eval((count_def_id, substs)) {
232 Ok(Integral(Usize(count))) => {
233 let val = count.as_u64(tcx.sess.target.uint_type);
234 assert_eq!(val as usize as u64, val);
238 Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported),
240 let mut diag = err.struct_error(tcx, count_expr.span, reason);
242 if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
243 if let Def::Local(..) = path.def {
244 diag.note(&format!("`{}` is a variable",
245 tcx.hir.node_to_pretty_string(count_expr.id)));