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::ConstAggregate::*;
13 use rustc::middle::const_val::ErrKind::*;
14 use rustc::middle::const_val::{ByteArray, ConstVal, ConstEvalErr, EvalResult, ErrKind};
16 use rustc::hir::map::blocks::FnLikeNode;
17 use rustc::hir::def::{Def, CtorKind};
18 use rustc::hir::def_id::DefId;
19 use rustc::ty::{self, Ty, TyCtxt};
20 use rustc::ty::util::IntTypeExt;
21 use rustc::ty::subst::{Substs, Subst};
22 use rustc::util::common::ErrorReported;
23 use rustc::util::nodemap::NodeMap;
28 use rustc::hir::{self, Expr};
31 use std::cmp::Ordering;
33 use rustc_const_math::*;
35 ($e:expr, $exn:expr) => {
36 return Err(ConstEvalErr { span: $e.span, kind: $exn })
41 ($e:expr, $op:expr) => {
44 Err(e) => signal!($e, ErrKind::from(e)),
49 /// * `DefId` is the id of the constant.
50 /// * `Substs` is the monomorphized substitutions for the expression.
51 pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
52 key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
53 -> Option<(DefId, &'tcx Substs<'tcx>)> {
54 ty::Instance::resolve(
59 ).map(|instance| (instance.def_id(), instance.substs))
62 pub struct ConstContext<'a, 'tcx: 'a> {
63 tcx: TyCtxt<'a, 'tcx, 'tcx>,
64 tables: &'a ty::TypeckTables<'tcx>,
65 param_env: ty::ParamEnv<'tcx>,
66 substs: &'tcx Substs<'tcx>,
67 fn_args: Option<NodeMap<&'tcx ty::Const<'tcx>>>
70 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
71 pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
72 param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
73 tables: &'a ty::TypeckTables<'tcx>)
77 param_env: param_env_and_substs.param_env,
79 substs: param_env_and_substs.value,
84 /// Evaluate a constant expression in a context where the expression isn't
85 /// guaranteed to be evaluable.
86 pub fn eval(&self, e: &'tcx Expr) -> EvalResult<'tcx> {
87 if self.tables.tainted_by_errors {
88 signal!(e, TypeckError);
90 eval_const_expr_partial(self, e)
94 type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
96 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
97 e: &'tcx Expr) -> EvalResult<'tcx> {
98 trace!("eval_const_expr_partial: {:?}", e);
100 let ty = cx.tables.expr_ty(e).subst(tcx, cx.substs);
101 let mk_const = |val| tcx.mk_const(ty::Const { val, ty });
103 let result = match e.node {
104 hir::ExprUnary(hir::UnNeg, ref inner) => {
105 // unary neg literals already got their sign during creation
106 if let hir::ExprLit(ref lit) = inner.node {
108 use syntax::ast::LitIntType::*;
109 const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128;
110 const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128;
111 const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
112 const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
113 const I128_OVERFLOW: u128 = i128::min_value() as u128;
114 let negated = match (&lit.node, &ty.sty) {
115 (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
116 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
117 Some(I8(i8::min_value()))
119 (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
120 (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
121 Some(I16(i16::min_value()))
123 (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
124 (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
125 Some(I32(i32::min_value()))
127 (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
128 (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
129 Some(I64(i64::min_value()))
131 (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
132 (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
133 Some(I128(i128::min_value()))
135 (&LitKind::Int(n, _), &ty::TyInt(IntTy::Isize)) |
136 (&LitKind::Int(n, Signed(IntTy::Isize)), _) => {
137 match tcx.sess.target.isize_ty {
138 IntTy::I16 => if n == I16_OVERFLOW {
139 Some(Isize(Is16(i16::min_value())))
143 IntTy::I32 => if n == I32_OVERFLOW {
144 Some(Isize(Is32(i32::min_value())))
148 IntTy::I64 => if n == I64_OVERFLOW {
149 Some(Isize(Is64(i64::min_value())))
153 _ => span_bug!(e.span, "typeck error")
158 if let Some(i) = negated {
159 return Ok(mk_const(Integral(i)));
162 mk_const(match cx.eval(inner)?.val {
163 Float(f) => Float(-f),
164 Integral(i) => Integral(math!(e, -i)),
165 _ => signal!(e, TypeckError)
168 hir::ExprUnary(hir::UnNot, ref inner) => {
169 mk_const(match cx.eval(inner)?.val {
170 Integral(i) => Integral(math!(e, !i)),
172 _ => signal!(e, TypeckError)
175 hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
176 hir::ExprBinary(op, ref a, ref b) => {
177 // technically, if we don't have type hints, but integral eval
178 // gives us a type through a type-suffix, cast or const def type
179 // we need to re-eval the other value of the BinOp if it was
181 mk_const(match (cx.eval(a)?.val, cx.eval(b)?.val) {
182 (Float(a), Float(b)) => {
183 use std::cmp::Ordering::*;
185 hir::BiAdd => Float(math!(e, a + b)),
186 hir::BiSub => Float(math!(e, a - b)),
187 hir::BiMul => Float(math!(e, a * b)),
188 hir::BiDiv => Float(math!(e, a / b)),
189 hir::BiRem => Float(math!(e, a % b)),
190 hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
191 hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
192 hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
193 hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
194 hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
195 hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
196 _ => span_bug!(e.span, "typeck error"),
199 (Integral(a), Integral(b)) => {
200 use std::cmp::Ordering::*;
202 hir::BiAdd => Integral(math!(e, a + b)),
203 hir::BiSub => Integral(math!(e, a - b)),
204 hir::BiMul => Integral(math!(e, a * b)),
205 hir::BiDiv => Integral(math!(e, a / b)),
206 hir::BiRem => Integral(math!(e, a % b)),
207 hir::BiBitAnd => Integral(math!(e, a & b)),
208 hir::BiBitOr => Integral(math!(e, a | b)),
209 hir::BiBitXor => Integral(math!(e, a ^ b)),
210 hir::BiShl => Integral(math!(e, a << b)),
211 hir::BiShr => Integral(math!(e, a >> b)),
212 hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
213 hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
214 hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
215 hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
216 hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
217 hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
218 _ => span_bug!(e.span, "typeck error"),
221 (Bool(a), Bool(b)) => {
223 hir::BiAnd => a && b,
225 hir::BiBitXor => a ^ b,
226 hir::BiBitAnd => a & b,
227 hir::BiBitOr => a | b,
234 _ => span_bug!(e.span, "typeck error"),
237 (Char(a), Char(b)) => {
245 _ => span_bug!(e.span, "typeck error"),
249 _ => signal!(e, MiscBinaryOp),
252 hir::ExprCast(ref base, _) => {
253 let base_val = cx.eval(base)?;
254 let base_ty = cx.tables.expr_ty(base).subst(tcx, cx.substs);
258 match cast_const(tcx, base_val.val, ty) {
259 Ok(val) => mk_const(val),
260 Err(kind) => signal!(e, kind),
264 hir::ExprPath(ref qpath) => {
265 let substs = cx.tables.node_substs(e.hir_id).subst(tcx, cx.substs);
266 match cx.tables.qpath_def(qpath, e.hir_id) {
268 Def::AssociatedConst(def_id) => {
269 let substs = tcx.normalize_associated_type_in_env(&substs, cx.param_env);
270 match tcx.at(e.span).const_eval(cx.param_env.and((def_id, substs))) {
272 Err(ConstEvalErr { kind: TypeckError, .. }) => {
273 signal!(e, TypeckError);
276 debug!("bad reference: {:?}, {:?}", err.description(), err.span);
277 signal!(e, ErroneousReferencedConstant(box err))
281 Def::VariantCtor(variant_def, CtorKind::Const) => {
282 mk_const(Variant(variant_def))
284 Def::VariantCtor(_, CtorKind::Fn) => {
285 signal!(e, UnimplementedConstVal("enum variants"));
287 Def::StructCtor(_, CtorKind::Const) => {
288 mk_const(Aggregate(Struct(&[])))
290 Def::StructCtor(_, CtorKind::Fn) => {
291 signal!(e, UnimplementedConstVal("tuple struct constructors"))
294 debug!("Def::Local({:?}): {:?}", id, cx.fn_args);
295 if let Some(&val) = cx.fn_args.as_ref().and_then(|args| args.get(&id)) {
298 signal!(e, NonConstPath);
301 Def::Method(id) | Def::Fn(id) => mk_const(Function(id, substs)),
302 Def::Err => span_bug!(e.span, "typeck error"),
303 _ => signal!(e, NonConstPath),
306 hir::ExprCall(ref callee, ref args) => {
307 let (def_id, substs) = match cx.eval(callee)?.val {
308 Function(def_id, substs) => (def_id, substs),
309 _ => signal!(e, TypeckError),
312 if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic {
313 let layout_of = |ty: Ty<'tcx>| {
314 let ty = tcx.erase_regions(&ty);
315 tcx.at(e.span).layout_of(cx.param_env.and(ty)).map_err(|err| {
316 ConstEvalErr { span: e.span, kind: LayoutError(err) }
319 match &tcx.item_name(def_id)[..] {
321 let size = layout_of(substs.type_at(0))?.size.bytes();
322 return Ok(mk_const(Integral(Usize(ConstUsize::new(size,
323 tcx.sess.target.usize_ty).unwrap()))));
326 let align = layout_of(substs.type_at(0))?.align.abi();
327 return Ok(mk_const(Integral(Usize(ConstUsize::new(align,
328 tcx.sess.target.usize_ty).unwrap()))));
331 let type_id = tcx.type_id_hash(substs.type_at(0));
332 return Ok(mk_const(Integral(U64(type_id))));
334 _ => signal!(e, TypeckError)
338 let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
339 if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
340 if fn_like.constness() == hir::Constness::Const {
341 tcx.hir.body(fn_like.body())
343 signal!(e, TypeckError)
346 signal!(e, TypeckError)
349 if tcx.is_const_fn(def_id) {
350 tcx.extern_const_body(def_id).body
352 signal!(e, TypeckError)
356 let arg_ids = body.arguments.iter().map(|arg| match arg.pat.node {
357 hir::PatKind::Binding(_, canonical_id, _, _) => Some(canonical_id),
359 }).collect::<Vec<_>>();
360 assert_eq!(arg_ids.len(), args.len());
362 let mut call_args = NodeMap();
363 for (arg, arg_expr) in arg_ids.into_iter().zip(args.iter()) {
364 let arg_val = cx.eval(arg_expr)?;
365 debug!("const call arg: {:?}", arg);
366 if let Some(id) = arg {
367 assert!(call_args.insert(id, arg_val).is_none());
370 debug!("const call({:?})", call_args);
371 let callee_cx = ConstContext {
373 param_env: cx.param_env,
374 tables: tcx.typeck_tables_of(def_id),
376 fn_args: Some(call_args)
378 callee_cx.eval(&body.value)?
380 hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty) {
381 Ok(val) => mk_const(val),
382 Err(err) => signal!(e, err),
384 hir::ExprBlock(ref block) => {
386 Some(ref expr) => cx.eval(expr)?,
387 None => mk_const(Aggregate(Tuple(&[]))),
390 hir::ExprType(ref e, _) => cx.eval(e)?,
391 hir::ExprTup(ref fields) => {
392 let values = fields.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
393 mk_const(Aggregate(Tuple(tcx.alloc_const_slice(&values))))
395 hir::ExprStruct(_, ref fields, _) => {
396 mk_const(Aggregate(Struct(tcx.alloc_name_const_slice(&fields.iter().map(|f| {
397 cx.eval(&f.expr).map(|v| (f.name.node, v))
398 }).collect::<Result<Vec<_>, _>>()?))))
400 hir::ExprIndex(ref arr, ref idx) => {
401 if !tcx.sess.features.borrow().const_indexing {
402 signal!(e, IndexOpFeatureGated);
404 let arr = cx.eval(arr)?;
405 let idx = match cx.eval(idx)?.val {
406 Integral(Usize(i)) => i.as_u64(),
407 _ => signal!(idx, IndexNotUsize),
409 assert_eq!(idx as usize as u64, idx);
411 Aggregate(Array(v)) => {
412 if let Some(&elem) = v.get(idx as usize) {
415 let n = v.len() as u64;
416 signal!(e, IndexOutOfBounds { len: n, index: idx })
420 Aggregate(Repeat(.., n)) if idx >= n => {
421 signal!(e, IndexOutOfBounds { len: n, index: idx })
423 Aggregate(Repeat(elem, _)) => elem,
425 ByteStr(b) if idx >= b.data.len() as u64 => {
426 signal!(e, IndexOutOfBounds { len: b.data.len() as u64, index: idx })
429 mk_const(Integral(U8(b.data[idx as usize])))
432 _ => signal!(e, IndexedNonVec),
435 hir::ExprArray(ref v) => {
436 let values = v.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
437 mk_const(Aggregate(Array(tcx.alloc_const_slice(&values))))
439 hir::ExprRepeat(ref elem, _) => {
440 let n = match ty.sty {
441 ty::TyArray(_, n) => n.val.to_const_int().unwrap().to_u64().unwrap(),
442 _ => span_bug!(e.span, "typeck error")
444 mk_const(Aggregate(Repeat(cx.eval(elem)?, n)))
446 hir::ExprTupField(ref base, index) => {
447 if let Aggregate(Tuple(fields)) = cx.eval(base)?.val {
450 signal!(base, ExpectedConstTuple);
453 hir::ExprField(ref base, field_name) => {
454 if let Aggregate(Struct(fields)) = cx.eval(base)?.val {
455 if let Some(&(_, f)) = fields.iter().find(|&&(name, _)| name == field_name.node) {
458 signal!(e, MissingStructField);
461 signal!(base, ExpectedConstStruct);
464 hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),
465 _ => signal!(e, MiscCatchAll)
471 fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
474 -> CastResult<'tcx> {
475 let v = val.to_u128_unchecked();
477 ty::TyBool if v == 0 => Ok(Bool(false)),
478 ty::TyBool if v == 1 => Ok(Bool(true)),
479 ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i128 as i8))),
480 ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i128 as i16))),
481 ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i128 as i32))),
482 ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))),
483 ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))),
484 ty::TyInt(ast::IntTy::Isize) => {
485 Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.isize_ty))))
487 ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
488 ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
489 ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
490 ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
491 ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))),
492 ty::TyUint(ast::UintTy::Usize) => {
493 Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.usize_ty))))
495 ty::TyFloat(fty) => {
496 if let Some(i) = val.to_u128() {
497 Ok(Float(ConstFloat::from_u128(i, fty)))
499 // The value must be negative, go through signed integers.
500 let i = val.to_u128_unchecked() as i128;
501 Ok(Float(ConstFloat::from_i128(i, fty)))
504 ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
505 ty::TyChar => match val {
506 U8(u) => Ok(Char(u as char)),
509 _ => Err(CannotCast),
513 fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
515 ty: Ty<'tcx>) -> CastResult<'tcx> {
516 let int_width = |ty| {
517 ty::layout::Integer::from_attr(tcx, ty).size().bits() as usize
521 if let Some(i) = val.to_i128(int_width(attr::SignedInt(ity))) {
522 cast_const_int(tcx, I128(i), ty)
528 if let Some(i) = val.to_u128(int_width(attr::UnsignedInt(uty))) {
529 cast_const_int(tcx, U128(i), ty)
534 ty::TyFloat(fty) => Ok(Float(val.convert(fty))),
535 _ => Err(CannotCast),
539 fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
542 -> CastResult<'tcx> {
544 Integral(i) => cast_const_int(tcx, i, ty),
545 Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
546 Float(f) => cast_const_float(tcx, f, ty),
547 Char(c) => cast_const_int(tcx, U32(c as u32), ty),
549 let adt = tcx.adt_def(tcx.parent_def_id(v).unwrap());
550 let idx = adt.variant_index_with_id(v);
551 cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty)
553 Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
554 ByteStr(b) => match ty.sty {
556 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
558 ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
559 ty::TyArray(ty, n) => {
560 let n = n.val.to_const_int().unwrap().to_u64().unwrap();
561 if ty == tcx.types.u8 && n == b.data.len() as u64 {
568 Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
570 _ => Err(CannotCast),
572 _ => Err(CannotCast),
574 Str(s) => match ty.sty {
575 ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
576 ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
577 ty::TyStr => Ok(Str(s)),
578 _ => Err(CannotCast),
580 _ => Err(CannotCast),
582 _ => Err(CannotCast),
586 fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
587 tcx: TyCtxt<'a, 'tcx, 'tcx>,
589 -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
591 use syntax::ast::LitIntType::*;
593 if let ty::TyAdt(adt, _) = ty.sty {
595 ty = adt.repr.discr_type().to_ty(tcx)
600 LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
601 LitKind::ByteStr(ref data) => Ok(ByteStr(ByteArray { data })),
602 LitKind::Byte(n) => Ok(Integral(U8(n))),
603 LitKind::Int(n, hint) => {
604 match (&ty.sty, hint) {
605 (&ty::TyInt(ity), _) |
606 (_, Signed(ity)) => {
607 Ok(Integral(ConstInt::new_signed_truncating(n as i128,
608 ity, tcx.sess.target.isize_ty)))
610 (&ty::TyUint(uty), _) |
611 (_, Unsigned(uty)) => {
612 Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
613 uty, tcx.sess.target.usize_ty)))
618 LitKind::Float(n, fty) => {
619 parse_float(&n.as_str(), fty).map(Float)
621 LitKind::FloatUnsuffixed(n) => {
622 let fty = match ty.sty {
623 ty::TyFloat(fty) => fty,
626 parse_float(&n.as_str(), fty).map(Float)
628 LitKind::Bool(b) => Ok(Bool(b)),
629 LitKind::Char(c) => Ok(Char(c)),
633 fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
634 -> Result<ConstFloat, ErrKind<'tcx>> {
635 ConstFloat::from_str(num, fty).map_err(|_| {
636 // FIXME(#31407) this is only necessary because float parsing is buggy
637 UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
641 pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
642 -> Result<Ordering, ErrorReported>
644 let result = match (a, b) {
645 (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
646 (&Float(a), &Float(b)) => a.try_cmp(b).ok(),
647 (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
648 (&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
649 (&ByteStr(a), &ByteStr(b)) => Some(a.data.cmp(b.data)),
650 (&Char(a), &Char(b)) => Some(a.cmp(&b)),
655 Some(result) => Ok(result),
657 // FIXME: can this ever be reached?
658 tcx.sess.delay_span_bug(span,
659 &format!("type mismatch comparing {:?} and {:?}", a, b));
665 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
666 pub fn compare_lit_exprs(&self,
669 b: &'tcx Expr) -> Result<Ordering, ErrorReported> {
671 let a = match self.eval(a) {
674 e.report(tcx, a.span, "expression");
675 return Err(ErrorReported);
678 let b = match self.eval(b) {
681 e.report(tcx, b.span, "expression");
682 return Err(ErrorReported);
685 compare_const_vals(tcx, span, &a.val, &b.val)