]> git.lizzy.rs Git - rust.git/blob - src/librustc_const_eval/eval.rs
Rollup merge of #41112 - ollie27:rustdoc_pull, r=GuillaumeGomez
[rust.git] / src / librustc_const_eval / eval.rs
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.
4 //
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.
10
11 use rustc::middle::const_val::ConstVal::*;
12 use rustc::middle::const_val::ConstVal;
13 use self::ErrKind::*;
14
15 use rustc::hir::map as hir_map;
16 use rustc::hir::map::blocks::FnLikeNode;
17 use rustc::traits;
18 use rustc::hir::def::Def;
19 use rustc::hir::def_id::DefId;
20 use rustc::ty::{self, Ty, TyCtxt};
21 use rustc::ty::util::IntTypeExt;
22 use rustc::ty::subst::{Substs, Subst};
23 use rustc::traits::Reveal;
24 use rustc::util::common::ErrorReported;
25 use rustc::util::nodemap::DefIdMap;
26
27 use graphviz::IntoCow;
28 use syntax::ast;
29 use rustc::hir::{self, Expr};
30 use syntax_pos::{Span, DUMMY_SP};
31
32 use std::borrow::Cow;
33 use std::cmp::Ordering;
34
35 use rustc_const_math::*;
36 use rustc_errors::DiagnosticBuilder;
37
38 macro_rules! signal {
39     ($e:expr, $exn:expr) => {
40         return Err(ConstEvalErr { span: $e.span, kind: $exn })
41     }
42 }
43
44 macro_rules! math {
45     ($e:expr, $op:expr) => {
46         match $op {
47             Ok(val) => val,
48             Err(e) => signal!($e, ErrKind::from(e)),
49         }
50     }
51 }
52
53 fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
54                                   variant_def: DefId)
55                                   -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> {
56     if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) {
57         let enum_node_id = tcx.hir.get_parent(variant_node_id);
58         if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) {
59             if let hir::ItemEnum(ref edef, _) = it.node {
60                 for variant in &edef.variants {
61                     if variant.node.data.id() == variant_node_id {
62                         return variant.node.disr_expr.map(|e| {
63                             let def_id = tcx.hir.body_owner_def_id(e);
64                             (&tcx.hir.body(e).value,
65                              tcx.item_tables(def_id))
66                         });
67                     }
68                 }
69             }
70         }
71     }
72     None
73 }
74
75 /// * `def_id` is the id of the constant.
76 /// * `substs` is the monomorphized substitutions for the expression.
77 ///
78 /// `substs` is optional and is used for associated constants.
79 /// This generally happens in late/trans const evaluation.
80 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
81                                         def_id: DefId,
82                                         substs: &'tcx Substs<'tcx>)
83                                         -> Option<(&'tcx Expr,
84                                                    &'a ty::TypeckTables<'tcx>)> {
85     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
86         match tcx.hir.find(node_id) {
87             None => None,
88             Some(hir_map::NodeItem(&hir::Item {
89                 node: hir::ItemConst(_, body), ..
90             })) |
91             Some(hir_map::NodeImplItem(&hir::ImplItem {
92                 node: hir::ImplItemKind::Const(_, body), ..
93             })) => {
94                 Some((&tcx.hir.body(body).value,
95                       tcx.item_tables(def_id)))
96             }
97             Some(hir_map::NodeTraitItem(ti)) => match ti.node {
98                 hir::TraitItemKind::Const(_, default) => {
99                     // If we have a trait item and the substitutions for it,
100                     // `resolve_trait_associated_const` will select an impl
101                     // or the default.
102                     let trait_id = tcx.hir.get_parent(node_id);
103                     let trait_id = tcx.hir.local_def_id(trait_id);
104                     let default_value = default.map(|body| {
105                         (&tcx.hir.body(body).value,
106                             tcx.item_tables(def_id))
107                     });
108                     resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
109                 }
110                 _ => None
111             },
112             Some(_) => None
113         }
114     } else {
115         let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
116             (&body.value, tcx.item_tables(def_id))
117         });
118         match tcx.sess.cstore.describe_def(def_id) {
119             Some(Def::AssociatedConst(_)) => {
120                 let trait_id = tcx.sess.cstore.trait_of_item(def_id);
121                 // As mentioned in the comments above for in-crate
122                 // constants, we only try to find the expression for a
123                 // trait-associated const if the caller gives us the
124                 // substitutions for the reference to it.
125                 if let Some(trait_id) = trait_id {
126                     resolve_trait_associated_const(tcx, def_id, expr_and_tables,
127                                                    trait_id, substs)
128                 } else {
129                     expr_and_tables
130                 }
131             },
132             Some(Def::Const(..)) => expr_and_tables,
133             _ => None
134         }
135     }
136 }
137
138 fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
139                                    -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)>
140 {
141     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
142         FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| {
143             if fn_like.constness() == hir::Constness::Const {
144                 Some((tcx.hir.body(fn_like.body()),
145                       tcx.item_tables(def_id)))
146             } else {
147                 None
148             }
149         })
150     } else {
151         if tcx.sess.cstore.is_const_fn(def_id) {
152             tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
153                 (body, tcx.item_tables(def_id))
154             })
155         } else {
156             None
157         }
158     }
159 }
160
161 fn build_const_eval_err<'a, 'tcx>(
162     tcx: TyCtxt<'a, 'tcx, 'tcx>,
163     err: &ConstEvalErr,
164     primary_span: Span,
165     primary_kind: &str)
166     -> DiagnosticBuilder<'tcx>
167 {
168     let mut err = err;
169     while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err {
170         err = i_err;
171     }
172
173     let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
174     note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag);
175     diag
176 }
177
178 pub fn report_const_eval_err<'a, 'tcx>(
179     tcx: TyCtxt<'a, 'tcx, 'tcx>,
180     err: &ConstEvalErr,
181     primary_span: Span,
182     primary_kind: &str)
183 {
184     if let TypeckError = err.kind {
185         return;
186     }
187     build_const_eval_err(tcx, err, primary_span, primary_kind).emit();
188 }
189
190 pub fn fatal_const_eval_err<'a, 'tcx>(
191     tcx: TyCtxt<'a, 'tcx, 'tcx>,
192     err: &ConstEvalErr,
193     primary_span: Span,
194     primary_kind: &str)
195     -> !
196 {
197     report_const_eval_err(tcx, err, primary_span, primary_kind);
198     tcx.sess.abort_if_errors();
199     unreachable!()
200 }
201
202 pub fn note_const_eval_err<'a, 'tcx>(
203     _tcx: TyCtxt<'a, 'tcx, 'tcx>,
204     err: &ConstEvalErr,
205     primary_span: Span,
206     primary_kind: &str,
207     diag: &mut DiagnosticBuilder)
208 {
209     match err.description() {
210         ConstEvalErrDescription::Simple(message) => {
211             diag.span_label(err.span, &message);
212         }
213     }
214
215     if !primary_span.contains(err.span) {
216         diag.span_note(primary_span,
217                        &format!("for {} here", primary_kind));
218     }
219 }
220
221 pub struct ConstContext<'a, 'tcx: 'a> {
222     tcx: TyCtxt<'a, 'tcx, 'tcx>,
223     tables: &'a ty::TypeckTables<'tcx>,
224     substs: &'tcx Substs<'tcx>,
225     fn_args: Option<DefIdMap<ConstVal<'tcx>>>
226 }
227
228 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
229     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self {
230         let def_id = tcx.hir.body_owner_def_id(body);
231         ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
232         ConstContext::with_tables(tcx, tcx.item_tables(def_id))
233     }
234
235     pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self {
236         ConstContext {
237             tcx: tcx,
238             tables: tables,
239             substs: tcx.intern_substs(&[]),
240             fn_args: None
241         }
242     }
243
244     /// Evaluate a constant expression in a context where the expression isn't
245     /// guaranteed to be evaluatable.
246     pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> {
247         if self.tables.tainted_by_errors {
248             signal!(e, TypeckError);
249         }
250         eval_const_expr_partial(self, e)
251     }
252 }
253
254 #[derive(Clone, Debug)]
255 pub struct ConstEvalErr<'tcx> {
256     pub span: Span,
257     pub kind: ErrKind<'tcx>,
258 }
259
260 #[derive(Clone, Debug)]
261 pub enum ErrKind<'tcx> {
262     CannotCast,
263     MissingStructField,
264     NegateOn(ConstVal<'tcx>),
265     NotOn(ConstVal<'tcx>),
266     CallOn(ConstVal<'tcx>),
267
268     NonConstPath,
269     UnimplementedConstVal(&'static str),
270     ExpectedConstTuple,
271     ExpectedConstStruct,
272     IndexedNonVec,
273     IndexNotUsize,
274     IndexOutOfBounds { len: u64, index: u64 },
275
276     MiscBinaryOp,
277     MiscCatchAll,
278
279     IndexOpFeatureGated,
280     Math(ConstMathErr),
281
282     ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
283
284     TypeckError
285 }
286
287 impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
288     fn from(err: ConstMathErr) -> ErrKind<'tcx> {
289         match err {
290             ConstMathErr::UnsignedNegation => TypeckError,
291             _ => Math(err)
292         }
293     }
294 }
295
296 #[derive(Clone, Debug)]
297 pub enum ConstEvalErrDescription<'a> {
298     Simple(Cow<'a, str>),
299 }
300
301 impl<'a> ConstEvalErrDescription<'a> {
302     /// Return a one-line description of the error, for lints and such
303     pub fn into_oneline(self) -> Cow<'a, str> {
304         match self {
305             ConstEvalErrDescription::Simple(simple) => simple,
306         }
307     }
308 }
309
310 impl<'tcx> ConstEvalErr<'tcx> {
311     pub fn description(&self) -> ConstEvalErrDescription {
312         use self::ErrKind::*;
313         use self::ConstEvalErrDescription::*;
314
315         macro_rules! simple {
316             ($msg:expr) => ({ Simple($msg.into_cow()) });
317             ($fmt:expr, $($arg:tt)+) => ({
318                 Simple(format!($fmt, $($arg)+).into_cow())
319             })
320         }
321
322         match self.kind {
323             CannotCast => simple!("can't cast this type"),
324             NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
325             NotOn(ref const_val) => simple!("not on {}", const_val.description()),
326             CallOn(ref const_val) => simple!("call on {}", const_val.description()),
327
328             MissingStructField  => simple!("nonexistent struct field"),
329             NonConstPath        => simple!("non-constant path in constant expression"),
330             UnimplementedConstVal(what) =>
331                 simple!("unimplemented constant expression: {}", what),
332             ExpectedConstTuple => simple!("expected constant tuple"),
333             ExpectedConstStruct => simple!("expected constant struct"),
334             IndexedNonVec => simple!("indexing is only supported for arrays"),
335             IndexNotUsize => simple!("indices must be of type `usize`"),
336             IndexOutOfBounds { len, index } => {
337                 simple!("index out of bounds: the len is {} but the index is {}",
338                         len, index)
339             }
340
341             MiscBinaryOp => simple!("bad operands for binary"),
342             MiscCatchAll => simple!("unsupported constant expr"),
343             IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
344             Math(ref err) => Simple(err.description().into_cow()),
345
346             ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
347
348             TypeckError => simple!("type-checking failed"),
349         }
350     }
351 }
352
353 pub type EvalResult<'tcx> = Result<ConstVal<'tcx>, ConstEvalErr<'tcx>>;
354 pub type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
355
356 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
357                                      e: &Expr) -> EvalResult<'tcx> {
358     let tcx = cx.tcx;
359     let ety = cx.tables.expr_ty(e);
360
361     // Avoid applying substitutions if they're empty, that'd ICE.
362     let ety = if cx.substs.is_empty() {
363         ety
364     } else {
365         ety.subst(tcx, cx.substs)
366     };
367
368     let result = match e.node {
369       hir::ExprUnary(hir::UnNeg, ref inner) => {
370         // unary neg literals already got their sign during creation
371         if let hir::ExprLit(ref lit) = inner.node {
372             use syntax::ast::*;
373             use syntax::ast::LitIntType::*;
374             const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128;
375             const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128;
376             const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
377             const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
378             const I128_OVERFLOW: u128 = i128::min_value() as u128;
379             match (&lit.node, &ety.sty) {
380                 (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
381                 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
382                     return Ok(Integral(I8(i8::min_value())))
383                 },
384                 (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
385                 (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
386                     return Ok(Integral(I16(i16::min_value())))
387                 },
388                 (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
389                 (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
390                     return Ok(Integral(I32(i32::min_value())))
391                 },
392                 (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
393                 (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
394                     return Ok(Integral(I64(i64::min_value())))
395                 },
396                 (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
397                 (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
398                     return Ok(Integral(I128(i128::min_value())))
399                 },
400                 (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) |
401                 (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
402                     match tcx.sess.target.int_type {
403                         IntTy::I16 => if n == I16_OVERFLOW {
404                             return Ok(Integral(Isize(Is16(i16::min_value()))));
405                         },
406                         IntTy::I32 => if n == I32_OVERFLOW {
407                             return Ok(Integral(Isize(Is32(i32::min_value()))));
408                         },
409                         IntTy::I64 => if n == I64_OVERFLOW {
410                             return Ok(Integral(Isize(Is64(i64::min_value()))));
411                         },
412                         _ => span_bug!(e.span, "typeck error")
413                     }
414                 },
415                 _ => {},
416             }
417         }
418         match cx.eval(inner)? {
419           Float(f) => Float(-f),
420           Integral(i) => Integral(math!(e, -i)),
421           const_val => signal!(e, NegateOn(const_val)),
422         }
423       }
424       hir::ExprUnary(hir::UnNot, ref inner) => {
425         match cx.eval(inner)? {
426           Integral(i) => Integral(math!(e, !i)),
427           Bool(b) => Bool(!b),
428           const_val => signal!(e, NotOn(const_val)),
429         }
430       }
431       hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
432       hir::ExprBinary(op, ref a, ref b) => {
433         // technically, if we don't have type hints, but integral eval
434         // gives us a type through a type-suffix, cast or const def type
435         // we need to re-eval the other value of the BinOp if it was
436         // not inferred
437         match (cx.eval(a)?, cx.eval(b)?) {
438           (Float(a), Float(b)) => {
439             use std::cmp::Ordering::*;
440             match op.node {
441               hir::BiAdd => Float(math!(e, a + b)),
442               hir::BiSub => Float(math!(e, a - b)),
443               hir::BiMul => Float(math!(e, a * b)),
444               hir::BiDiv => Float(math!(e, a / b)),
445               hir::BiRem => Float(math!(e, a % b)),
446               hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
447               hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
448               hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
449               hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
450               hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
451               hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
452               _ => span_bug!(e.span, "typeck error"),
453             }
454           }
455           (Integral(a), Integral(b)) => {
456             use std::cmp::Ordering::*;
457             match op.node {
458               hir::BiAdd => Integral(math!(e, a + b)),
459               hir::BiSub => Integral(math!(e, a - b)),
460               hir::BiMul => Integral(math!(e, a * b)),
461               hir::BiDiv => Integral(math!(e, a / b)),
462               hir::BiRem => Integral(math!(e, a % b)),
463               hir::BiBitAnd => Integral(math!(e, a & b)),
464               hir::BiBitOr => Integral(math!(e, a | b)),
465               hir::BiBitXor => Integral(math!(e, a ^ b)),
466               hir::BiShl => Integral(math!(e, a << b)),
467               hir::BiShr => Integral(math!(e, a >> b)),
468               hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
469               hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
470               hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
471               hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
472               hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
473               hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
474               _ => span_bug!(e.span, "typeck error"),
475             }
476           }
477           (Bool(a), Bool(b)) => {
478             Bool(match op.node {
479               hir::BiAnd => a && b,
480               hir::BiOr => a || b,
481               hir::BiBitXor => a ^ b,
482               hir::BiBitAnd => a & b,
483               hir::BiBitOr => a | b,
484               hir::BiEq => a == b,
485               hir::BiNe => a != b,
486               hir::BiLt => a < b,
487               hir::BiLe => a <= b,
488               hir::BiGe => a >= b,
489               hir::BiGt => a > b,
490               _ => span_bug!(e.span, "typeck error"),
491              })
492           }
493           (Char(a), Char(b)) => {
494             Bool(match op.node {
495               hir::BiEq => a == b,
496               hir::BiNe => a != b,
497               hir::BiLt => a < b,
498               hir::BiLe => a <= b,
499               hir::BiGe => a >= b,
500               hir::BiGt => a > b,
501               _ => span_bug!(e.span, "typeck error"),
502              })
503           }
504
505           _ => signal!(e, MiscBinaryOp),
506         }
507       }
508       hir::ExprCast(ref base, _) => {
509         match cast_const(tcx, cx.eval(base)?, ety) {
510             Ok(val) => val,
511             Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
512         }
513       }
514       hir::ExprPath(ref qpath) => {
515         let substs = cx.tables.node_id_item_substs(e.id)
516             .unwrap_or_else(|| tcx.intern_substs(&[]));
517
518         // Avoid applying substitutions if they're empty, that'd ICE.
519         let substs = if cx.substs.is_empty() {
520             substs
521         } else {
522             substs.subst(tcx, cx.substs)
523         };
524
525           match cx.tables.qpath_def(qpath, e.id) {
526               Def::Const(def_id) |
527               Def::AssociatedConst(def_id) => {
528                   if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) {
529                       let cx = ConstContext::with_tables(tcx, tables);
530                       match cx.eval(expr) {
531                           Ok(val) => val,
532                           Err(ConstEvalErr { kind: TypeckError, .. }) => {
533                               signal!(e, TypeckError);
534                           }
535                           Err(err) => {
536                               debug!("bad reference: {:?}, {:?}", err.description(), err.span);
537                               signal!(e, ErroneousReferencedConstant(box err))
538                           },
539                       }
540                   } else {
541                       signal!(e, TypeckError);
542                   }
543               },
544               Def::VariantCtor(variant_def, ..) => {
545                   if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
546                       let cx = ConstContext::with_tables(tcx, tables);
547                       match cx.eval(expr) {
548                           Ok(val) => val,
549                           Err(ConstEvalErr { kind: TypeckError, .. }) => {
550                               signal!(e, TypeckError);
551                           }
552                           Err(err) => {
553                               debug!("bad reference: {:?}, {:?}", err.description(), err.span);
554                               signal!(e, ErroneousReferencedConstant(box err))
555                           },
556                       }
557                   } else {
558                       signal!(e, UnimplementedConstVal("enum variants"));
559                   }
560               }
561               Def::StructCtor(..) => {
562                   ConstVal::Struct(Default::default())
563               }
564               Def::Local(def_id) => {
565                   debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args);
566                   if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) {
567                       val.clone()
568                   } else {
569                       signal!(e, NonConstPath);
570                   }
571               },
572               Def::Method(id) | Def::Fn(id) => Function(id, substs),
573               Def::Err => span_bug!(e.span, "typeck error"),
574               _ => signal!(e, NonConstPath),
575           }
576       }
577       hir::ExprCall(ref callee, ref args) => {
578           let (did, substs) = match cx.eval(callee)? {
579               Function(did, substs) => (did, substs),
580               Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
581               callee => signal!(e, CallOn(callee)),
582           };
583           let (body, tables) = match lookup_const_fn_by_id(tcx, did) {
584               Some(x) => x,
585               None => signal!(e, NonConstPath),
586           };
587
588           let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
589                hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
590                _ => None
591            }).collect::<Vec<_>>();
592           assert_eq!(arg_defs.len(), args.len());
593
594           let mut call_args = DefIdMap();
595           for (arg, arg_expr) in arg_defs.into_iter().zip(args.iter()) {
596               let arg_val = cx.eval(arg_expr)?;
597               debug!("const call arg: {:?}", arg);
598               if let Some(def_id) = arg {
599                 assert!(call_args.insert(def_id, arg_val).is_none());
600               }
601           }
602           debug!("const call({:?})", call_args);
603           let callee_cx = ConstContext {
604             tcx: tcx,
605             tables: tables,
606             substs: substs,
607             fn_args: Some(call_args)
608           };
609           callee_cx.eval(&body.value)?
610       },
611       hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
612           Ok(val) => val,
613           Err(err) => signal!(e, err),
614       },
615       hir::ExprBlock(ref block) => {
616         match block.expr {
617             Some(ref expr) => cx.eval(expr)?,
618             None => Tuple(vec![]),
619         }
620       }
621       hir::ExprType(ref e, _) => cx.eval(e)?,
622       hir::ExprTup(ref fields) => {
623         Tuple(fields.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
624       }
625       hir::ExprStruct(_, ref fields, _) => {
626         Struct(fields.iter().map(|f| {
627             cx.eval(&f.expr).map(|v| (f.name.node, v))
628         }).collect::<Result<_, _>>()?)
629       }
630       hir::ExprIndex(ref arr, ref idx) => {
631         if !tcx.sess.features.borrow().const_indexing {
632             signal!(e, IndexOpFeatureGated);
633         }
634         let arr = cx.eval(arr)?;
635         let idx = match cx.eval(idx)? {
636             Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
637             _ => signal!(idx, IndexNotUsize),
638         };
639         assert_eq!(idx as usize as u64, idx);
640         match arr {
641             Array(ref v) => {
642                 if let Some(elem) = v.get(idx as usize) {
643                     elem.clone()
644                 } else {
645                     let n = v.len() as u64;
646                     assert_eq!(n as usize as u64, n);
647                     signal!(e, IndexOutOfBounds { len: n, index: idx })
648                 }
649             }
650
651             Repeat(.., n) if idx >= n => {
652                 signal!(e, IndexOutOfBounds { len: n, index: idx })
653             }
654             Repeat(ref elem, _) => (**elem).clone(),
655
656             ByteStr(ref data) if idx >= data.len() as u64 => {
657                 signal!(e, IndexOutOfBounds { len: data.len() as u64, index: idx })
658             }
659             ByteStr(data) => {
660                 Integral(U8(data[idx as usize]))
661             },
662
663             _ => signal!(e, IndexedNonVec),
664         }
665       }
666       hir::ExprArray(ref v) => {
667         Array(v.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
668       }
669       hir::ExprRepeat(ref elem, _) => {
670           let n = match ety.sty {
671             ty::TyArray(_, n) => n as u64,
672             _ => span_bug!(e.span, "typeck error")
673           };
674           Repeat(Box::new(cx.eval(elem)?), n)
675       },
676       hir::ExprTupField(ref base, index) => {
677         let c = cx.eval(base)?;
678         if let Tuple(ref fields) = c {
679             fields[index.node].clone()
680         } else {
681             signal!(base, ExpectedConstTuple);
682         }
683       }
684       hir::ExprField(ref base, field_name) => {
685         let c = cx.eval(base)?;
686         if let Struct(ref fields) = c {
687             if let Some(f) = fields.get(&field_name.node) {
688                 f.clone()
689             } else {
690                 signal!(e, MissingStructField);
691             }
692         } else {
693             signal!(base, ExpectedConstStruct);
694         }
695       }
696       hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),
697       _ => signal!(e, MiscCatchAll)
698     };
699
700     Ok(result)
701 }
702
703 fn resolve_trait_associated_const<'a, 'tcx: 'a>(
704     tcx: TyCtxt<'a, 'tcx, 'tcx>,
705     trait_item_id: DefId,
706     default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>,
707     trait_id: DefId,
708     rcvr_substs: &'tcx Substs<'tcx>
709 ) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>
710 {
711     let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
712     debug!("resolve_trait_associated_const: trait_ref={:?}",
713            trait_ref);
714
715     tcx.populate_implementations_for_trait_if_necessary(trait_id);
716     tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
717         let mut selcx = traits::SelectionContext::new(&infcx);
718         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
719                                                  trait_ref.to_poly_trait_predicate());
720         let selection = match selcx.select(&obligation) {
721             Ok(Some(vtable)) => vtable,
722             // Still ambiguous, so give up and let the caller decide whether this
723             // expression is really needed yet. Some associated constant values
724             // can't be evaluated until monomorphization is done in trans.
725             Ok(None) => {
726                 return None
727             }
728             Err(_) => {
729                 return None
730             }
731         };
732
733         // NOTE: this code does not currently account for specialization, but when
734         // it does so, it should hook into the Reveal to determine when the
735         // constant should resolve; this will also require plumbing through to this
736         // function whether we are in "trans mode" to pick the right Reveal
737         // when constructing the inference context above.
738         match selection {
739             traits::VtableImpl(ref impl_data) => {
740                 let name = tcx.associated_item(trait_item_id).name;
741                 let ac = tcx.associated_items(impl_data.impl_def_id)
742                     .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
743                 match ac {
744                     Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()),
745                     None => default_value,
746                 }
747             }
748             _ => {
749                 bug!("resolve_trait_associated_const: unexpected vtable type")
750             }
751         }
752     })
753 }
754
755 fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
756                             val: ConstInt,
757                             ty: Ty<'tcx>)
758                             -> CastResult<'tcx> {
759     let v = val.to_u128_unchecked();
760     match ty.sty {
761         ty::TyBool if v == 0 => Ok(Bool(false)),
762         ty::TyBool if v == 1 => Ok(Bool(true)),
763         ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i128 as i8))),
764         ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i128 as i16))),
765         ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i128 as i32))),
766         ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))),
767         ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))),
768         ty::TyInt(ast::IntTy::Is) => {
769             Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.int_type))))
770         },
771         ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
772         ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
773         ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
774         ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
775         ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))),
776         ty::TyUint(ast::UintTy::Us) => {
777             Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
778         },
779         ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(val.to_f64()))),
780         ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(val.to_f32()))),
781         ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
782         ty::TyChar => match val {
783             U8(u) => Ok(Char(u as char)),
784             _ => bug!(),
785         },
786         _ => bug!(),
787     }
788 }
789
790 fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
791                               val: ConstFloat,
792                               ty: Ty<'tcx>) -> CastResult<'tcx> {
793     match ty.sty {
794         ty::TyInt(_) | ty::TyUint(_) => {
795             let i = match val {
796                 F32(f) if f >= 0.0 => U128(f as u128),
797                 F64(f) if f >= 0.0 => U128(f as u128),
798
799                 F32(f) => I128(f as i128),
800                 F64(f) => I128(f as i128)
801             };
802
803             if let (I128(_), &ty::TyUint(_)) = (i, &ty.sty) {
804                 return Err(CannotCast);
805             }
806
807             cast_const_int(tcx, i, ty)
808         }
809         ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val {
810             F32(f) => f as f64,
811             F64(f) => f
812         }))),
813         ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val {
814             F64(f) => f as f32,
815             F32(f) => f
816         }))),
817         _ => Err(CannotCast),
818     }
819 }
820
821 fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
822                         val: ConstVal<'tcx>,
823                         ty: Ty<'tcx>)
824                         -> CastResult<'tcx> {
825     match val {
826         Integral(i) => cast_const_int(tcx, i, ty),
827         Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
828         Float(f) => cast_const_float(tcx, f, ty),
829         Char(c) => cast_const_int(tcx, U32(c as u32), ty),
830         Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
831         ByteStr(b) => match ty.sty {
832             ty::TyRawPtr(_) => {
833                 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
834             },
835             ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
836                 ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)),
837                 ty::TySlice(_) => {
838                     Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
839                 },
840                 _ => Err(CannotCast),
841             },
842             _ => Err(CannotCast),
843         },
844         Str(s) => match ty.sty {
845             ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
846             ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
847                 ty::TyStr => Ok(Str(s)),
848                 _ => Err(CannotCast),
849             },
850             _ => Err(CannotCast),
851         },
852         _ => Err(CannotCast),
853     }
854 }
855
856 fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
857                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
858                           mut ty: Ty<'tcx>)
859                           -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
860     use syntax::ast::*;
861     use syntax::ast::LitIntType::*;
862
863     if let ty::TyAdt(adt, _) = ty.sty {
864         if adt.is_enum() {
865             ty = adt.repr.discr_type().to_ty(tcx)
866         }
867     }
868
869     match *lit {
870         LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
871         LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
872         LitKind::Byte(n) => Ok(Integral(U8(n))),
873         LitKind::Int(n, hint) => {
874             match (&ty.sty, hint) {
875                 (&ty::TyInt(ity), _) |
876                 (_, Signed(ity)) => {
877                     Ok(Integral(ConstInt::new_signed_truncating(n as i128,
878                         ity, tcx.sess.target.int_type)))
879                 }
880                 (&ty::TyUint(uty), _) |
881                 (_, Unsigned(uty)) => {
882                     Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
883                         uty, tcx.sess.target.uint_type)))
884                 }
885                 _ => bug!()
886             }
887         }
888         LitKind::Float(n, fty) => {
889             parse_float(&n.as_str(), fty).map(Float)
890         }
891         LitKind::FloatUnsuffixed(n) => {
892             let fty = match ty.sty {
893                 ty::TyFloat(fty) => fty,
894                 _ => bug!()
895             };
896             parse_float(&n.as_str(), fty).map(Float)
897         }
898         LitKind::Bool(b) => Ok(Bool(b)),
899         LitKind::Char(c) => Ok(Char(c)),
900     }
901 }
902
903 fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
904                      -> Result<ConstFloat, ErrKind<'tcx>> {
905     let val = match fty {
906         ast::FloatTy::F32 => num.parse::<f32>().map(F32),
907         ast::FloatTy::F64 => num.parse::<f64>().map(F64)
908     };
909     val.map_err(|_| {
910         // FIXME(#31407) this is only necessary because float parsing is buggy
911         UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
912     })
913 }
914
915 pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
916                           -> Result<Ordering, ErrorReported>
917 {
918     let result = match (a, b) {
919         (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
920         (&Float(a), &Float(b)) => a.try_cmp(b).ok(),
921         (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
922         (&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
923         (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
924         (&Char(a), &Char(ref b)) => Some(a.cmp(b)),
925         _ => None,
926     };
927
928     match result {
929         Some(result) => Ok(result),
930         None => {
931             // FIXME: can this ever be reached?
932             span_err!(tcx.sess, span, E0298,
933                       "type mismatch comparing {} and {}",
934                       a.description(),
935                       b.description());
936             Err(ErrorReported)
937         }
938     }
939 }
940
941 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
942     pub fn compare_lit_exprs(&self,
943                              span: Span,
944                              a: &Expr,
945                              b: &Expr) -> Result<Ordering, ErrorReported> {
946         let tcx = self.tcx;
947         let a = match self.eval(a) {
948             Ok(a) => a,
949             Err(e) => {
950                 report_const_eval_err(tcx, &e, a.span, "expression");
951                 return Err(ErrorReported);
952             }
953         };
954         let b = match self.eval(b) {
955             Ok(b) => b,
956             Err(e) => {
957                 report_const_eval_err(tcx, &e, b.span, "expression");
958                 return Err(ErrorReported);
959             }
960         };
961         compare_const_vals(tcx, span, &a, &b)
962     }
963 }
964
965
966 /// Returns the value of the length-valued expression
967 pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
968                              count: hir::BodyId,
969                              reason: &str)
970                              -> Result<usize, ErrorReported>
971 {
972     let count_expr = &tcx.hir.body(count).value;
973     match ConstContext::new(tcx, count).eval(count_expr) {
974         Ok(Integral(Usize(count))) => {
975             let val = count.as_u64(tcx.sess.target.uint_type);
976             assert_eq!(val as usize as u64, val);
977             Ok(val as usize)
978         },
979         Ok(_) |
980         Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported),
981         Err(err) => {
982             let mut diag = build_const_eval_err(
983                 tcx, &err, count_expr.span, reason);
984
985             if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
986                 if let Def::Local(..) = path.def {
987                     diag.note(&format!("`{}` is a variable",
988                                        tcx.hir.node_to_pretty_string(count_expr.id)));
989                 }
990             }
991
992             diag.emit();
993             Err(ErrorReported)
994         }
995     }
996 }