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.
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.
11 use rustc::middle::const_val::ConstVal::*;
12 use rustc::middle::const_val::ConstVal;
15 use rustc::hir::map as hir_map;
16 use rustc::hir::map::blocks::FnLikeNode;
18 use rustc::hir::def::Def;
19 use rustc::hir::def_id::DefId;
20 use rustc::ty::{self, Ty, TyCtxt};
21 use rustc::ty::util::IntTypeExt;
22 use rustc::ty::subst::{Substs, Subst};
23 use rustc::traits::Reveal;
24 use rustc::util::common::ErrorReported;
25 use rustc::util::nodemap::DefIdMap;
27 use graphviz::IntoCow;
29 use rustc::hir::{self, Expr};
30 use syntax_pos::{Span, DUMMY_SP};
33 use std::cmp::Ordering;
35 use rustc_const_math::*;
36 use rustc_errors::DiagnosticBuilder;
39 ($e:expr, $exn:expr) => {
40 return Err(ConstEvalErr { span: $e.span, kind: $exn })
45 ($e:expr, $op:expr) => {
48 Err(e) => signal!($e, ErrKind::from(e)),
53 fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
55 -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> {
56 if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) {
57 let enum_node_id = tcx.hir.get_parent(variant_node_id);
58 if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) {
59 if let hir::ItemEnum(ref edef, _) = it.node {
60 for variant in &edef.variants {
61 if variant.node.data.id() == variant_node_id {
62 return variant.node.disr_expr.map(|e| {
63 let def_id = tcx.hir.body_owner_def_id(e);
64 (&tcx.hir.body(e).value,
65 tcx.item_tables(def_id))
75 /// * `def_id` is the id of the constant.
76 /// * `substs` is the monomorphized substitutions for the expression.
78 /// `substs` is optional and is used for associated constants.
79 /// This generally happens in late/trans const evaluation.
80 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
82 substs: &'tcx Substs<'tcx>)
83 -> Option<(&'tcx Expr,
84 &'a ty::TypeckTables<'tcx>)> {
85 if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
86 match tcx.hir.find(node_id) {
88 Some(hir_map::NodeItem(&hir::Item {
89 node: hir::ItemConst(_, body), ..
91 Some(hir_map::NodeImplItem(&hir::ImplItem {
92 node: hir::ImplItemKind::Const(_, body), ..
94 Some((&tcx.hir.body(body).value,
95 tcx.item_tables(def_id)))
97 Some(hir_map::NodeTraitItem(ti)) => match ti.node {
98 hir::TraitItemKind::Const(_, default) => {
99 // If we have a trait item and the substitutions for it,
100 // `resolve_trait_associated_const` will select an impl
102 let trait_id = tcx.hir.get_parent(node_id);
103 let trait_id = tcx.hir.local_def_id(trait_id);
104 let default_value = default.map(|body| {
105 (&tcx.hir.body(body).value,
106 tcx.item_tables(def_id))
108 resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
115 let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
116 (&body.value, tcx.item_tables(def_id))
118 match tcx.sess.cstore.describe_def(def_id) {
119 Some(Def::AssociatedConst(_)) => {
120 let trait_id = tcx.sess.cstore.trait_of_item(def_id);
121 // As mentioned in the comments above for in-crate
122 // constants, we only try to find the expression for a
123 // trait-associated const if the caller gives us the
124 // substitutions for the reference to it.
125 if let Some(trait_id) = trait_id {
126 resolve_trait_associated_const(tcx, def_id, expr_and_tables,
132 Some(Def::Const(..)) => expr_and_tables,
138 fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
139 -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)>
141 if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
142 FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| {
143 if fn_like.constness() == hir::Constness::Const {
144 Some((tcx.hir.body(fn_like.body()),
145 tcx.item_tables(def_id)))
151 if tcx.sess.cstore.is_const_fn(def_id) {
152 tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
153 (body, tcx.item_tables(def_id))
161 fn build_const_eval_err<'a, 'tcx>(
162 tcx: TyCtxt<'a, 'tcx, 'tcx>,
166 -> DiagnosticBuilder<'tcx>
169 while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err {
173 let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
174 note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag);
178 pub fn report_const_eval_err<'a, 'tcx>(
179 tcx: TyCtxt<'a, 'tcx, 'tcx>,
184 if let TypeckError = err.kind {
187 build_const_eval_err(tcx, err, primary_span, primary_kind).emit();
190 pub fn fatal_const_eval_err<'a, 'tcx>(
191 tcx: TyCtxt<'a, 'tcx, 'tcx>,
197 report_const_eval_err(tcx, err, primary_span, primary_kind);
198 tcx.sess.abort_if_errors();
202 pub fn note_const_eval_err<'a, 'tcx>(
203 _tcx: TyCtxt<'a, 'tcx, 'tcx>,
207 diag: &mut DiagnosticBuilder)
209 match err.description() {
210 ConstEvalErrDescription::Simple(message) => {
211 diag.span_label(err.span, &message);
215 if !primary_span.contains(err.span) {
216 diag.span_note(primary_span,
217 &format!("for {} here", primary_kind));
221 pub struct ConstContext<'a, 'tcx: 'a> {
222 tcx: TyCtxt<'a, 'tcx, 'tcx>,
223 tables: &'a ty::TypeckTables<'tcx>,
224 substs: &'tcx Substs<'tcx>,
225 fn_args: Option<DefIdMap<ConstVal<'tcx>>>
228 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
229 pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self {
230 let def_id = tcx.hir.body_owner_def_id(body);
231 ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
232 ConstContext::with_tables(tcx, tcx.item_tables(def_id))
235 pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self {
239 substs: tcx.intern_substs(&[]),
244 /// Evaluate a constant expression in a context where the expression isn't
245 /// guaranteed to be evaluatable.
246 pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> {
247 if self.tables.tainted_by_errors {
248 signal!(e, TypeckError);
250 eval_const_expr_partial(self, e)
254 #[derive(Clone, Debug)]
255 pub struct ConstEvalErr<'tcx> {
257 pub kind: ErrKind<'tcx>,
260 #[derive(Clone, Debug)]
261 pub enum ErrKind<'tcx> {
264 NegateOn(ConstVal<'tcx>),
265 NotOn(ConstVal<'tcx>),
266 CallOn(ConstVal<'tcx>),
269 UnimplementedConstVal(&'static str),
274 IndexOutOfBounds { len: u64, index: u64 },
282 ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
287 impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
288 fn from(err: ConstMathErr) -> ErrKind<'tcx> {
290 ConstMathErr::UnsignedNegation => TypeckError,
296 #[derive(Clone, Debug)]
297 pub enum ConstEvalErrDescription<'a> {
298 Simple(Cow<'a, str>),
301 impl<'a> ConstEvalErrDescription<'a> {
302 /// Return a one-line description of the error, for lints and such
303 pub fn into_oneline(self) -> Cow<'a, str> {
305 ConstEvalErrDescription::Simple(simple) => simple,
310 impl<'tcx> ConstEvalErr<'tcx> {
311 pub fn description(&self) -> ConstEvalErrDescription {
312 use self::ErrKind::*;
313 use self::ConstEvalErrDescription::*;
315 macro_rules! simple {
316 ($msg:expr) => ({ Simple($msg.into_cow()) });
317 ($fmt:expr, $($arg:tt)+) => ({
318 Simple(format!($fmt, $($arg)+).into_cow())
323 CannotCast => simple!("can't cast this type"),
324 NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
325 NotOn(ref const_val) => simple!("not on {}", const_val.description()),
326 CallOn(ref const_val) => simple!("call on {}", const_val.description()),
328 MissingStructField => simple!("nonexistent struct field"),
329 NonConstPath => simple!("non-constant path in constant expression"),
330 UnimplementedConstVal(what) =>
331 simple!("unimplemented constant expression: {}", what),
332 ExpectedConstTuple => simple!("expected constant tuple"),
333 ExpectedConstStruct => simple!("expected constant struct"),
334 IndexedNonVec => simple!("indexing is only supported for arrays"),
335 IndexNotUsize => simple!("indices must be of type `usize`"),
336 IndexOutOfBounds { len, index } => {
337 simple!("index out of bounds: the len is {} but the index is {}",
341 MiscBinaryOp => simple!("bad operands for binary"),
342 MiscCatchAll => simple!("unsupported constant expr"),
343 IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
344 Math(ref err) => Simple(err.description().into_cow()),
346 ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
348 TypeckError => simple!("type-checking failed"),
353 pub type EvalResult<'tcx> = Result<ConstVal<'tcx>, ConstEvalErr<'tcx>>;
354 pub type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
356 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
357 e: &Expr) -> EvalResult<'tcx> {
359 let ety = cx.tables.expr_ty(e);
361 // Avoid applying substitutions if they're empty, that'd ICE.
362 let ety = if cx.substs.is_empty() {
365 ety.subst(tcx, cx.substs)
368 let result = match e.node {
369 hir::ExprUnary(hir::UnNeg, ref inner) => {
370 // unary neg literals already got their sign during creation
371 if let hir::ExprLit(ref lit) = inner.node {
373 use syntax::ast::LitIntType::*;
374 const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128;
375 const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128;
376 const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
377 const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
378 const I128_OVERFLOW: u128 = i128::min_value() as u128;
379 match (&lit.node, &ety.sty) {
380 (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
381 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
382 return Ok(Integral(I8(i8::min_value())))
384 (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
385 (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
386 return Ok(Integral(I16(i16::min_value())))
388 (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
389 (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
390 return Ok(Integral(I32(i32::min_value())))
392 (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
393 (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
394 return Ok(Integral(I64(i64::min_value())))
396 (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
397 (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
398 return Ok(Integral(I128(i128::min_value())))
400 (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) |
401 (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
402 match tcx.sess.target.int_type {
403 IntTy::I16 => if n == I16_OVERFLOW {
404 return Ok(Integral(Isize(Is16(i16::min_value()))));
406 IntTy::I32 => if n == I32_OVERFLOW {
407 return Ok(Integral(Isize(Is32(i32::min_value()))));
409 IntTy::I64 => if n == I64_OVERFLOW {
410 return Ok(Integral(Isize(Is64(i64::min_value()))));
412 _ => span_bug!(e.span, "typeck error")
418 match cx.eval(inner)? {
419 Float(f) => Float(-f),
420 Integral(i) => Integral(math!(e, -i)),
421 const_val => signal!(e, NegateOn(const_val)),
424 hir::ExprUnary(hir::UnNot, ref inner) => {
425 match cx.eval(inner)? {
426 Integral(i) => Integral(math!(e, !i)),
428 const_val => signal!(e, NotOn(const_val)),
431 hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
432 hir::ExprBinary(op, ref a, ref b) => {
433 // technically, if we don't have type hints, but integral eval
434 // gives us a type through a type-suffix, cast or const def type
435 // we need to re-eval the other value of the BinOp if it was
437 match (cx.eval(a)?, cx.eval(b)?) {
438 (Float(a), Float(b)) => {
439 use std::cmp::Ordering::*;
441 hir::BiAdd => Float(math!(e, a + b)),
442 hir::BiSub => Float(math!(e, a - b)),
443 hir::BiMul => Float(math!(e, a * b)),
444 hir::BiDiv => Float(math!(e, a / b)),
445 hir::BiRem => Float(math!(e, a % b)),
446 hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
447 hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
448 hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
449 hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
450 hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
451 hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
452 _ => span_bug!(e.span, "typeck error"),
455 (Integral(a), Integral(b)) => {
456 use std::cmp::Ordering::*;
458 hir::BiAdd => Integral(math!(e, a + b)),
459 hir::BiSub => Integral(math!(e, a - b)),
460 hir::BiMul => Integral(math!(e, a * b)),
461 hir::BiDiv => Integral(math!(e, a / b)),
462 hir::BiRem => Integral(math!(e, a % b)),
463 hir::BiBitAnd => Integral(math!(e, a & b)),
464 hir::BiBitOr => Integral(math!(e, a | b)),
465 hir::BiBitXor => Integral(math!(e, a ^ b)),
466 hir::BiShl => Integral(math!(e, a << b)),
467 hir::BiShr => Integral(math!(e, a >> b)),
468 hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
469 hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
470 hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
471 hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
472 hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
473 hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
474 _ => span_bug!(e.span, "typeck error"),
477 (Bool(a), Bool(b)) => {
479 hir::BiAnd => a && b,
481 hir::BiBitXor => a ^ b,
482 hir::BiBitAnd => a & b,
483 hir::BiBitOr => a | b,
490 _ => span_bug!(e.span, "typeck error"),
493 (Char(a), Char(b)) => {
501 _ => span_bug!(e.span, "typeck error"),
505 _ => signal!(e, MiscBinaryOp),
508 hir::ExprCast(ref base, _) => {
509 match cast_const(tcx, cx.eval(base)?, ety) {
511 Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
514 hir::ExprPath(ref qpath) => {
515 let substs = cx.tables.node_id_item_substs(e.id)
516 .unwrap_or_else(|| tcx.intern_substs(&[]));
518 // Avoid applying substitutions if they're empty, that'd ICE.
519 let substs = if cx.substs.is_empty() {
522 substs.subst(tcx, cx.substs)
525 match cx.tables.qpath_def(qpath, e.id) {
527 Def::AssociatedConst(def_id) => {
528 if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) {
529 let cx = ConstContext::with_tables(tcx, tables);
530 match cx.eval(expr) {
532 Err(ConstEvalErr { kind: TypeckError, .. }) => {
533 signal!(e, TypeckError);
536 debug!("bad reference: {:?}, {:?}", err.description(), err.span);
537 signal!(e, ErroneousReferencedConstant(box err))
541 signal!(e, TypeckError);
544 Def::VariantCtor(variant_def, ..) => {
545 if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
546 let cx = ConstContext::with_tables(tcx, tables);
547 match cx.eval(expr) {
549 Err(ConstEvalErr { kind: TypeckError, .. }) => {
550 signal!(e, TypeckError);
553 debug!("bad reference: {:?}, {:?}", err.description(), err.span);
554 signal!(e, ErroneousReferencedConstant(box err))
558 signal!(e, UnimplementedConstVal("enum variants"));
561 Def::StructCtor(..) => {
562 ConstVal::Struct(Default::default())
564 Def::Local(def_id) => {
565 debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args);
566 if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) {
569 signal!(e, NonConstPath);
572 Def::Method(id) | Def::Fn(id) => Function(id, substs),
573 Def::Err => span_bug!(e.span, "typeck error"),
574 _ => signal!(e, NonConstPath),
577 hir::ExprCall(ref callee, ref args) => {
578 let (did, substs) = match cx.eval(callee)? {
579 Function(did, substs) => (did, substs),
580 Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
581 callee => signal!(e, CallOn(callee)),
583 let (body, tables) = match lookup_const_fn_by_id(tcx, did) {
585 None => signal!(e, NonConstPath),
588 let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
589 hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
591 }).collect::<Vec<_>>();
592 assert_eq!(arg_defs.len(), args.len());
594 let mut call_args = DefIdMap();
595 for (arg, arg_expr) in arg_defs.into_iter().zip(args.iter()) {
596 let arg_val = cx.eval(arg_expr)?;
597 debug!("const call arg: {:?}", arg);
598 if let Some(def_id) = arg {
599 assert!(call_args.insert(def_id, arg_val).is_none());
602 debug!("const call({:?})", call_args);
603 let callee_cx = ConstContext {
607 fn_args: Some(call_args)
609 callee_cx.eval(&body.value)?
611 hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
613 Err(err) => signal!(e, err),
615 hir::ExprBlock(ref block) => {
617 Some(ref expr) => cx.eval(expr)?,
618 None => Tuple(vec![]),
621 hir::ExprType(ref e, _) => cx.eval(e)?,
622 hir::ExprTup(ref fields) => {
623 Tuple(fields.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
625 hir::ExprStruct(_, ref fields, _) => {
626 Struct(fields.iter().map(|f| {
627 cx.eval(&f.expr).map(|v| (f.name.node, v))
628 }).collect::<Result<_, _>>()?)
630 hir::ExprIndex(ref arr, ref idx) => {
631 if !tcx.sess.features.borrow().const_indexing {
632 signal!(e, IndexOpFeatureGated);
634 let arr = cx.eval(arr)?;
635 let idx = match cx.eval(idx)? {
636 Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
637 _ => signal!(idx, IndexNotUsize),
639 assert_eq!(idx as usize as u64, idx);
642 if let Some(elem) = v.get(idx as usize) {
645 let n = v.len() as u64;
646 assert_eq!(n as usize as u64, n);
647 signal!(e, IndexOutOfBounds { len: n, index: idx })
651 Repeat(.., n) if idx >= n => {
652 signal!(e, IndexOutOfBounds { len: n, index: idx })
654 Repeat(ref elem, _) => (**elem).clone(),
656 ByteStr(ref data) if idx >= data.len() as u64 => {
657 signal!(e, IndexOutOfBounds { len: data.len() as u64, index: idx })
660 Integral(U8(data[idx as usize]))
663 _ => signal!(e, IndexedNonVec),
666 hir::ExprArray(ref v) => {
667 Array(v.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
669 hir::ExprRepeat(ref elem, _) => {
670 let n = match ety.sty {
671 ty::TyArray(_, n) => n as u64,
672 _ => span_bug!(e.span, "typeck error")
674 Repeat(Box::new(cx.eval(elem)?), n)
676 hir::ExprTupField(ref base, index) => {
677 let c = cx.eval(base)?;
678 if let Tuple(ref fields) = c {
679 fields[index.node].clone()
681 signal!(base, ExpectedConstTuple);
684 hir::ExprField(ref base, field_name) => {
685 let c = cx.eval(base)?;
686 if let Struct(ref fields) = c {
687 if let Some(f) = fields.get(&field_name.node) {
690 signal!(e, MissingStructField);
693 signal!(base, ExpectedConstStruct);
696 hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),
697 _ => signal!(e, MiscCatchAll)
703 fn resolve_trait_associated_const<'a, 'tcx: 'a>(
704 tcx: TyCtxt<'a, 'tcx, 'tcx>,
705 trait_item_id: DefId,
706 default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>,
708 rcvr_substs: &'tcx Substs<'tcx>
709 ) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>
711 let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
712 debug!("resolve_trait_associated_const: trait_ref={:?}",
715 tcx.populate_implementations_for_trait_if_necessary(trait_id);
716 tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
717 let mut selcx = traits::SelectionContext::new(&infcx);
718 let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
719 trait_ref.to_poly_trait_predicate());
720 let selection = match selcx.select(&obligation) {
721 Ok(Some(vtable)) => vtable,
722 // Still ambiguous, so give up and let the caller decide whether this
723 // expression is really needed yet. Some associated constant values
724 // can't be evaluated until monomorphization is done in trans.
733 // NOTE: this code does not currently account for specialization, but when
734 // it does so, it should hook into the Reveal to determine when the
735 // constant should resolve; this will also require plumbing through to this
736 // function whether we are in "trans mode" to pick the right Reveal
737 // when constructing the inference context above.
739 traits::VtableImpl(ref impl_data) => {
740 let name = tcx.associated_item(trait_item_id).name;
741 let ac = tcx.associated_items(impl_data.impl_def_id)
742 .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
744 Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()),
745 None => default_value,
749 bug!("resolve_trait_associated_const: unexpected vtable type")
755 fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
758 -> CastResult<'tcx> {
759 let v = val.to_u128_unchecked();
761 ty::TyBool if v == 0 => Ok(Bool(false)),
762 ty::TyBool if v == 1 => Ok(Bool(true)),
763 ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i128 as i8))),
764 ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i128 as i16))),
765 ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i128 as i32))),
766 ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))),
767 ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))),
768 ty::TyInt(ast::IntTy::Is) => {
769 Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.int_type))))
771 ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
772 ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
773 ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
774 ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
775 ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))),
776 ty::TyUint(ast::UintTy::Us) => {
777 Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
779 ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(val.to_f64()))),
780 ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(val.to_f32()))),
781 ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
782 ty::TyChar => match val {
783 U8(u) => Ok(Char(u as char)),
790 fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
792 ty: Ty<'tcx>) -> CastResult<'tcx> {
794 ty::TyInt(_) | ty::TyUint(_) => {
796 F32(f) if f >= 0.0 => U128(f as u128),
797 F64(f) if f >= 0.0 => U128(f as u128),
799 F32(f) => I128(f as i128),
800 F64(f) => I128(f as i128)
803 if let (I128(_), &ty::TyUint(_)) = (i, &ty.sty) {
804 return Err(CannotCast);
807 cast_const_int(tcx, i, ty)
809 ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val {
813 ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val {
817 _ => Err(CannotCast),
821 fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
824 -> CastResult<'tcx> {
826 Integral(i) => cast_const_int(tcx, i, ty),
827 Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
828 Float(f) => cast_const_float(tcx, f, ty),
829 Char(c) => cast_const_int(tcx, U32(c as u32), ty),
830 Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
831 ByteStr(b) => match ty.sty {
833 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
835 ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
836 ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)),
838 Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
840 _ => Err(CannotCast),
842 _ => Err(CannotCast),
844 Str(s) => match ty.sty {
845 ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
846 ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
847 ty::TyStr => Ok(Str(s)),
848 _ => Err(CannotCast),
850 _ => Err(CannotCast),
852 _ => Err(CannotCast),
856 fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
857 tcx: TyCtxt<'a, 'tcx, 'tcx>,
859 -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
861 use syntax::ast::LitIntType::*;
863 if let ty::TyAdt(adt, _) = ty.sty {
865 ty = adt.repr.discr_type().to_ty(tcx)
870 LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
871 LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
872 LitKind::Byte(n) => Ok(Integral(U8(n))),
873 LitKind::Int(n, hint) => {
874 match (&ty.sty, hint) {
875 (&ty::TyInt(ity), _) |
876 (_, Signed(ity)) => {
877 Ok(Integral(ConstInt::new_signed_truncating(n as i128,
878 ity, tcx.sess.target.int_type)))
880 (&ty::TyUint(uty), _) |
881 (_, Unsigned(uty)) => {
882 Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
883 uty, tcx.sess.target.uint_type)))
888 LitKind::Float(n, fty) => {
889 parse_float(&n.as_str(), fty).map(Float)
891 LitKind::FloatUnsuffixed(n) => {
892 let fty = match ty.sty {
893 ty::TyFloat(fty) => fty,
896 parse_float(&n.as_str(), fty).map(Float)
898 LitKind::Bool(b) => Ok(Bool(b)),
899 LitKind::Char(c) => Ok(Char(c)),
903 fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
904 -> Result<ConstFloat, ErrKind<'tcx>> {
905 let val = match fty {
906 ast::FloatTy::F32 => num.parse::<f32>().map(F32),
907 ast::FloatTy::F64 => num.parse::<f64>().map(F64)
910 // FIXME(#31407) this is only necessary because float parsing is buggy
911 UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
915 pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
916 -> Result<Ordering, ErrorReported>
918 let result = match (a, b) {
919 (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
920 (&Float(a), &Float(b)) => a.try_cmp(b).ok(),
921 (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
922 (&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
923 (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
924 (&Char(a), &Char(ref b)) => Some(a.cmp(b)),
929 Some(result) => Ok(result),
931 // FIXME: can this ever be reached?
932 span_err!(tcx.sess, span, E0298,
933 "type mismatch comparing {} and {}",
941 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
942 pub fn compare_lit_exprs(&self,
945 b: &Expr) -> Result<Ordering, ErrorReported> {
947 let a = match self.eval(a) {
950 report_const_eval_err(tcx, &e, a.span, "expression");
951 return Err(ErrorReported);
954 let b = match self.eval(b) {
957 report_const_eval_err(tcx, &e, b.span, "expression");
958 return Err(ErrorReported);
961 compare_const_vals(tcx, span, &a, &b)
966 /// Returns the value of the length-valued expression
967 pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
970 -> Result<usize, ErrorReported>
972 let count_expr = &tcx.hir.body(count).value;
973 match ConstContext::new(tcx, count).eval(count_expr) {
974 Ok(Integral(Usize(count))) => {
975 let val = count.as_u64(tcx.sess.target.uint_type);
976 assert_eq!(val as usize as u64, val);
980 Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported),
982 let mut diag = build_const_eval_err(
983 tcx, &err, count_expr.span, reason);
985 if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
986 if let Def::Local(..) = path.def {
987 diag.note(&format!("`{}` is a variable",
988 tcx.hir.node_to_pretty_string(count_expr.id)));