]> git.lizzy.rs Git - rust.git/blob - src/librustc_const_eval/eval.rs
4ae3c7d37db8dec202f82f0bf9f34cf2c3b49930
[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 //#![allow(non_camel_case_types)]
12
13 use rustc::middle::const_val::ConstVal::*;
14 use rustc::middle::const_val::ConstVal;
15 use self::ErrKind::*;
16 use self::EvalHint::*;
17
18 use rustc::hir::map as ast_map;
19 use rustc::hir::map::blocks::FnLikeNode;
20 use rustc::middle::cstore::InlinedItem;
21 use rustc::traits;
22 use rustc::hir::def::{Def, PathResolution};
23 use rustc::hir::def_id::DefId;
24 use rustc::hir::pat_util::def_to_path;
25 use rustc::ty::{self, Ty, TyCtxt};
26 use rustc::ty::util::IntTypeExt;
27 use rustc::ty::subst::Substs;
28 use rustc::traits::Reveal;
29 use rustc::util::common::ErrorReported;
30 use rustc::util::nodemap::NodeMap;
31 use rustc::lint;
32
33 use graphviz::IntoCow;
34 use syntax::ast;
35 use rustc::hir::{Expr, PatKind};
36 use rustc::hir;
37 use rustc::hir::intravisit::FnKind;
38 use syntax::ptr::P;
39 use syntax::codemap;
40 use syntax::attr::IntType;
41 use syntax_pos::{self, Span};
42
43 use std::borrow::Cow;
44 use std::cmp::Ordering;
45 use std::collections::hash_map::Entry::Vacant;
46
47 use rustc_const_math::*;
48 use rustc_errors::DiagnosticBuilder;
49
50 macro_rules! math {
51     ($e:expr, $op:expr) => {
52         match $op {
53             Ok(val) => val,
54             Err(e) => signal!($e, Math(e)),
55         }
56     }
57 }
58
59 fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
60                                   variant_def: DefId)
61                                   -> Option<&'tcx Expr> {
62     fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId)
63                         -> Option<&'a Expr> {
64         for variant in variants {
65             if variant.node.data.id() == id {
66                 return variant.node.disr_expr.as_ref().map(|e| &**e);
67             }
68         }
69         None
70     }
71
72     if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) {
73         let enum_node_id = tcx.map.get_parent(variant_node_id);
74         match tcx.map.find(enum_node_id) {
75             None => None,
76             Some(ast_map::NodeItem(it)) => match it.node {
77                 hir::ItemEnum(hir::EnumDef { ref variants }, _) => {
78                     variant_expr(variants, variant_node_id)
79                 }
80                 _ => None
81             },
82             Some(_) => None
83         }
84     } else {
85         None
86     }
87 }
88
89 /// * `def_id` is the id of the constant.
90 /// * `substs` is the monomorphized substitutions for the expression.
91 ///
92 /// `substs` is optional and is used for associated constants.
93 /// This generally happens in late/trans const evaluation.
94 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
95                                         def_id: DefId,
96                                         substs: Option<&'tcx Substs<'tcx>>)
97                                         -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)> {
98     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
99         match tcx.map.find(node_id) {
100             None => None,
101             Some(ast_map::NodeItem(it)) => match it.node {
102                 hir::ItemConst(ref ty, ref const_expr) => {
103                     Some((&const_expr, tcx.ast_ty_to_prim_ty(ty)))
104                 }
105                 _ => None
106             },
107             Some(ast_map::NodeTraitItem(ti)) => match ti.node {
108                 hir::ConstTraitItem(..) => {
109                     if let Some(substs) = substs {
110                         // If we have a trait item and the substitutions for it,
111                         // `resolve_trait_associated_const` will select an impl
112                         // or the default.
113                         let trait_id = tcx.map.get_parent(node_id);
114                         let trait_id = tcx.map.local_def_id(trait_id);
115                         resolve_trait_associated_const(tcx, ti, trait_id, substs)
116                     } else {
117                         // Technically, without knowing anything about the
118                         // expression that generates the obligation, we could
119                         // still return the default if there is one. However,
120                         // it's safer to return `None` than to return some value
121                         // that may differ from what you would get from
122                         // correctly selecting an impl.
123                         None
124                     }
125                 }
126                 _ => None
127             },
128             Some(ast_map::NodeImplItem(ii)) => match ii.node {
129                 hir::ImplItemKind::Const(ref ty, ref expr) => {
130                     Some((&expr, tcx.ast_ty_to_prim_ty(ty)))
131                 }
132                 _ => None
133             },
134             Some(_) => None
135         }
136     } else {
137         match tcx.extern_const_statics.borrow().get(&def_id) {
138             Some(&None) => return None,
139             Some(&Some((expr_id, ty))) => {
140                 return Some((tcx.map.expect_expr(expr_id), ty));
141             }
142             None => {}
143         }
144         let mut used_substs = false;
145         let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
146             Some((&InlinedItem::Item(_, ref item), _)) => match item.node {
147                 hir::ItemConst(ref ty, ref const_expr) => {
148                     Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty)))
149                 },
150                 _ => None
151             },
152             Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node {
153                 hir::ConstTraitItem(..) => {
154                     used_substs = true;
155                     if let Some(substs) = substs {
156                         // As mentioned in the comments above for in-crate
157                         // constants, we only try to find the expression for
158                         // a trait-associated const if the caller gives us
159                         // the substitutions for the reference to it.
160                         resolve_trait_associated_const(tcx, ti, trait_id, substs)
161                     } else {
162                         None
163                     }
164                 }
165                 _ => None
166             },
167             Some((&InlinedItem::ImplItem(_, ref ii), _)) => match ii.node {
168                 hir::ImplItemKind::Const(ref ty, ref expr) => {
169                     Some((&**expr, tcx.ast_ty_to_prim_ty(ty)))
170                 },
171                 _ => None
172             },
173             _ => None
174         };
175         // If we used the substitutions, particularly to choose an impl
176         // of a trait-associated const, don't cache that, because the next
177         // lookup with the same def_id may yield a different result.
178         if !used_substs {
179             tcx.extern_const_statics
180                .borrow_mut()
181                .insert(def_id, expr_ty.map(|(e, t)| (e.id, t)));
182         }
183         expr_ty
184     }
185 }
186
187 fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
188                                                  def_id: DefId)
189                                                  -> Option<ast::NodeId> {
190     match tcx.extern_const_fns.borrow().get(&def_id) {
191         Some(&ast::DUMMY_NODE_ID) => return None,
192         Some(&fn_id) => return Some(fn_id),
193         None => {}
194     }
195
196     if !tcx.sess.cstore.is_const_fn(def_id) {
197         tcx.extern_const_fns.borrow_mut().insert(def_id, ast::DUMMY_NODE_ID);
198         return None;
199     }
200
201     let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
202         Some((&InlinedItem::Item(_, ref item), _)) => Some(item.id),
203         Some((&InlinedItem::ImplItem(_, ref item), _)) => Some(item.id),
204         _ => None
205     };
206     tcx.extern_const_fns.borrow_mut().insert(def_id,
207                                              fn_id.unwrap_or(ast::DUMMY_NODE_ID));
208     fn_id
209 }
210
211 pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
212                                        -> Option<FnLikeNode<'tcx>>
213 {
214     let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
215         node_id
216     } else {
217         if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
218             fn_id
219         } else {
220             return None;
221         }
222     };
223
224     let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) {
225         Some(fn_like) => fn_like,
226         None => return None
227     };
228
229     match fn_like.kind() {
230         FnKind::ItemFn(_, _, _, hir::Constness::Const, ..) => {
231             Some(fn_like)
232         }
233         FnKind::Method(_, m, ..) => {
234             if m.constness == hir::Constness::Const {
235                 Some(fn_like)
236             } else {
237                 None
238             }
239         }
240         _ => None
241     }
242 }
243
244 pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
245                                    expr: &Expr,
246                                    pat_id: ast::NodeId,
247                                    span: Span)
248                                    -> Result<P<hir::Pat>, DefId> {
249     let pat_ty = tcx.expr_ty(expr);
250     debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
251     match pat_ty.sty {
252         ty::TyFloat(_) => {
253             tcx.sess.add_lint(
254                 lint::builtin::ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN,
255                 pat_id,
256                 span,
257                 format!("floating point constants cannot be used in patterns"));
258         }
259         ty::TyAdt(adt_def, _) if adt_def.is_union() => {
260             // Matching on union fields is unsafe, we can't hide it in constants
261             tcx.sess.span_err(span, "cannot use unions in constant patterns");
262         }
263         ty::TyAdt(adt_def, _) => {
264             if !tcx.has_attr(adt_def.did, "structural_match") {
265                 tcx.sess.add_lint(
266                     lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
267                     pat_id,
268                     span,
269                     format!("to use a constant of type `{}` \
270                              in a pattern, \
271                              `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
272                             tcx.item_path_str(adt_def.did),
273                             tcx.item_path_str(adt_def.did)));
274             }
275         }
276         _ => { }
277     }
278     let pat = match expr.node {
279         hir::ExprTup(ref exprs) =>
280             PatKind::Tuple(exprs.iter()
281                                 .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
282                                 .collect::<Result<_, _>>()?, None),
283
284         hir::ExprCall(ref callee, ref args) => {
285             let def = tcx.expect_def(callee.id);
286             if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) {
287                entry.insert(PathResolution::new(def));
288             }
289             let path = match def {
290                 Def::Struct(def_id) => def_to_path(tcx, def_id),
291                 Def::Variant(variant_did) => def_to_path(tcx, variant_did),
292                 Def::Fn(..) | Def::Method(..) => return Ok(P(hir::Pat {
293                     id: expr.id,
294                     node: PatKind::Lit(P(expr.clone())),
295                     span: span,
296                 })),
297                 _ => bug!()
298             };
299             let pats = args.iter()
300                            .map(|expr| const_expr_to_pat(tcx, &**expr, pat_id, span))
301                            .collect::<Result<_, _>>()?;
302             PatKind::TupleStruct(path, pats, None)
303         }
304
305         hir::ExprStruct(ref path, ref fields, None) => {
306             let field_pats =
307                 fields.iter()
308                       .map(|field| Ok(codemap::Spanned {
309                           span: syntax_pos::DUMMY_SP,
310                           node: hir::FieldPat {
311                               name: field.name.node,
312                               pat: const_expr_to_pat(tcx, &field.expr, pat_id, span)?,
313                               is_shorthand: false,
314                           },
315                       }))
316                       .collect::<Result<_, _>>()?;
317             PatKind::Struct(path.clone(), field_pats, false)
318         }
319
320         hir::ExprVec(ref exprs) => {
321             let pats = exprs.iter()
322                             .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
323                             .collect::<Result<_, _>>()?;
324             PatKind::Vec(pats, None, hir::HirVec::new())
325         }
326
327         hir::ExprPath(_, ref path) => {
328             match tcx.expect_def(expr.id) {
329                 Def::Struct(..) | Def::Variant(..) => PatKind::Path(None, path.clone()),
330                 Def::Const(def_id) | Def::AssociatedConst(def_id) => {
331                     let substs = Some(tcx.node_id_item_substs(expr.id).substs);
332                     let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap();
333                     return const_expr_to_pat(tcx, expr, pat_id, span);
334                 },
335                 _ => bug!(),
336             }
337         }
338
339         _ => PatKind::Lit(P(expr.clone()))
340     };
341     Ok(P(hir::Pat { id: expr.id, node: pat, span: span }))
342 }
343
344 pub fn report_const_eval_err<'a, 'tcx>(
345     tcx: TyCtxt<'a, 'tcx, 'tcx>,
346     err: &ConstEvalErr,
347     primary_span: Span,
348     primary_kind: &str)
349     -> DiagnosticBuilder<'tcx>
350 {
351     let mut err = err;
352     while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err {
353         err = i_err;
354     }
355
356     let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
357     note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag);
358     diag
359 }
360
361 pub fn fatal_const_eval_err<'a, 'tcx>(
362     tcx: TyCtxt<'a, 'tcx, 'tcx>,
363     err: &ConstEvalErr,
364     primary_span: Span,
365     primary_kind: &str)
366     -> !
367 {
368     report_const_eval_err(tcx, err, primary_span, primary_kind).emit();
369     tcx.sess.abort_if_errors();
370     unreachable!()
371 }
372
373 pub fn note_const_eval_err<'a, 'tcx>(
374     _tcx: TyCtxt<'a, 'tcx, 'tcx>,
375     err: &ConstEvalErr,
376     primary_span: Span,
377     primary_kind: &str,
378     diag: &mut DiagnosticBuilder)
379 {
380     match err.description() {
381         ConstEvalErrDescription::Simple(message) => {
382             diag.span_label(err.span, &message);
383         }
384     }
385
386     if !primary_span.contains(err.span) {
387         diag.span_note(primary_span,
388                        &format!("for {} here", primary_kind));
389     }
390 }
391
392 pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
393                                  e: &Expr) -> ConstVal {
394     match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
395         Ok(r) => r,
396         // non-const path still needs to be a fatal error, because enums are funky
397         Err(s) => {
398             report_const_eval_err(tcx, &s, e.span, "expression").emit();
399             match s.kind {
400                 NonConstPath |
401                 UnimplementedConstVal(_) => tcx.sess.abort_if_errors(),
402                 _ => {}
403             }
404             Dummy
405         },
406     }
407 }
408
409 pub type FnArgMap<'a> = Option<&'a NodeMap<ConstVal>>;
410
411 #[derive(Clone)]
412 pub struct ConstEvalErr {
413     pub span: Span,
414     pub kind: ErrKind,
415 }
416
417 #[derive(Clone)]
418 pub enum ErrKind {
419     CannotCast,
420     CannotCastTo(&'static str),
421     InvalidOpForInts(hir::BinOp_),
422     InvalidOpForBools(hir::BinOp_),
423     InvalidOpForFloats(hir::BinOp_),
424     InvalidOpForIntUint(hir::BinOp_),
425     InvalidOpForUintInt(hir::BinOp_),
426     NegateOn(ConstVal),
427     NotOn(ConstVal),
428     CallOn(ConstVal),
429
430     MissingStructField,
431     NonConstPath,
432     UnimplementedConstVal(&'static str),
433     UnresolvedPath,
434     ExpectedConstTuple,
435     ExpectedConstStruct,
436     TupleIndexOutOfBounds,
437     IndexedNonVec,
438     IndexNegative,
439     IndexNotInt,
440     IndexOutOfBounds { len: u64, index: u64 },
441     RepeatCountNotNatural,
442     RepeatCountNotInt,
443
444     MiscBinaryOp,
445     MiscCatchAll,
446
447     IndexOpFeatureGated,
448     Math(ConstMathErr),
449
450     IntermediateUnsignedNegative,
451     /// Expected, Got
452     TypeMismatch(String, ConstInt),
453
454     BadType(ConstVal),
455     ErroneousReferencedConstant(Box<ConstEvalErr>),
456     CharCast(ConstInt),
457 }
458
459 impl From<ConstMathErr> for ErrKind {
460     fn from(err: ConstMathErr) -> ErrKind {
461         Math(err)
462     }
463 }
464
465 #[derive(Clone, Debug)]
466 pub enum ConstEvalErrDescription<'a> {
467     Simple(Cow<'a, str>),
468 }
469
470 impl<'a> ConstEvalErrDescription<'a> {
471     /// Return a one-line description of the error, for lints and such
472     pub fn into_oneline(self) -> Cow<'a, str> {
473         match self {
474             ConstEvalErrDescription::Simple(simple) => simple,
475         }
476     }
477 }
478
479 impl ConstEvalErr {
480     pub fn description(&self) -> ConstEvalErrDescription {
481         use self::ErrKind::*;
482         use self::ConstEvalErrDescription::*;
483
484         macro_rules! simple {
485             ($msg:expr) => ({ Simple($msg.into_cow()) });
486             ($fmt:expr, $($arg:tt)+) => ({
487                 Simple(format!($fmt, $($arg)+).into_cow())
488             })
489         }
490
491         match self.kind {
492             CannotCast => simple!("can't cast this type"),
493             CannotCastTo(s) => simple!("can't cast this type to {}", s),
494             InvalidOpForInts(_) =>  simple!("can't do this op on integrals"),
495             InvalidOpForBools(_) =>  simple!("can't do this op on bools"),
496             InvalidOpForFloats(_) => simple!("can't do this op on floats"),
497             InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"),
498             InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"),
499             NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
500             NotOn(ref const_val) => simple!("not on {}", const_val.description()),
501             CallOn(ref const_val) => simple!("call on {}", const_val.description()),
502
503             MissingStructField  => simple!("nonexistent struct field"),
504             NonConstPath        => simple!("non-constant path in constant expression"),
505             UnimplementedConstVal(what) =>
506                 simple!("unimplemented constant expression: {}", what),
507             UnresolvedPath => simple!("unresolved path in constant expression"),
508             ExpectedConstTuple => simple!("expected constant tuple"),
509             ExpectedConstStruct => simple!("expected constant struct"),
510             TupleIndexOutOfBounds => simple!("tuple index out of bounds"),
511             IndexedNonVec => simple!("indexing is only supported for arrays"),
512             IndexNegative => simple!("indices must be non-negative integers"),
513             IndexNotInt => simple!("indices must be integers"),
514             IndexOutOfBounds { len, index } => {
515                 simple!("index out of bounds: the len is {} but the index is {}",
516                         len, index)
517             }
518             RepeatCountNotNatural => simple!("repeat count must be a natural number"),
519             RepeatCountNotInt => simple!("repeat count must be integers"),
520
521             MiscBinaryOp => simple!("bad operands for binary"),
522             MiscCatchAll => simple!("unsupported constant expr"),
523             IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
524             Math(ref err) => Simple(err.description().into_cow()),
525
526             IntermediateUnsignedNegative => simple!(
527                 "during the computation of an unsigned a negative \
528                  number was encountered. This is most likely a bug in\
529                  the constant evaluator"),
530
531             TypeMismatch(ref expected, ref got) => {
532                 simple!("expected {}, found {}", expected, got.description())
533             },
534             BadType(ref i) => simple!("value of wrong type: {:?}", i),
535             ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
536             CharCast(ref got) => {
537                 simple!("only `u8` can be cast as `char`, not `{}`", got.description())
538             },
539         }
540     }
541 }
542
543 pub type EvalResult = Result<ConstVal, ConstEvalErr>;
544 pub type CastResult = Result<ConstVal, ErrKind>;
545
546 // FIXME: Long-term, this enum should go away: trying to evaluate
547 // an expression which hasn't been type-checked is a recipe for
548 // disaster.  That said, it's not clear how to fix ast_ty_to_ty
549 // to avoid the ordering issue.
550
551 /// Hint to determine how to evaluate constant expressions which
552 /// might not be type-checked.
553 #[derive(Copy, Clone, Debug)]
554 pub enum EvalHint<'tcx> {
555     /// We have a type-checked expression.
556     ExprTypeChecked,
557     /// We have an expression which hasn't been type-checked, but we have
558     /// an idea of what the type will be because of the context. For example,
559     /// the length of an array is always `usize`. (This is referred to as
560     /// a hint because it isn't guaranteed to be consistent with what
561     /// type-checking would compute.)
562     UncheckedExprHint(Ty<'tcx>),
563     /// We have an expression which has not yet been type-checked, and
564     /// and we have no clue what the type will be.
565     UncheckedExprNoHint,
566 }
567
568 impl<'tcx> EvalHint<'tcx> {
569     fn erase_hint(&self) -> EvalHint<'tcx> {
570         match *self {
571             ExprTypeChecked => ExprTypeChecked,
572             UncheckedExprHint(_) | UncheckedExprNoHint => UncheckedExprNoHint,
573         }
574     }
575     fn checked_or(&self, ty: Ty<'tcx>) -> EvalHint<'tcx> {
576         match *self {
577             ExprTypeChecked => ExprTypeChecked,
578             _ => UncheckedExprHint(ty),
579         }
580     }
581 }
582
583 macro_rules! signal {
584     ($e:expr, $exn:expr) => {
585         return Err(ConstEvalErr { span: $e.span, kind: $exn })
586     }
587 }
588
589 /// Evaluate a constant expression in a context where the expression isn't
590 /// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
591 /// but a few places need to evaluate constants during type-checking, like
592 /// computing the length of an array. (See also the FIXME above EvalHint.)
593 pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
594                                          e: &Expr,
595                                          ty_hint: EvalHint<'tcx>,
596                                          fn_args: FnArgMap) -> EvalResult {
597     // Try to compute the type of the expression based on the EvalHint.
598     // (See also the definition of EvalHint, and the FIXME above EvalHint.)
599     let ety = match ty_hint {
600         ExprTypeChecked => {
601             // After type-checking, expr_ty is guaranteed to succeed.
602             Some(tcx.expr_ty(e))
603         }
604         UncheckedExprHint(ty) => {
605             // Use the type hint; it's not guaranteed to be right, but it's
606             // usually good enough.
607             Some(ty)
608         }
609         UncheckedExprNoHint => {
610             // This expression might not be type-checked, and we have no hint.
611             // Try to query the context for a type anyway; we might get lucky
612             // (for example, if the expression was imported from another crate).
613             tcx.expr_ty_opt(e)
614         }
615     };
616     let result = match e.node {
617       hir::ExprUnary(hir::UnNeg, ref inner) => {
618         // unary neg literals already got their sign during creation
619         if let hir::ExprLit(ref lit) = inner.node {
620             use syntax::ast::*;
621             use syntax::ast::LitIntType::*;
622             const I8_OVERFLOW: u64 = ::std::i8::MAX as u64 + 1;
623             const I16_OVERFLOW: u64 = ::std::i16::MAX as u64 + 1;
624             const I32_OVERFLOW: u64 = ::std::i32::MAX as u64 + 1;
625             const I64_OVERFLOW: u64 = ::std::i64::MAX as u64 + 1;
626             match (&lit.node, ety.map(|t| &t.sty)) {
627                 (&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) |
628                 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
629                     return Ok(Integral(I8(::std::i8::MIN)))
630                 },
631                 (&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) |
632                 (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
633                     return Ok(Integral(I16(::std::i16::MIN)))
634                 },
635                 (&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) |
636                 (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
637                     return Ok(Integral(I32(::std::i32::MIN)))
638                 },
639                 (&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) |
640                 (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
641                     return Ok(Integral(I64(::std::i64::MIN)))
642                 },
643                 (&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) |
644                 (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
645                     match tcx.sess.target.int_type {
646                         IntTy::I16 => if n == I16_OVERFLOW {
647                             return Ok(Integral(Isize(Is16(::std::i16::MIN))));
648                         },
649                         IntTy::I32 => if n == I32_OVERFLOW {
650                             return Ok(Integral(Isize(Is32(::std::i32::MIN))));
651                         },
652                         IntTy::I64 => if n == I64_OVERFLOW {
653                             return Ok(Integral(Isize(Is64(::std::i64::MIN))));
654                         },
655                         _ => bug!(),
656                     }
657                 },
658                 _ => {},
659             }
660         }
661         match eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)? {
662           Float(f) => Float(-f),
663           Integral(i) => Integral(math!(e, -i)),
664           const_val => signal!(e, NegateOn(const_val)),
665         }
666       }
667       hir::ExprUnary(hir::UnNot, ref inner) => {
668         match eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)? {
669           Integral(i) => Integral(math!(e, !i)),
670           Bool(b) => Bool(!b),
671           const_val => signal!(e, NotOn(const_val)),
672         }
673       }
674       hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
675       hir::ExprBinary(op, ref a, ref b) => {
676         let b_ty = match op.node {
677             hir::BiShl | hir::BiShr => ty_hint.erase_hint(),
678             _ => ty_hint
679         };
680         // technically, if we don't have type hints, but integral eval
681         // gives us a type through a type-suffix, cast or const def type
682         // we need to re-eval the other value of the BinOp if it was
683         // not inferred
684         match (eval_const_expr_partial(tcx, &a, ty_hint, fn_args)?,
685                eval_const_expr_partial(tcx, &b, b_ty, fn_args)?) {
686           (Float(a), Float(b)) => {
687             use std::cmp::Ordering::*;
688             match op.node {
689               hir::BiAdd => Float(math!(e, a + b)),
690               hir::BiSub => Float(math!(e, a - b)),
691               hir::BiMul => Float(math!(e, a * b)),
692               hir::BiDiv => Float(math!(e, a / b)),
693               hir::BiRem => Float(math!(e, a % b)),
694               hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
695               hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
696               hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
697               hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
698               hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
699               hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
700               _ => signal!(e, InvalidOpForFloats(op.node)),
701             }
702           }
703           (Integral(a), Integral(b)) => {
704             use std::cmp::Ordering::*;
705             match op.node {
706               hir::BiAdd => Integral(math!(e, a + b)),
707               hir::BiSub => Integral(math!(e, a - b)),
708               hir::BiMul => Integral(math!(e, a * b)),
709               hir::BiDiv => Integral(math!(e, a / b)),
710               hir::BiRem => Integral(math!(e, a % b)),
711               hir::BiBitAnd => Integral(math!(e, a & b)),
712               hir::BiBitOr => Integral(math!(e, a | b)),
713               hir::BiBitXor => Integral(math!(e, a ^ b)),
714               hir::BiShl => Integral(math!(e, a << b)),
715               hir::BiShr => Integral(math!(e, a >> b)),
716               hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
717               hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
718               hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
719               hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
720               hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
721               hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
722               _ => signal!(e, InvalidOpForInts(op.node)),
723             }
724           }
725           (Bool(a), Bool(b)) => {
726             Bool(match op.node {
727               hir::BiAnd => a && b,
728               hir::BiOr => a || b,
729               hir::BiBitXor => a ^ b,
730               hir::BiBitAnd => a & b,
731               hir::BiBitOr => a | b,
732               hir::BiEq => a == b,
733               hir::BiNe => a != b,
734               _ => signal!(e, InvalidOpForBools(op.node)),
735              })
736           }
737
738           _ => signal!(e, MiscBinaryOp),
739         }
740       }
741       hir::ExprCast(ref base, ref target_ty) => {
742         let ety = tcx.ast_ty_to_prim_ty(&target_ty).or(ety)
743                 .unwrap_or_else(|| {
744                     tcx.sess.span_fatal(target_ty.span,
745                                         "target type not found for const cast")
746                 });
747
748         let base_hint = if let ExprTypeChecked = ty_hint {
749             ExprTypeChecked
750         } else {
751             match tcx.expr_ty_opt(&base) {
752                 Some(t) => UncheckedExprHint(t),
753                 None => ty_hint
754             }
755         };
756
757         let val = match eval_const_expr_partial(tcx, &base, base_hint, fn_args) {
758             Ok(val) => val,
759             Err(ConstEvalErr { kind: ErroneousReferencedConstant(
760                 box ConstEvalErr { kind: TypeMismatch(_, val), .. }), .. }) |
761             Err(ConstEvalErr { kind: TypeMismatch(_, val), .. }) => {
762                 // Something like `5i8 as usize` doesn't need a type hint for the base
763                 // instead take the type hint from the inner value
764                 let hint = match val.int_type() {
765                     Some(IntType::UnsignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_uint(ty)),
766                     Some(IntType::SignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_int(ty)),
767                     // we had a type hint, so we can't have an unknown type
768                     None => bug!(),
769                 };
770                 eval_const_expr_partial(tcx, &base, hint, fn_args)?
771             },
772             Err(e) => return Err(e),
773         };
774         match cast_const(tcx, val, ety) {
775             Ok(val) => val,
776             Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
777         }
778       }
779       hir::ExprPath(..) => {
780           // This function can be used before type checking when not all paths are fully resolved.
781           // FIXME: There's probably a better way to make sure we don't panic here.
782           let resolution = tcx.expect_resolution(e.id);
783           if resolution.depth != 0 {
784               signal!(e, UnresolvedPath);
785           }
786           match resolution.base_def {
787               Def::Const(def_id) |
788               Def::AssociatedConst(def_id) => {
789                   let substs = if let ExprTypeChecked = ty_hint {
790                       Some(tcx.node_id_item_substs(e.id).substs)
791                   } else {
792                       None
793                   };
794                   if let Some((expr, ty)) = lookup_const_by_id(tcx, def_id, substs) {
795                       let item_hint = match ty {
796                           Some(ty) => ty_hint.checked_or(ty),
797                           None => ty_hint,
798                       };
799                       match eval_const_expr_partial(tcx, expr, item_hint, None) {
800                           Ok(val) => val,
801                           Err(err) => {
802                               debug!("bad reference: {:?}, {:?}", err.description(), err.span);
803                               signal!(e, ErroneousReferencedConstant(box err))
804                           },
805                       }
806                   } else {
807                       signal!(e, NonConstPath);
808                   }
809               },
810               Def::Variant(variant_def) => {
811                   if let Some(const_expr) = lookup_variant_by_id(tcx, variant_def) {
812                       match eval_const_expr_partial(tcx, const_expr, ty_hint, None) {
813                           Ok(val) => val,
814                           Err(err) => {
815                               debug!("bad reference: {:?}, {:?}", err.description(), err.span);
816                               signal!(e, ErroneousReferencedConstant(box err))
817                           },
818                       }
819                   } else {
820                       signal!(e, UnimplementedConstVal("enum variants"));
821                   }
822               }
823               Def::Struct(..) => {
824                   ConstVal::Struct(e.id)
825               }
826               Def::Local(def_id) => {
827                   let id = tcx.map.as_local_node_id(def_id).unwrap();
828                   debug!("Def::Local({:?}): {:?}", id, fn_args);
829                   if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
830                       val.clone()
831                   } else {
832                       signal!(e, NonConstPath);
833                   }
834               },
835               Def::Method(id) | Def::Fn(id) => Function(id),
836               _ => signal!(e, NonConstPath),
837           }
838       }
839       hir::ExprCall(ref callee, ref args) => {
840           let sub_ty_hint = ty_hint.erase_hint();
841           let callee_val = eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)?;
842           let did = match callee_val {
843               Function(did) => did,
844               Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
845               callee => signal!(e, CallOn(callee)),
846           };
847           let (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) {
848               (fn_like.decl(), &fn_like.body().expr)
849           } else {
850               signal!(e, NonConstPath)
851           };
852           let result = result.as_ref().expect("const fn has no result expression");
853           assert_eq!(decl.inputs.len(), args.len());
854
855           let mut call_args = NodeMap();
856           for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) {
857               let arg_hint = ty_hint.erase_hint();
858               let arg_val = eval_const_expr_partial(
859                   tcx,
860                   arg_expr,
861                   arg_hint,
862                   fn_args
863               )?;
864               debug!("const call arg: {:?}", arg);
865               let old = call_args.insert(arg.pat.id, arg_val);
866               assert!(old.is_none());
867           }
868           debug!("const call({:?})", call_args);
869           eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))?
870       },
871       hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
872           Ok(val) => val,
873           Err(err) => signal!(e, err),
874       },
875       hir::ExprBlock(ref block) => {
876         match block.expr {
877             Some(ref expr) => eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)?,
878             None => signal!(e, UnimplementedConstVal("empty block")),
879         }
880       }
881       hir::ExprType(ref e, _) => eval_const_expr_partial(tcx, &e, ty_hint, fn_args)?,
882       hir::ExprTup(_) => Tuple(e.id),
883       hir::ExprStruct(..) => Struct(e.id),
884       hir::ExprIndex(ref arr, ref idx) => {
885         if !tcx.sess.features.borrow().const_indexing {
886             signal!(e, IndexOpFeatureGated);
887         }
888         let arr_hint = ty_hint.erase_hint();
889         let arr = eval_const_expr_partial(tcx, arr, arr_hint, fn_args)?;
890         let idx_hint = ty_hint.checked_or(tcx.types.usize);
891         let idx = match eval_const_expr_partial(tcx, idx, idx_hint, fn_args)? {
892             Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
893             Integral(_) => bug!(),
894             _ => signal!(idx, IndexNotInt),
895         };
896         assert_eq!(idx as usize as u64, idx);
897         match arr {
898             Array(_, n) if idx >= n => {
899                 signal!(e, IndexOutOfBounds { len: n, index: idx })
900             }
901             Array(v, n) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
902                 assert_eq!(n as usize as u64, n);
903                 eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args)?
904             } else {
905                 bug!()
906             },
907
908             Repeat(_, n) if idx >= n => {
909                 signal!(e, IndexOutOfBounds { len: n, index: idx })
910             }
911             Repeat(elem, _) => eval_const_expr_partial(
912                 tcx,
913                 &tcx.map.expect_expr(elem),
914                 ty_hint,
915                 fn_args,
916             )?,
917
918             ByteStr(ref data) if idx >= data.len() as u64 => {
919                 signal!(e, IndexOutOfBounds { len: data.len() as u64, index: idx })
920             }
921             ByteStr(data) => {
922                 Integral(U8(data[idx as usize]))
923             },
924
925             _ => signal!(e, IndexedNonVec),
926         }
927       }
928       hir::ExprVec(ref v) => Array(e.id, v.len() as u64),
929       hir::ExprRepeat(_, ref n) => {
930           let len_hint = ty_hint.checked_or(tcx.types.usize);
931           Repeat(
932               e.id,
933               match eval_const_expr_partial(tcx, &n, len_hint, fn_args)? {
934                   Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
935                   Integral(_) => signal!(e, RepeatCountNotNatural),
936                   _ => signal!(e, RepeatCountNotInt),
937               },
938           )
939       },
940       hir::ExprTupField(ref base, index) => {
941         let base_hint = ty_hint.erase_hint();
942         let c = eval_const_expr_partial(tcx, base, base_hint, fn_args)?;
943         if let Tuple(tup_id) = c {
944             if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
945                 if index.node < fields.len() {
946                     eval_const_expr_partial(tcx, &fields[index.node], ty_hint, fn_args)?
947                 } else {
948                     signal!(e, TupleIndexOutOfBounds);
949                 }
950             } else {
951                 bug!()
952             }
953         } else {
954             signal!(base, ExpectedConstTuple);
955         }
956       }
957       hir::ExprField(ref base, field_name) => {
958         let base_hint = ty_hint.erase_hint();
959         // Get the base expression if it is a struct and it is constant
960         let c = eval_const_expr_partial(tcx, base, base_hint, fn_args)?;
961         if let Struct(struct_id) = c {
962             if let hir::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
963                 // Check that the given field exists and evaluate it
964                 // if the idents are compared run-pass/issue-19244 fails
965                 if let Some(f) = fields.iter().find(|f| f.name.node
966                                                      == field_name.node) {
967                     eval_const_expr_partial(tcx, &f.expr, ty_hint, fn_args)?
968                 } else {
969                     signal!(e, MissingStructField);
970                 }
971             } else {
972                 bug!()
973             }
974         } else {
975             signal!(base, ExpectedConstStruct);
976         }
977       }
978       hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),
979       _ => signal!(e, MiscCatchAll)
980     };
981
982     match (ety.map(|t| &t.sty), result) {
983         (Some(ref ty_hint), Integral(i)) => match infer(i, tcx, ty_hint) {
984             Ok(inferred) => Ok(Integral(inferred)),
985             Err(err) => signal!(e, err),
986         },
987         (_, result) => Ok(result),
988     }
989 }
990
991 fn infer<'a, 'tcx>(i: ConstInt,
992                    tcx: TyCtxt<'a, 'tcx, 'tcx>,
993                    ty_hint: &ty::TypeVariants<'tcx>)
994                    -> Result<ConstInt, ErrKind> {
995     use syntax::ast::*;
996
997     match (ty_hint, i) {
998         (&ty::TyInt(IntTy::I8), result @ I8(_)) => Ok(result),
999         (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result),
1000         (&ty::TyInt(IntTy::I32), result @ I32(_)) => Ok(result),
1001         (&ty::TyInt(IntTy::I64), result @ I64(_)) => Ok(result),
1002         (&ty::TyInt(IntTy::Is), result @ Isize(_)) => Ok(result),
1003
1004         (&ty::TyUint(UintTy::U8), result @ U8(_)) => Ok(result),
1005         (&ty::TyUint(UintTy::U16), result @ U16(_)) => Ok(result),
1006         (&ty::TyUint(UintTy::U32), result @ U32(_)) => Ok(result),
1007         (&ty::TyUint(UintTy::U64), result @ U64(_)) => Ok(result),
1008         (&ty::TyUint(UintTy::Us), result @ Usize(_)) => Ok(result),
1009
1010         (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i64 as i8)),
1011         (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i64 as i16)),
1012         (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i64 as i32)),
1013         (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i64)),
1014         (&ty::TyInt(IntTy::Is), Infer(i)) => {
1015             Ok(Isize(ConstIsize::new_truncating(i as i64, tcx.sess.target.int_type)))
1016         },
1017
1018         (&ty::TyInt(IntTy::I8), InferSigned(i)) => Ok(I8(i as i8)),
1019         (&ty::TyInt(IntTy::I16), InferSigned(i)) => Ok(I16(i as i16)),
1020         (&ty::TyInt(IntTy::I32), InferSigned(i)) => Ok(I32(i as i32)),
1021         (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i)),
1022         (&ty::TyInt(IntTy::Is), InferSigned(i)) => {
1023             Ok(Isize(ConstIsize::new_truncating(i, tcx.sess.target.int_type)))
1024         },
1025
1026         (&ty::TyUint(UintTy::U8), Infer(i)) => Ok(U8(i as u8)),
1027         (&ty::TyUint(UintTy::U16), Infer(i)) => Ok(U16(i as u16)),
1028         (&ty::TyUint(UintTy::U32), Infer(i)) => Ok(U32(i as u32)),
1029         (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i)),
1030         (&ty::TyUint(UintTy::Us), Infer(i)) => {
1031             Ok(Usize(ConstUsize::new_truncating(i, tcx.sess.target.uint_type)))
1032         },
1033         (&ty::TyUint(_), InferSigned(_)) => Err(IntermediateUnsignedNegative),
1034
1035         (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
1036         (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
1037
1038         (&ty::TyAdt(adt, _), i) if adt.is_enum() => {
1039             let hints = tcx.lookup_repr_hints(adt.did);
1040             let int_ty = tcx.enum_repr_type(hints.iter().next());
1041             infer(i, tcx, &int_ty.to_ty(tcx).sty)
1042         },
1043         (_, i) => Err(BadType(ConstVal::Integral(i))),
1044     }
1045 }
1046
1047 fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1048                                                 ti: &'tcx hir::TraitItem,
1049                                                 trait_id: DefId,
1050                                                 rcvr_substs: &'tcx Substs<'tcx>)
1051                                                 -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>
1052 {
1053     let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
1054     debug!("resolve_trait_associated_const: trait_ref={:?}",
1055            trait_ref);
1056
1057     tcx.populate_implementations_for_trait_if_necessary(trait_id);
1058     tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
1059         let mut selcx = traits::SelectionContext::new(&infcx);
1060         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
1061                                                  trait_ref.to_poly_trait_predicate());
1062         let selection = match selcx.select(&obligation) {
1063             Ok(Some(vtable)) => vtable,
1064             // Still ambiguous, so give up and let the caller decide whether this
1065             // expression is really needed yet. Some associated constant values
1066             // can't be evaluated until monomorphization is done in trans.
1067             Ok(None) => {
1068                 return None
1069             }
1070             Err(_) => {
1071                 return None
1072             }
1073         };
1074
1075         // NOTE: this code does not currently account for specialization, but when
1076         // it does so, it should hook into the Reveal to determine when the
1077         // constant should resolve; this will also require plumbing through to this
1078         // function whether we are in "trans mode" to pick the right Reveal
1079         // when constructing the inference context above.
1080         match selection {
1081             traits::VtableImpl(ref impl_data) => {
1082                 let ac = tcx.impl_or_trait_items(impl_data.impl_def_id)
1083                     .iter().filter_map(|&def_id| {
1084                         match tcx.impl_or_trait_item(def_id) {
1085                             ty::ConstTraitItem(ic) => Some(ic),
1086                             _ => None
1087                         }
1088                     }).find(|ic| ic.name == ti.name);
1089                 match ac {
1090                     Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
1091                     None => match ti.node {
1092                         hir::ConstTraitItem(ref ty, Some(ref expr)) => {
1093                             Some((&*expr, tcx.ast_ty_to_prim_ty(ty)))
1094                         },
1095                         _ => None,
1096                     },
1097                 }
1098             }
1099             _ => {
1100             span_bug!(ti.span,
1101                       "resolve_trait_associated_const: unexpected vtable type")
1102             }
1103         }
1104     })
1105 }
1106
1107 fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult {
1108     let v = val.to_u64_unchecked();
1109     match ty.sty {
1110         ty::TyBool if v == 0 => Ok(Bool(false)),
1111         ty::TyBool if v == 1 => Ok(Bool(true)),
1112         ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i64 as i8))),
1113         ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i64 as i16))),
1114         ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i64 as i32))),
1115         ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i64))),
1116         ty::TyInt(ast::IntTy::Is) => {
1117             Ok(Integral(Isize(ConstIsize::new_truncating(v as i64, tcx.sess.target.int_type))))
1118         },
1119         ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
1120         ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
1121         ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
1122         ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v))),
1123         ty::TyUint(ast::UintTy::Us) => {
1124             Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
1125         },
1126         ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() {
1127             Infer(u) => Ok(Float(F64(u as f64))),
1128             InferSigned(i) => Ok(Float(F64(i as f64))),
1129             _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
1130         },
1131         ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() {
1132             Infer(u) => Ok(Float(F32(u as f32))),
1133             InferSigned(i) => Ok(Float(F32(i as f32))),
1134             _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
1135         },
1136         ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
1137         ty::TyChar => match infer(val, tcx, &ty::TyUint(ast::UintTy::U8)) {
1138             Ok(U8(u)) => Ok(Char(u as char)),
1139             // can only occur before typeck, typeck blocks `T as char` for `T` != `u8`
1140             _ => Err(CharCast(val)),
1141         },
1142         _ => Err(CannotCast),
1143     }
1144 }
1145
1146 fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1147                               val: ConstFloat,
1148                               ty: ty::Ty) -> CastResult {
1149     match ty.sty {
1150         ty::TyInt(_) | ty::TyUint(_) => {
1151             let i = match val {
1152                 F32(f) if f >= 0.0 => Infer(f as u64),
1153                 FInfer { f64: f, .. } |
1154                 F64(f) if f >= 0.0 => Infer(f as u64),
1155
1156                 F32(f) => InferSigned(f as i64),
1157                 FInfer { f64: f, .. } |
1158                 F64(f) => InferSigned(f as i64)
1159             };
1160
1161             if let (InferSigned(_), &ty::TyUint(_)) = (i, &ty.sty) {
1162                 return Err(CannotCast);
1163             }
1164
1165             cast_const_int(tcx, i, ty)
1166         }
1167         ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val {
1168             F32(f) => f as f64,
1169             FInfer { f64: f, .. } | F64(f) => f
1170         }))),
1171         ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val {
1172             F64(f) => f as f32,
1173             FInfer { f32: f, .. } | F32(f) => f
1174         }))),
1175         _ => Err(CannotCast),
1176     }
1177 }
1178
1179 fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult {
1180     match val {
1181         Integral(i) => cast_const_int(tcx, i, ty),
1182         Bool(b) => cast_const_int(tcx, Infer(b as u64), ty),
1183         Float(f) => cast_const_float(tcx, f, ty),
1184         Char(c) => cast_const_int(tcx, Infer(c as u64), ty),
1185         Function(_) => Err(UnimplementedConstVal("casting fn pointers")),
1186         ByteStr(b) => match ty.sty {
1187             ty::TyRawPtr(_) => {
1188                 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
1189             },
1190             ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
1191                 ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)),
1192                 ty::TySlice(_) => {
1193                     Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
1194                 },
1195                 _ => Err(CannotCast),
1196             },
1197             _ => Err(CannotCast),
1198         },
1199         Str(s) => match ty.sty {
1200             ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
1201             ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
1202                 ty::TyStr => Ok(Str(s)),
1203                 _ => Err(CannotCast),
1204             },
1205             _ => Err(CannotCast),
1206         },
1207         _ => Err(CannotCast),
1208     }
1209 }
1210
1211 fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
1212                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
1213                           ty_hint: Option<Ty<'tcx>>)
1214                           -> Result<ConstVal, ErrKind> {
1215     use syntax::ast::*;
1216     use syntax::ast::LitIntType::*;
1217     match *lit {
1218         LitKind::Str(ref s, _) => Ok(Str((*s).clone())),
1219         LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
1220         LitKind::Byte(n) => Ok(Integral(U8(n))),
1221         LitKind::Int(n, Signed(ity)) => {
1222             infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral)
1223         },
1224
1225         LitKind::Int(n, Unsuffixed) => {
1226             match ty_hint.map(|t| &t.sty) {
1227                 Some(&ty::TyInt(ity)) => {
1228                     infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral)
1229                 },
1230                 Some(&ty::TyUint(uty)) => {
1231                     infer(Infer(n), tcx, &ty::TyUint(uty)).map(Integral)
1232                 },
1233                 None => Ok(Integral(Infer(n))),
1234                 Some(&ty::TyAdt(adt, _)) => {
1235                     let hints = tcx.lookup_repr_hints(adt.did);
1236                     let int_ty = tcx.enum_repr_type(hints.iter().next());
1237                     infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty).map(Integral)
1238                 },
1239                 Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit),
1240             }
1241         },
1242         LitKind::Int(n, Unsigned(ity)) => {
1243             infer(Infer(n), tcx, &ty::TyUint(ity)).map(Integral)
1244         },
1245
1246         LitKind::Float(ref n, fty) => {
1247             parse_float(n, Some(fty)).map(Float)
1248         }
1249         LitKind::FloatUnsuffixed(ref n) => {
1250             let fty_hint = match ty_hint.map(|t| &t.sty) {
1251                 Some(&ty::TyFloat(fty)) => Some(fty),
1252                 _ => None
1253             };
1254             parse_float(n, fty_hint).map(Float)
1255         }
1256         LitKind::Bool(b) => Ok(Bool(b)),
1257         LitKind::Char(c) => Ok(Char(c)),
1258     }
1259 }
1260
1261 fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>)
1262                -> Result<ConstFloat, ErrKind> {
1263     let val = match fty_hint {
1264         Some(ast::FloatTy::F32) => num.parse::<f32>().map(F32),
1265         Some(ast::FloatTy::F64) => num.parse::<f64>().map(F64),
1266         None => {
1267             num.parse::<f32>().and_then(|f32| {
1268                 num.parse::<f64>().map(|f64| {
1269                     FInfer { f32: f32, f64: f64 }
1270                 })
1271             })
1272         }
1273     };
1274     val.map_err(|_| {
1275         // FIXME(#31407) this is only necessary because float parsing is buggy
1276         UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
1277     })
1278 }
1279
1280 pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
1281                           -> Result<Ordering, ErrorReported>
1282 {
1283     let result = match (a, b) {
1284         (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
1285         (&Float(a), &Float(b)) => a.try_cmp(b).ok(),
1286         (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
1287         (&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
1288         (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
1289         (&Char(a), &Char(ref b)) => Some(a.cmp(b)),
1290         _ => None,
1291     };
1292
1293     match result {
1294         Some(result) => Ok(result),
1295         None => {
1296             // FIXME: can this ever be reached?
1297             span_err!(tcx.sess, span, E0298,
1298                       "type mismatch comparing {} and {}",
1299                       a.description(),
1300                       b.description());
1301             Err(ErrorReported)
1302         }
1303     }
1304 }
1305
1306 pub fn compare_lit_exprs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1307                                    span: Span,
1308                                    a: &Expr,
1309                                    b: &Expr) -> Result<Ordering, ErrorReported> {
1310     let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) {
1311         Ok(a) => a,
1312         Err(e) => {
1313             report_const_eval_err(tcx, &e, a.span, "expression").emit();
1314             return Err(ErrorReported);
1315         }
1316     };
1317     let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) {
1318         Ok(b) => b,
1319         Err(e) => {
1320             report_const_eval_err(tcx, &e, b.span, "expression").emit();
1321             return Err(ErrorReported);
1322         }
1323     };
1324     compare_const_vals(tcx, span, &a, &b)
1325 }
1326
1327
1328 /// Returns the value of the length-valued expression
1329 pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1330                              count_expr: &hir::Expr,
1331                              reason: &str)
1332                              -> Result<usize, ErrorReported>
1333 {
1334     let hint = UncheckedExprHint(tcx.types.usize);
1335     match eval_const_expr_partial(tcx, count_expr, hint, None) {
1336         Ok(Integral(Usize(count))) => {
1337             let val = count.as_u64(tcx.sess.target.uint_type);
1338             assert_eq!(val as usize as u64, val);
1339             Ok(val as usize)
1340         },
1341         Ok(const_val) => {
1342             struct_span_err!(tcx.sess, count_expr.span, E0306,
1343                              "expected `usize` for {}, found {}",
1344                              reason,
1345                              const_val.description())
1346                 .span_label(count_expr.span, &format!("expected `usize`"))
1347                 .emit();
1348
1349             Err(ErrorReported)
1350         }
1351         Err(err) => {
1352             let mut diag = report_const_eval_err(
1353                 tcx, &err, count_expr.span, reason);
1354
1355             match count_expr.node {
1356                 hir::ExprPath(None, hir::Path {
1357                     global: false,
1358                     ref segments,
1359                     ..
1360                 }) if segments.len() == 1 => {
1361                     if let Some(Def::Local(..)) = tcx.expect_def_or_none(count_expr.id) {
1362                         diag.note(&format!("`{}` is a variable", segments[0].name));
1363                     }
1364                 }
1365                 _ => {}
1366             }
1367
1368             diag.emit();
1369             Err(ErrorReported)
1370         }
1371     }
1372 }