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, CtorKind};
19 use rustc::hir::def_id::DefId;
20 use rustc::ty::{self, Ty, TyCtxt};
21 use rustc::ty::maps::Providers;
22 use rustc::ty::util::IntTypeExt;
23 use rustc::ty::subst::{Substs, Subst};
24 use rustc::util::common::ErrorReported;
25 use rustc::util::nodemap::DefIdMap;
30 use rustc::hir::{self, Expr};
33 use std::cmp::Ordering;
35 use rustc_const_math::*;
38 ($e:expr, $exn:expr) => {
39 return Err(ConstEvalErr { span: $e.span, kind: $exn })
44 ($e:expr, $op:expr) => {
47 Err(e) => signal!($e, ErrKind::from(e)),
52 /// * `DefId` is the id of the constant.
53 /// * `Substs` is the monomorphized substitutions for the expression.
54 pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
55 key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
56 -> Option<(DefId, &'tcx Substs<'tcx>)> {
57 let (def_id, _) = key.value;
58 if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
59 match tcx.hir.find(node_id) {
60 Some(hir_map::NodeTraitItem(_)) => {
61 // If we have a trait item and the substitutions for it,
62 // `resolve_trait_associated_const` will select an impl
64 resolve_trait_associated_const(tcx, key)
69 match tcx.describe_def(def_id) {
70 Some(Def::AssociatedConst(_)) => {
71 // As mentioned in the comments above for in-crate
72 // constants, we only try to find the expression for a
73 // trait-associated const if the caller gives us the
74 // substitutions for the reference to it.
75 if tcx.trait_of_item(def_id).is_some() {
76 resolve_trait_associated_const(tcx, key)
86 pub struct ConstContext<'a, 'tcx: 'a> {
87 tcx: TyCtxt<'a, 'tcx, 'tcx>,
88 tables: &'a ty::TypeckTables<'tcx>,
89 param_env: ty::ParamEnv<'tcx>,
90 substs: &'tcx Substs<'tcx>,
91 fn_args: Option<DefIdMap<ConstVal<'tcx>>>
94 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
95 pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
96 param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
97 tables: &'a ty::TypeckTables<'tcx>)
101 param_env: param_env_and_substs.param_env,
103 substs: param_env_and_substs.value,
108 /// Evaluate a constant expression in a context where the expression isn't
109 /// guaranteed to be evaluable.
110 pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> {
111 if self.tables.tainted_by_errors {
112 signal!(e, TypeckError);
114 eval_const_expr_partial(self, e)
118 type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
120 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
121 e: &Expr) -> EvalResult<'tcx> {
123 let ety = cx.tables.expr_ty(e).subst(tcx, cx.substs);
125 let result = match e.node {
126 hir::ExprUnary(hir::UnNeg, ref inner) => {
127 // unary neg literals already got their sign during creation
128 if let hir::ExprLit(ref lit) = inner.node {
130 use syntax::ast::LitIntType::*;
131 const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128;
132 const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128;
133 const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
134 const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
135 const I128_OVERFLOW: u128 = i128::min_value() as u128;
136 match (&lit.node, &ety.sty) {
137 (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
138 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
139 return Ok(Integral(I8(i8::min_value())))
141 (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
142 (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
143 return Ok(Integral(I16(i16::min_value())))
145 (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
146 (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
147 return Ok(Integral(I32(i32::min_value())))
149 (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
150 (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
151 return Ok(Integral(I64(i64::min_value())))
153 (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
154 (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
155 return Ok(Integral(I128(i128::min_value())))
157 (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) |
158 (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
159 match tcx.sess.target.int_type {
160 IntTy::I16 => if n == I16_OVERFLOW {
161 return Ok(Integral(Isize(Is16(i16::min_value()))));
163 IntTy::I32 => if n == I32_OVERFLOW {
164 return Ok(Integral(Isize(Is32(i32::min_value()))));
166 IntTy::I64 => if n == I64_OVERFLOW {
167 return Ok(Integral(Isize(Is64(i64::min_value()))));
169 _ => span_bug!(e.span, "typeck error")
175 match cx.eval(inner)? {
176 Float(f) => Float(-f),
177 Integral(i) => Integral(math!(e, -i)),
178 const_val => signal!(e, NegateOn(const_val)),
181 hir::ExprUnary(hir::UnNot, ref inner) => {
182 match cx.eval(inner)? {
183 Integral(i) => Integral(math!(e, !i)),
185 const_val => signal!(e, NotOn(const_val)),
188 hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
189 hir::ExprBinary(op, ref a, ref b) => {
190 // technically, if we don't have type hints, but integral eval
191 // gives us a type through a type-suffix, cast or const def type
192 // we need to re-eval the other value of the BinOp if it was
194 match (cx.eval(a)?, cx.eval(b)?) {
195 (Float(a), Float(b)) => {
196 use std::cmp::Ordering::*;
198 hir::BiAdd => Float(math!(e, a + b)),
199 hir::BiSub => Float(math!(e, a - b)),
200 hir::BiMul => Float(math!(e, a * b)),
201 hir::BiDiv => Float(math!(e, a / b)),
202 hir::BiRem => Float(math!(e, a % b)),
203 hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
204 hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
205 hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
206 hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
207 hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
208 hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
209 _ => span_bug!(e.span, "typeck error"),
212 (Integral(a), Integral(b)) => {
213 use std::cmp::Ordering::*;
215 hir::BiAdd => Integral(math!(e, a + b)),
216 hir::BiSub => Integral(math!(e, a - b)),
217 hir::BiMul => Integral(math!(e, a * b)),
218 hir::BiDiv => Integral(math!(e, a / b)),
219 hir::BiRem => Integral(math!(e, a % b)),
220 hir::BiBitAnd => Integral(math!(e, a & b)),
221 hir::BiBitOr => Integral(math!(e, a | b)),
222 hir::BiBitXor => Integral(math!(e, a ^ b)),
223 hir::BiShl => Integral(math!(e, a << b)),
224 hir::BiShr => Integral(math!(e, a >> b)),
225 hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
226 hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
227 hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
228 hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
229 hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
230 hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
231 _ => span_bug!(e.span, "typeck error"),
234 (Bool(a), Bool(b)) => {
236 hir::BiAnd => a && b,
238 hir::BiBitXor => a ^ b,
239 hir::BiBitAnd => a & b,
240 hir::BiBitOr => a | b,
247 _ => span_bug!(e.span, "typeck error"),
250 (Char(a), Char(b)) => {
258 _ => span_bug!(e.span, "typeck error"),
262 _ => signal!(e, MiscBinaryOp),
265 hir::ExprCast(ref base, _) => {
266 let base_val = cx.eval(base)?;
267 let base_ty = cx.tables.expr_ty(base).subst(tcx, cx.substs);
271 match cast_const(tcx, base_val, ety) {
273 Err(kind) => signal!(e, kind),
277 hir::ExprPath(ref qpath) => {
278 let substs = cx.tables.node_substs(e.hir_id).subst(tcx, cx.substs);
279 match cx.tables.qpath_def(qpath, e.hir_id) {
281 Def::AssociatedConst(def_id) => {
282 match tcx.at(e.span).const_eval(cx.param_env.and((def_id, substs))) {
284 Err(ConstEvalErr { kind: TypeckError, .. }) => {
285 signal!(e, TypeckError);
288 debug!("bad reference: {:?}, {:?}", err.description(), err.span);
289 signal!(e, ErroneousReferencedConstant(box err))
293 Def::VariantCtor(variant_def, CtorKind::Const) => {
296 Def::VariantCtor(_, CtorKind::Fn) => {
297 signal!(e, UnimplementedConstVal("enum variants"));
299 Def::StructCtor(_, CtorKind::Const) => {
300 ConstVal::Struct(Default::default())
302 Def::StructCtor(_, CtorKind::Fn) => {
303 signal!(e, UnimplementedConstVal("tuple struct constructors"))
305 Def::Local(def_id) => {
306 debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args);
307 if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) {
310 signal!(e, NonConstPath);
313 Def::Method(id) | Def::Fn(id) => Function(id, substs),
314 Def::Err => span_bug!(e.span, "typeck error"),
315 _ => signal!(e, NonConstPath),
318 hir::ExprCall(ref callee, ref args) => {
319 let (def_id, substs) = match cx.eval(callee)? {
320 Function(def_id, substs) => (def_id, substs),
321 _ => signal!(e, TypeckError),
324 if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic {
325 let layout_of = |ty: Ty<'tcx>| {
326 ty.layout(tcx, cx.param_env).map_err(|err| {
327 ConstEvalErr { span: e.span, kind: LayoutError(err) }
330 match &tcx.item_name(def_id).as_str()[..] {
332 let size = layout_of(substs.type_at(0))?.size(tcx);
333 return Ok(Integral(Usize(ConstUsize::new(size.bytes(),
334 tcx.sess.target.uint_type).unwrap())));
337 let align = layout_of(substs.type_at(0))?.align(tcx);
338 return Ok(Integral(Usize(ConstUsize::new(align.abi(),
339 tcx.sess.target.uint_type).unwrap())));
341 _ => signal!(e, TypeckError)
345 let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
346 if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
347 if fn_like.constness() == hir::Constness::Const {
348 tcx.hir.body(fn_like.body())
350 signal!(e, TypeckError)
353 signal!(e, TypeckError)
356 if tcx.is_const_fn(def_id) {
357 tcx.extern_const_body(def_id)
359 signal!(e, TypeckError)
363 let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
364 hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
366 }).collect::<Vec<_>>();
367 assert_eq!(arg_defs.len(), args.len());
369 let mut call_args = DefIdMap();
370 for (arg, arg_expr) in arg_defs.into_iter().zip(args.iter()) {
371 let arg_val = cx.eval(arg_expr)?;
372 debug!("const call arg: {:?}", arg);
373 if let Some(def_id) = arg {
374 assert!(call_args.insert(def_id, arg_val).is_none());
377 debug!("const call({:?})", call_args);
378 let callee_cx = ConstContext {
380 param_env: cx.param_env,
381 tables: tcx.typeck_tables_of(def_id),
383 fn_args: Some(call_args)
385 callee_cx.eval(&body.value)?
387 hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
389 Err(err) => signal!(e, err),
391 hir::ExprBlock(ref block) => {
393 Some(ref expr) => cx.eval(expr)?,
394 None => Tuple(vec![]),
397 hir::ExprType(ref e, _) => cx.eval(e)?,
398 hir::ExprTup(ref fields) => {
399 Tuple(fields.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
401 hir::ExprStruct(_, ref fields, _) => {
402 Struct(fields.iter().map(|f| {
403 cx.eval(&f.expr).map(|v| (f.name.node, v))
404 }).collect::<Result<_, _>>()?)
406 hir::ExprIndex(ref arr, ref idx) => {
407 if !tcx.sess.features.borrow().const_indexing {
408 signal!(e, IndexOpFeatureGated);
410 let arr = cx.eval(arr)?;
411 let idx = match cx.eval(idx)? {
412 Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
413 _ => signal!(idx, IndexNotUsize),
415 assert_eq!(idx as usize as u64, idx);
418 if let Some(elem) = v.get(idx as usize) {
421 let n = v.len() as u64;
422 assert_eq!(n as usize as u64, n);
423 signal!(e, IndexOutOfBounds { len: n, index: idx })
427 Repeat(.., n) if idx >= n => {
428 signal!(e, IndexOutOfBounds { len: n, index: idx })
430 Repeat(ref elem, _) => (**elem).clone(),
432 ByteStr(ref data) if idx >= data.len() as u64 => {
433 signal!(e, IndexOutOfBounds { len: data.len() as u64, index: idx })
436 Integral(U8(data[idx as usize]))
439 _ => signal!(e, IndexedNonVec),
442 hir::ExprArray(ref v) => {
443 Array(v.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
445 hir::ExprRepeat(ref elem, _) => {
446 let n = match ety.sty {
447 ty::TyArray(_, n) => n as u64,
448 _ => span_bug!(e.span, "typeck error")
450 Repeat(Box::new(cx.eval(elem)?), n)
452 hir::ExprTupField(ref base, index) => {
453 let c = cx.eval(base)?;
454 if let Tuple(ref fields) = c {
455 fields[index.node].clone()
457 signal!(base, ExpectedConstTuple);
460 hir::ExprField(ref base, field_name) => {
461 let c = cx.eval(base)?;
462 if let Struct(ref fields) = c {
463 if let Some(f) = fields.get(&field_name.node) {
466 signal!(e, MissingStructField);
469 signal!(base, ExpectedConstStruct);
472 hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),
473 _ => signal!(e, MiscCatchAll)
479 fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
480 key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
481 -> Option<(DefId, &'tcx Substs<'tcx>)> {
482 let param_env = key.param_env;
483 let (def_id, substs) = key.value;
484 let trait_item = tcx.associated_item(def_id);
485 let trait_id = trait_item.container.id();
486 let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs));
487 debug!("resolve_trait_associated_const: trait_ref={:?}",
490 tcx.infer_ctxt().enter(|infcx| {
491 let mut selcx = traits::SelectionContext::new(&infcx);
492 let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
494 trait_ref.to_poly_trait_predicate());
495 let selection = match selcx.select(&obligation) {
496 Ok(Some(vtable)) => vtable,
497 // Still ambiguous, so give up and let the caller decide whether this
498 // expression is really needed yet. Some associated constant values
499 // can't be evaluated until monomorphization is done in trans.
508 // NOTE: this code does not currently account for specialization, but when
509 // it does so, it should hook into the param_env.reveal to determine when the
510 // constant should resolve.
512 traits::VtableImpl(ref impl_data) => {
513 let name = trait_item.name;
514 let ac = tcx.associated_items(impl_data.impl_def_id)
515 .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
517 // FIXME(eddyb) Use proper Instance resolution to
518 // get the correct Substs returned from here.
520 let substs = Substs::identity_for_item(tcx, ic.def_id);
521 Some((ic.def_id, substs))
524 if trait_item.defaultness.has_value() {
532 traits::VtableParam(_) => None,
534 bug!("resolve_trait_associated_const: unexpected vtable type {:?}", selection)
540 fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
543 -> CastResult<'tcx> {
544 let v = val.to_u128_unchecked();
546 ty::TyBool if v == 0 => Ok(Bool(false)),
547 ty::TyBool if v == 1 => Ok(Bool(true)),
548 ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i128 as i8))),
549 ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i128 as i16))),
550 ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i128 as i32))),
551 ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))),
552 ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))),
553 ty::TyInt(ast::IntTy::Is) => {
554 Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.int_type))))
556 ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
557 ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
558 ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
559 ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
560 ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))),
561 ty::TyUint(ast::UintTy::Us) => {
562 Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
564 ty::TyFloat(fty) => {
565 if let Some(i) = val.to_u128() {
566 Ok(Float(ConstFloat::from_u128(i, fty)))
568 // The value must be negative, go through signed integers.
569 let i = val.to_u128_unchecked() as i128;
570 Ok(Float(ConstFloat::from_i128(i, fty)))
573 ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
574 ty::TyChar => match val {
575 U8(u) => Ok(Char(u as char)),
578 _ => Err(CannotCast),
582 fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
584 ty: Ty<'tcx>) -> CastResult<'tcx> {
585 let int_width = |ty| {
586 ty::layout::Integer::from_attr(tcx, ty).size().bits() as usize
590 if let Some(i) = val.to_i128(int_width(attr::SignedInt(ity))) {
591 cast_const_int(tcx, I128(i), ty)
597 if let Some(i) = val.to_u128(int_width(attr::UnsignedInt(uty))) {
598 cast_const_int(tcx, U128(i), ty)
603 ty::TyFloat(fty) => Ok(Float(val.convert(fty))),
604 _ => Err(CannotCast),
608 fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
611 -> CastResult<'tcx> {
613 Integral(i) => cast_const_int(tcx, i, ty),
614 Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
615 Float(f) => cast_const_float(tcx, f, ty),
616 Char(c) => cast_const_int(tcx, U32(c as u32), ty),
618 let adt = tcx.adt_def(tcx.parent_def_id(v).unwrap());
619 let idx = adt.variant_index_with_id(v);
620 cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty)
622 Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
623 ByteStr(b) => match ty.sty {
625 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
627 ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
628 ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)),
630 Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
632 _ => Err(CannotCast),
634 _ => Err(CannotCast),
636 Str(s) => match ty.sty {
637 ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
638 ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
639 ty::TyStr => Ok(Str(s)),
640 _ => Err(CannotCast),
642 _ => Err(CannotCast),
644 _ => Err(CannotCast),
648 fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
649 tcx: TyCtxt<'a, 'tcx, 'tcx>,
651 -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
653 use syntax::ast::LitIntType::*;
655 if let ty::TyAdt(adt, _) = ty.sty {
657 ty = adt.repr.discr_type().to_ty(tcx)
662 LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
663 LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
664 LitKind::Byte(n) => Ok(Integral(U8(n))),
665 LitKind::Int(n, hint) => {
666 match (&ty.sty, hint) {
667 (&ty::TyInt(ity), _) |
668 (_, Signed(ity)) => {
669 Ok(Integral(ConstInt::new_signed_truncating(n as i128,
670 ity, tcx.sess.target.int_type)))
672 (&ty::TyUint(uty), _) |
673 (_, Unsigned(uty)) => {
674 Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
675 uty, tcx.sess.target.uint_type)))
680 LitKind::Float(n, fty) => {
681 parse_float(&n.as_str(), fty).map(Float)
683 LitKind::FloatUnsuffixed(n) => {
684 let fty = match ty.sty {
685 ty::TyFloat(fty) => fty,
688 parse_float(&n.as_str(), fty).map(Float)
690 LitKind::Bool(b) => Ok(Bool(b)),
691 LitKind::Char(c) => Ok(Char(c)),
695 fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
696 -> Result<ConstFloat, ErrKind<'tcx>> {
697 ConstFloat::from_str(num, fty).map_err(|_| {
698 // FIXME(#31407) this is only necessary because float parsing is buggy
699 UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
703 pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
704 -> Result<Ordering, ErrorReported>
706 let result = match (a, b) {
707 (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
708 (&Float(a), &Float(b)) => a.try_cmp(b).ok(),
709 (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
710 (&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
711 (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
712 (&Char(a), &Char(ref b)) => Some(a.cmp(b)),
717 Some(result) => Ok(result),
719 // FIXME: can this ever be reached?
720 span_err!(tcx.sess, span, E0298,
721 "type mismatch comparing {} and {}",
729 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
730 pub fn compare_lit_exprs(&self,
733 b: &Expr) -> Result<Ordering, ErrorReported> {
735 let a = match self.eval(a) {
738 e.report(tcx, a.span, "expression");
739 return Err(ErrorReported);
742 let b = match self.eval(b) {
745 e.report(tcx, b.span, "expression");
746 return Err(ErrorReported);
749 compare_const_vals(tcx, span, &a, &b)
753 pub fn provide(providers: &mut Providers) {
754 *providers = Providers {
760 fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
761 key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
762 -> EvalResult<'tcx> {
763 let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, key) {
766 return Err(ConstEvalErr {
767 span: tcx.def_span(key.value.0),
772 let tables = tcx.typeck_tables_of(def_id);
773 let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
774 tcx.mir_const_qualif(def_id);
775 tcx.hir.body(tcx.hir.body_owned_by(id))
777 tcx.extern_const_body(def_id)
779 ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value)