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