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