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