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::ErrKind::*;
13 use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind};
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::maps::Providers;
22 use rustc::ty::util::IntTypeExt;
23 use rustc::ty::subst::{Substs, Subst};
24 use rustc::traits::Reveal;
25 use rustc::util::common::ErrorReported;
26 use rustc::util::nodemap::DefIdMap;
29 use rustc::hir::{self, Expr};
30 use syntax_pos::{Span, DUMMY_SP};
32 use std::cmp::Ordering;
34 use rustc_const_math::*;
37 ($e:expr, $exn:expr) => {
38 return Err(ConstEvalErr { span: $e.span, kind: $exn })
43 ($e:expr, $op:expr) => {
46 Err(e) => signal!($e, ErrKind::from(e)),
51 fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
53 -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> {
54 if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) {
55 let enum_node_id = tcx.hir.get_parent(variant_node_id);
56 if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) {
57 if let hir::ItemEnum(ref edef, _) = it.node {
58 for variant in &edef.variants {
59 if variant.node.data.id() == variant_node_id {
60 return variant.node.disr_expr.map(|e| {
61 let def_id = tcx.hir.body_owner_def_id(e);
62 (&tcx.hir.body(e).value,
63 tcx.item_tables(def_id))
73 /// * `def_id` is the id of the constant.
74 /// * `substs` is the monomorphized substitutions for the expression.
76 /// `substs` is optional and is used for associated constants.
77 /// This generally happens in late/trans const evaluation.
78 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
80 substs: &'tcx Substs<'tcx>)
81 -> Option<(&'tcx Expr,
82 &'a ty::TypeckTables<'tcx>)> {
83 if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
84 match tcx.hir.find(node_id) {
86 Some(hir_map::NodeItem(&hir::Item {
87 node: hir::ItemConst(_, body), ..
89 Some(hir_map::NodeImplItem(&hir::ImplItem {
90 node: hir::ImplItemKind::Const(_, body), ..
92 Some((&tcx.hir.body(body).value,
93 tcx.item_tables(def_id)))
95 Some(hir_map::NodeTraitItem(ti)) => match ti.node {
96 hir::TraitItemKind::Const(_, default) => {
97 // If we have a trait item and the substitutions for it,
98 // `resolve_trait_associated_const` will select an impl
100 let trait_id = tcx.hir.get_parent(node_id);
101 let trait_id = tcx.hir.local_def_id(trait_id);
102 let default_value = default.map(|body| {
103 (&tcx.hir.body(body).value,
104 tcx.item_tables(def_id))
106 resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
113 let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
114 (&body.value, tcx.item_tables(def_id))
116 match tcx.sess.cstore.describe_def(def_id) {
117 Some(Def::AssociatedConst(_)) => {
118 let trait_id = tcx.sess.cstore.trait_of_item(def_id);
119 // As mentioned in the comments above for in-crate
120 // constants, we only try to find the expression for a
121 // trait-associated const if the caller gives us the
122 // substitutions for the reference to it.
123 if let Some(trait_id) = trait_id {
124 resolve_trait_associated_const(tcx, def_id, expr_and_tables,
130 Some(Def::Const(..)) => expr_and_tables,
136 fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
137 -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)>
139 if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
140 FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| {
141 if fn_like.constness() == hir::Constness::Const {
142 Some((tcx.hir.body(fn_like.body()),
143 tcx.item_tables(def_id)))
149 if tcx.sess.cstore.is_const_fn(def_id) {
150 tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
151 (body, tcx.item_tables(def_id))
159 pub struct ConstContext<'a, 'tcx: 'a> {
160 tcx: TyCtxt<'a, 'tcx, 'tcx>,
161 tables: &'a ty::TypeckTables<'tcx>,
162 substs: &'tcx Substs<'tcx>,
163 fn_args: Option<DefIdMap<ConstVal<'tcx>>>
166 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
167 pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self {
171 substs: tcx.intern_substs(&[]),
176 /// Evaluate a constant expression in a context where the expression isn't
177 /// guaranteed to be evaluatable.
178 pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> {
179 if self.tables.tainted_by_errors {
180 signal!(e, TypeckError);
182 eval_const_expr_partial(self, e)
186 type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
188 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
189 e: &Expr) -> EvalResult<'tcx> {
191 let ety = cx.tables.expr_ty(e);
193 // Avoid applying substitutions if they're empty, that'd ICE.
194 let ety = if cx.substs.is_empty() {
197 ety.subst(tcx, cx.substs)
200 let result = match e.node {
201 hir::ExprUnary(hir::UnNeg, ref inner) => {
202 // unary neg literals already got their sign during creation
203 if let hir::ExprLit(ref lit) = inner.node {
205 use syntax::ast::LitIntType::*;
206 const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128;
207 const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128;
208 const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
209 const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
210 const I128_OVERFLOW: u128 = i128::min_value() as u128;
211 match (&lit.node, &ety.sty) {
212 (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
213 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
214 return Ok(Integral(I8(i8::min_value())))
216 (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
217 (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
218 return Ok(Integral(I16(i16::min_value())))
220 (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
221 (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
222 return Ok(Integral(I32(i32::min_value())))
224 (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
225 (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
226 return Ok(Integral(I64(i64::min_value())))
228 (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
229 (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
230 return Ok(Integral(I128(i128::min_value())))
232 (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) |
233 (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
234 match tcx.sess.target.int_type {
235 IntTy::I16 => if n == I16_OVERFLOW {
236 return Ok(Integral(Isize(Is16(i16::min_value()))));
238 IntTy::I32 => if n == I32_OVERFLOW {
239 return Ok(Integral(Isize(Is32(i32::min_value()))));
241 IntTy::I64 => if n == I64_OVERFLOW {
242 return Ok(Integral(Isize(Is64(i64::min_value()))));
244 _ => span_bug!(e.span, "typeck error")
250 match cx.eval(inner)? {
251 Float(f) => Float(-f),
252 Integral(i) => Integral(math!(e, -i)),
253 const_val => signal!(e, NegateOn(const_val)),
256 hir::ExprUnary(hir::UnNot, ref inner) => {
257 match cx.eval(inner)? {
258 Integral(i) => Integral(math!(e, !i)),
260 const_val => signal!(e, NotOn(const_val)),
263 hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
264 hir::ExprBinary(op, ref a, ref b) => {
265 // technically, if we don't have type hints, but integral eval
266 // gives us a type through a type-suffix, cast or const def type
267 // we need to re-eval the other value of the BinOp if it was
269 match (cx.eval(a)?, cx.eval(b)?) {
270 (Float(a), Float(b)) => {
271 use std::cmp::Ordering::*;
273 hir::BiAdd => Float(math!(e, a + b)),
274 hir::BiSub => Float(math!(e, a - b)),
275 hir::BiMul => Float(math!(e, a * b)),
276 hir::BiDiv => Float(math!(e, a / b)),
277 hir::BiRem => Float(math!(e, a % b)),
278 hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
279 hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
280 hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
281 hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
282 hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
283 hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
284 _ => span_bug!(e.span, "typeck error"),
287 (Integral(a), Integral(b)) => {
288 use std::cmp::Ordering::*;
290 hir::BiAdd => Integral(math!(e, a + b)),
291 hir::BiSub => Integral(math!(e, a - b)),
292 hir::BiMul => Integral(math!(e, a * b)),
293 hir::BiDiv => Integral(math!(e, a / b)),
294 hir::BiRem => Integral(math!(e, a % b)),
295 hir::BiBitAnd => Integral(math!(e, a & b)),
296 hir::BiBitOr => Integral(math!(e, a | b)),
297 hir::BiBitXor => Integral(math!(e, a ^ b)),
298 hir::BiShl => Integral(math!(e, a << b)),
299 hir::BiShr => Integral(math!(e, a >> b)),
300 hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
301 hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
302 hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
303 hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
304 hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
305 hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
306 _ => span_bug!(e.span, "typeck error"),
309 (Bool(a), Bool(b)) => {
311 hir::BiAnd => a && b,
313 hir::BiBitXor => a ^ b,
314 hir::BiBitAnd => a & b,
315 hir::BiBitOr => a | b,
322 _ => span_bug!(e.span, "typeck error"),
325 (Char(a), Char(b)) => {
333 _ => span_bug!(e.span, "typeck error"),
337 _ => signal!(e, MiscBinaryOp),
340 hir::ExprCast(ref base, _) => {
341 match cast_const(tcx, cx.eval(base)?, ety) {
343 Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
346 hir::ExprPath(ref qpath) => {
347 let substs = cx.tables.node_id_item_substs(e.id)
348 .unwrap_or_else(|| tcx.intern_substs(&[]));
350 // Avoid applying substitutions if they're empty, that'd ICE.
351 let substs = if cx.substs.is_empty() {
354 substs.subst(tcx, cx.substs)
357 match cx.tables.qpath_def(qpath, e.id) {
359 Def::AssociatedConst(def_id) => {
360 if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) {
361 let cx = ConstContext::with_tables(tcx, tables);
362 match cx.eval(expr) {
364 Err(ConstEvalErr { kind: TypeckError, .. }) => {
365 signal!(e, TypeckError);
368 debug!("bad reference: {:?}, {:?}", err.description(), err.span);
369 signal!(e, ErroneousReferencedConstant(box err))
373 signal!(e, TypeckError);
376 Def::VariantCtor(variant_def, ..) => {
377 if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
378 let cx = ConstContext::with_tables(tcx, tables);
379 match cx.eval(expr) {
381 Err(ConstEvalErr { kind: TypeckError, .. }) => {
382 signal!(e, TypeckError);
385 debug!("bad reference: {:?}, {:?}", err.description(), err.span);
386 signal!(e, ErroneousReferencedConstant(box err))
390 signal!(e, UnimplementedConstVal("enum variants"));
393 Def::StructCtor(..) => {
394 ConstVal::Struct(Default::default())
396 Def::Local(def_id) => {
397 debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args);
398 if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) {
401 signal!(e, NonConstPath);
404 Def::Method(id) | Def::Fn(id) => Function(id, substs),
405 Def::Err => span_bug!(e.span, "typeck error"),
406 _ => signal!(e, NonConstPath),
409 hir::ExprCall(ref callee, ref args) => {
410 let (did, substs) = match cx.eval(callee)? {
411 Function(did, substs) => (did, substs),
412 Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
413 callee => signal!(e, CallOn(callee)),
415 let (body, tables) = match lookup_const_fn_by_id(tcx, did) {
417 None => signal!(e, NonConstPath),
420 let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
421 hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
423 }).collect::<Vec<_>>();
424 assert_eq!(arg_defs.len(), args.len());
426 let mut call_args = DefIdMap();
427 for (arg, arg_expr) in arg_defs.into_iter().zip(args.iter()) {
428 let arg_val = cx.eval(arg_expr)?;
429 debug!("const call arg: {:?}", arg);
430 if let Some(def_id) = arg {
431 assert!(call_args.insert(def_id, arg_val).is_none());
434 debug!("const call({:?})", call_args);
435 let callee_cx = ConstContext {
439 fn_args: Some(call_args)
441 callee_cx.eval(&body.value)?
443 hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
445 Err(err) => signal!(e, err),
447 hir::ExprBlock(ref block) => {
449 Some(ref expr) => cx.eval(expr)?,
450 None => Tuple(vec![]),
453 hir::ExprType(ref e, _) => cx.eval(e)?,
454 hir::ExprTup(ref fields) => {
455 Tuple(fields.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
457 hir::ExprStruct(_, ref fields, _) => {
458 Struct(fields.iter().map(|f| {
459 cx.eval(&f.expr).map(|v| (f.name.node, v))
460 }).collect::<Result<_, _>>()?)
462 hir::ExprIndex(ref arr, ref idx) => {
463 if !tcx.sess.features.borrow().const_indexing {
464 signal!(e, IndexOpFeatureGated);
466 let arr = cx.eval(arr)?;
467 let idx = match cx.eval(idx)? {
468 Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
469 _ => signal!(idx, IndexNotUsize),
471 assert_eq!(idx as usize as u64, idx);
474 if let Some(elem) = v.get(idx as usize) {
477 let n = v.len() as u64;
478 assert_eq!(n as usize as u64, n);
479 signal!(e, IndexOutOfBounds { len: n, index: idx })
483 Repeat(.., n) if idx >= n => {
484 signal!(e, IndexOutOfBounds { len: n, index: idx })
486 Repeat(ref elem, _) => (**elem).clone(),
488 ByteStr(ref data) if idx >= data.len() as u64 => {
489 signal!(e, IndexOutOfBounds { len: data.len() as u64, index: idx })
492 Integral(U8(data[idx as usize]))
495 _ => signal!(e, IndexedNonVec),
498 hir::ExprArray(ref v) => {
499 Array(v.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
501 hir::ExprRepeat(ref elem, _) => {
502 let n = match ety.sty {
503 ty::TyArray(_, n) => n as u64,
504 _ => span_bug!(e.span, "typeck error")
506 Repeat(Box::new(cx.eval(elem)?), n)
508 hir::ExprTupField(ref base, index) => {
509 let c = cx.eval(base)?;
510 if let Tuple(ref fields) = c {
511 fields[index.node].clone()
513 signal!(base, ExpectedConstTuple);
516 hir::ExprField(ref base, field_name) => {
517 let c = cx.eval(base)?;
518 if let Struct(ref fields) = c {
519 if let Some(f) = fields.get(&field_name.node) {
522 signal!(e, MissingStructField);
525 signal!(base, ExpectedConstStruct);
528 hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),
529 _ => signal!(e, MiscCatchAll)
535 fn resolve_trait_associated_const<'a, 'tcx: 'a>(
536 tcx: TyCtxt<'a, 'tcx, 'tcx>,
537 trait_item_id: DefId,
538 default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>,
540 rcvr_substs: &'tcx Substs<'tcx>
541 ) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>
543 let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
544 debug!("resolve_trait_associated_const: trait_ref={:?}",
547 tcx.populate_implementations_for_trait_if_necessary(trait_id);
548 tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
549 let mut selcx = traits::SelectionContext::new(&infcx);
550 let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
551 trait_ref.to_poly_trait_predicate());
552 let selection = match selcx.select(&obligation) {
553 Ok(Some(vtable)) => vtable,
554 // Still ambiguous, so give up and let the caller decide whether this
555 // expression is really needed yet. Some associated constant values
556 // can't be evaluated until monomorphization is done in trans.
565 // NOTE: this code does not currently account for specialization, but when
566 // it does so, it should hook into the Reveal to determine when the
567 // constant should resolve; this will also require plumbing through to this
568 // function whether we are in "trans mode" to pick the right Reveal
569 // when constructing the inference context above.
571 traits::VtableImpl(ref impl_data) => {
572 let name = tcx.associated_item(trait_item_id).name;
573 let ac = tcx.associated_items(impl_data.impl_def_id)
574 .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
576 Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()),
577 None => default_value,
581 bug!("resolve_trait_associated_const: unexpected vtable type")
587 fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
590 -> CastResult<'tcx> {
591 let v = val.to_u128_unchecked();
593 ty::TyBool if v == 0 => Ok(Bool(false)),
594 ty::TyBool if v == 1 => Ok(Bool(true)),
595 ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i128 as i8))),
596 ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i128 as i16))),
597 ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i128 as i32))),
598 ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))),
599 ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))),
600 ty::TyInt(ast::IntTy::Is) => {
601 Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.int_type))))
603 ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
604 ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
605 ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
606 ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
607 ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))),
608 ty::TyUint(ast::UintTy::Us) => {
609 Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
611 ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(val.to_f64()))),
612 ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(val.to_f32()))),
613 ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
614 ty::TyChar => match val {
615 U8(u) => Ok(Char(u as char)),
622 fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
624 ty: Ty<'tcx>) -> CastResult<'tcx> {
626 ty::TyInt(_) | ty::TyUint(_) => {
628 F32(f) if f >= 0.0 => U128(f as u128),
629 F64(f) if f >= 0.0 => U128(f as u128),
631 F32(f) => I128(f as i128),
632 F64(f) => I128(f as i128)
635 if let (I128(_), &ty::TyUint(_)) = (i, &ty.sty) {
636 return Err(CannotCast);
639 cast_const_int(tcx, i, ty)
641 ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val {
645 ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val {
649 _ => Err(CannotCast),
653 fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
656 -> CastResult<'tcx> {
658 Integral(i) => cast_const_int(tcx, i, ty),
659 Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
660 Float(f) => cast_const_float(tcx, f, ty),
661 Char(c) => cast_const_int(tcx, U32(c as u32), ty),
662 Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
663 ByteStr(b) => match ty.sty {
665 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
667 ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
668 ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)),
670 Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
672 _ => Err(CannotCast),
674 _ => Err(CannotCast),
676 Str(s) => match ty.sty {
677 ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
678 ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
679 ty::TyStr => Ok(Str(s)),
680 _ => Err(CannotCast),
682 _ => Err(CannotCast),
684 _ => Err(CannotCast),
688 fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
689 tcx: TyCtxt<'a, 'tcx, 'tcx>,
691 -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
693 use syntax::ast::LitIntType::*;
695 if let ty::TyAdt(adt, _) = ty.sty {
697 ty = adt.repr.discr_type().to_ty(tcx)
702 LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
703 LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
704 LitKind::Byte(n) => Ok(Integral(U8(n))),
705 LitKind::Int(n, hint) => {
706 match (&ty.sty, hint) {
707 (&ty::TyInt(ity), _) |
708 (_, Signed(ity)) => {
709 Ok(Integral(ConstInt::new_signed_truncating(n as i128,
710 ity, tcx.sess.target.int_type)))
712 (&ty::TyUint(uty), _) |
713 (_, Unsigned(uty)) => {
714 Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
715 uty, tcx.sess.target.uint_type)))
720 LitKind::Float(n, fty) => {
721 parse_float(&n.as_str(), fty).map(Float)
723 LitKind::FloatUnsuffixed(n) => {
724 let fty = match ty.sty {
725 ty::TyFloat(fty) => fty,
728 parse_float(&n.as_str(), fty).map(Float)
730 LitKind::Bool(b) => Ok(Bool(b)),
731 LitKind::Char(c) => Ok(Char(c)),
735 fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
736 -> Result<ConstFloat, ErrKind<'tcx>> {
737 let val = match fty {
738 ast::FloatTy::F32 => num.parse::<f32>().map(F32),
739 ast::FloatTy::F64 => num.parse::<f64>().map(F64)
742 // FIXME(#31407) this is only necessary because float parsing is buggy
743 UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
747 pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
748 -> Result<Ordering, ErrorReported>
750 let result = match (a, b) {
751 (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
752 (&Float(a), &Float(b)) => a.try_cmp(b).ok(),
753 (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
754 (&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
755 (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
756 (&Char(a), &Char(ref b)) => Some(a.cmp(b)),
761 Some(result) => Ok(result),
763 // FIXME: can this ever be reached?
764 span_err!(tcx.sess, span, E0298,
765 "type mismatch comparing {} and {}",
773 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
774 pub fn compare_lit_exprs(&self,
777 b: &Expr) -> Result<Ordering, ErrorReported> {
779 let a = match self.eval(a) {
782 e.report(tcx, a.span, "expression");
783 return Err(ErrorReported);
786 let b = match self.eval(b) {
789 e.report(tcx, b.span, "expression");
790 return Err(ErrorReported);
793 compare_const_vals(tcx, span, &a, &b)
797 pub fn provide(providers: &mut Providers) {
798 *providers = Providers {
799 monomorphic_const_eval,
804 fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
806 -> EvalResult<'tcx> {
807 let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id));
809 let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
810 ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
811 tcx.hir.body(tcx.hir.body_owned_by(id))
813 tcx.sess.cstore.maybe_get_item_body(tcx, def_id).unwrap()