]> git.proxmox.com Git - rustc.git/blob - src/librustc_const_eval/eval.rs
New upstream version 1.20.0+dfsg1
[rustc.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 use rustc::middle::const_val::ConstVal::*;
12 use rustc::middle::const_val::ErrKind::*;
13 use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind};
14
15 use rustc::hir::map as hir_map;
16 use rustc::hir::map::blocks::FnLikeNode;
17 use rustc::traits;
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::traits::Reveal;
25 use rustc::util::common::ErrorReported;
26 use rustc::util::nodemap::DefIdMap;
27
28 use syntax::ast;
29 use rustc::hir::{self, Expr};
30 use syntax_pos::Span;
31
32 use std::cmp::Ordering;
33
34 use rustc_const_math::*;
35
36 macro_rules! signal {
37 ($e:expr, $exn:expr) => {
38 return Err(ConstEvalErr { span: $e.span, kind: $exn })
39 }
40 }
41
42 macro_rules! math {
43 ($e:expr, $op:expr) => {
44 match $op {
45 Ok(val) => val,
46 Err(e) => signal!($e, ErrKind::from(e)),
47 }
48 }
49 }
50
51 /// * `def_id` is the id of the constant.
52 /// * `substs` is the monomorphized substitutions for the expression.
53 ///
54 /// `substs` is optional and is used for associated constants.
55 /// This generally happens in late/trans const evaluation.
56 pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
57 def_id: DefId,
58 substs: &'tcx Substs<'tcx>)
59 -> Option<(DefId, &'tcx Substs<'tcx>)> {
60 if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
61 match tcx.hir.find(node_id) {
62 Some(hir_map::NodeTraitItem(_)) => {
63 // If we have a trait item and the substitutions for it,
64 // `resolve_trait_associated_const` will select an impl
65 // or the default.
66 resolve_trait_associated_const(tcx, def_id, substs)
67 }
68 _ => Some((def_id, substs))
69 }
70 } else {
71 match tcx.describe_def(def_id) {
72 Some(Def::AssociatedConst(_)) => {
73 // As mentioned in the comments above for in-crate
74 // constants, we only try to find the expression for a
75 // trait-associated const if the caller gives us the
76 // substitutions for the reference to it.
77 if tcx.trait_of_item(def_id).is_some() {
78 resolve_trait_associated_const(tcx, def_id, substs)
79 } else {
80 Some((def_id, substs))
81 }
82 }
83 _ => Some((def_id, substs))
84 }
85 }
86 }
87
88 pub struct ConstContext<'a, 'tcx: 'a> {
89 tcx: TyCtxt<'a, 'tcx, 'tcx>,
90 tables: &'a ty::TypeckTables<'tcx>,
91 substs: &'tcx Substs<'tcx>,
92 fn_args: Option<DefIdMap<ConstVal<'tcx>>>
93 }
94
95 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
96 pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self {
97 ConstContext {
98 tcx: tcx,
99 tables: tables,
100 substs: tcx.intern_substs(&[]),
101 fn_args: None
102 }
103 }
104
105 /// Evaluate a constant expression in a context where the expression isn't
106 /// guaranteed to be evaluatable.
107 pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> {
108 if self.tables.tainted_by_errors {
109 signal!(e, TypeckError);
110 }
111 eval_const_expr_partial(self, e)
112 }
113 }
114
115 type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
116
117 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
118 e: &Expr) -> EvalResult<'tcx> {
119 let tcx = cx.tcx;
120 let ety = cx.tables.expr_ty(e);
121
122 // Avoid applying substitutions if they're empty, that'd ICE.
123 let ety = if cx.substs.is_empty() {
124 ety
125 } else {
126 ety.subst(tcx, cx.substs)
127 };
128
129 let result = match e.node {
130 hir::ExprUnary(hir::UnNeg, ref inner) => {
131 // unary neg literals already got their sign during creation
132 if let hir::ExprLit(ref lit) = inner.node {
133 use syntax::ast::*;
134 use syntax::ast::LitIntType::*;
135 const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128;
136 const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128;
137 const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
138 const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
139 const I128_OVERFLOW: u128 = i128::min_value() as u128;
140 match (&lit.node, &ety.sty) {
141 (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
142 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
143 return Ok(Integral(I8(i8::min_value())))
144 },
145 (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
146 (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
147 return Ok(Integral(I16(i16::min_value())))
148 },
149 (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
150 (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
151 return Ok(Integral(I32(i32::min_value())))
152 },
153 (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
154 (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
155 return Ok(Integral(I64(i64::min_value())))
156 },
157 (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
158 (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
159 return Ok(Integral(I128(i128::min_value())))
160 },
161 (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) |
162 (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
163 match tcx.sess.target.int_type {
164 IntTy::I16 => if n == I16_OVERFLOW {
165 return Ok(Integral(Isize(Is16(i16::min_value()))));
166 },
167 IntTy::I32 => if n == I32_OVERFLOW {
168 return Ok(Integral(Isize(Is32(i32::min_value()))));
169 },
170 IntTy::I64 => if n == I64_OVERFLOW {
171 return Ok(Integral(Isize(Is64(i64::min_value()))));
172 },
173 _ => span_bug!(e.span, "typeck error")
174 }
175 },
176 _ => {},
177 }
178 }
179 match cx.eval(inner)? {
180 Float(f) => Float(-f),
181 Integral(i) => Integral(math!(e, -i)),
182 const_val => signal!(e, NegateOn(const_val)),
183 }
184 }
185 hir::ExprUnary(hir::UnNot, ref inner) => {
186 match cx.eval(inner)? {
187 Integral(i) => Integral(math!(e, !i)),
188 Bool(b) => Bool(!b),
189 const_val => signal!(e, NotOn(const_val)),
190 }
191 }
192 hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
193 hir::ExprBinary(op, ref a, ref b) => {
194 // technically, if we don't have type hints, but integral eval
195 // gives us a type through a type-suffix, cast or const def type
196 // we need to re-eval the other value of the BinOp if it was
197 // not inferred
198 match (cx.eval(a)?, cx.eval(b)?) {
199 (Float(a), Float(b)) => {
200 use std::cmp::Ordering::*;
201 match op.node {
202 hir::BiAdd => Float(math!(e, a + b)),
203 hir::BiSub => Float(math!(e, a - b)),
204 hir::BiMul => Float(math!(e, a * b)),
205 hir::BiDiv => Float(math!(e, a / b)),
206 hir::BiRem => Float(math!(e, a % b)),
207 hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
208 hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
209 hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
210 hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
211 hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
212 hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
213 _ => span_bug!(e.span, "typeck error"),
214 }
215 }
216 (Integral(a), Integral(b)) => {
217 use std::cmp::Ordering::*;
218 match op.node {
219 hir::BiAdd => Integral(math!(e, a + b)),
220 hir::BiSub => Integral(math!(e, a - b)),
221 hir::BiMul => Integral(math!(e, a * b)),
222 hir::BiDiv => Integral(math!(e, a / b)),
223 hir::BiRem => Integral(math!(e, a % b)),
224 hir::BiBitAnd => Integral(math!(e, a & b)),
225 hir::BiBitOr => Integral(math!(e, a | b)),
226 hir::BiBitXor => Integral(math!(e, a ^ b)),
227 hir::BiShl => Integral(math!(e, a << b)),
228 hir::BiShr => Integral(math!(e, a >> b)),
229 hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
230 hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
231 hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
232 hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
233 hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
234 hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
235 _ => span_bug!(e.span, "typeck error"),
236 }
237 }
238 (Bool(a), Bool(b)) => {
239 Bool(match op.node {
240 hir::BiAnd => a && b,
241 hir::BiOr => a || b,
242 hir::BiBitXor => a ^ b,
243 hir::BiBitAnd => a & b,
244 hir::BiBitOr => a | b,
245 hir::BiEq => a == b,
246 hir::BiNe => a != b,
247 hir::BiLt => a < b,
248 hir::BiLe => a <= b,
249 hir::BiGe => a >= b,
250 hir::BiGt => a > b,
251 _ => span_bug!(e.span, "typeck error"),
252 })
253 }
254 (Char(a), Char(b)) => {
255 Bool(match op.node {
256 hir::BiEq => a == b,
257 hir::BiNe => a != b,
258 hir::BiLt => a < b,
259 hir::BiLe => a <= b,
260 hir::BiGe => a >= b,
261 hir::BiGt => a > b,
262 _ => span_bug!(e.span, "typeck error"),
263 })
264 }
265
266 _ => signal!(e, MiscBinaryOp),
267 }
268 }
269 hir::ExprCast(ref base, _) => {
270 let base_val = cx.eval(base)?;
271 let base_ty = cx.tables.expr_ty(base);
272
273 // Avoid applying substitutions if they're empty, that'd ICE.
274 let base_ty = if cx.substs.is_empty() {
275 base_ty
276 } else {
277 base_ty.subst(tcx, cx.substs)
278 };
279 if ety == base_ty {
280 base_val
281 } else {
282 match cast_const(tcx, base_val, ety) {
283 Ok(val) => val,
284 Err(kind) => signal!(e, kind),
285 }
286 }
287 }
288 hir::ExprPath(ref qpath) => {
289 let substs = cx.tables.node_substs(e.id);
290
291 // Avoid applying substitutions if they're empty, that'd ICE.
292 let substs = if cx.substs.is_empty() {
293 substs
294 } else {
295 substs.subst(tcx, cx.substs)
296 };
297
298 match cx.tables.qpath_def(qpath, e.id) {
299 Def::Const(def_id) |
300 Def::AssociatedConst(def_id) => {
301 match tcx.at(e.span).const_eval((def_id, substs)) {
302 Ok(val) => val,
303 Err(ConstEvalErr { kind: TypeckError, .. }) => {
304 signal!(e, TypeckError);
305 }
306 Err(err) => {
307 debug!("bad reference: {:?}, {:?}", err.description(), err.span);
308 signal!(e, ErroneousReferencedConstant(box err))
309 },
310 }
311 },
312 Def::VariantCtor(variant_def, CtorKind::Const) => {
313 Variant(variant_def)
314 }
315 Def::VariantCtor(_, CtorKind::Fn) => {
316 signal!(e, UnimplementedConstVal("enum variants"));
317 }
318 Def::StructCtor(_, CtorKind::Const) => {
319 ConstVal::Struct(Default::default())
320 }
321 Def::StructCtor(_, CtorKind::Fn) => {
322 signal!(e, UnimplementedConstVal("tuple struct constructors"))
323 }
324 Def::Local(def_id) => {
325 debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args);
326 if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) {
327 val.clone()
328 } else {
329 signal!(e, NonConstPath);
330 }
331 },
332 Def::Method(id) | Def::Fn(id) => Function(id, substs),
333 Def::Err => span_bug!(e.span, "typeck error"),
334 _ => signal!(e, NonConstPath),
335 }
336 }
337 hir::ExprCall(ref callee, ref args) => {
338 let (def_id, substs) = match cx.eval(callee)? {
339 Function(def_id, substs) => (def_id, substs),
340 _ => signal!(e, TypeckError),
341 };
342
343 let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
344 if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
345 if fn_like.constness() == hir::Constness::Const {
346 tcx.hir.body(fn_like.body())
347 } else {
348 signal!(e, TypeckError)
349 }
350 } else {
351 signal!(e, TypeckError)
352 }
353 } else {
354 if tcx.is_const_fn(def_id) {
355 tcx.sess.cstore.item_body(tcx, def_id)
356 } else {
357 signal!(e, TypeckError)
358 }
359 };
360
361 let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
362 hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
363 _ => None
364 }).collect::<Vec<_>>();
365 assert_eq!(arg_defs.len(), args.len());
366
367 let mut call_args = DefIdMap();
368 for (arg, arg_expr) in arg_defs.into_iter().zip(args.iter()) {
369 let arg_val = cx.eval(arg_expr)?;
370 debug!("const call arg: {:?}", arg);
371 if let Some(def_id) = arg {
372 assert!(call_args.insert(def_id, arg_val).is_none());
373 }
374 }
375 debug!("const call({:?})", call_args);
376 let callee_cx = ConstContext {
377 tcx: tcx,
378 tables: tcx.typeck_tables_of(def_id),
379 substs: substs,
380 fn_args: Some(call_args)
381 };
382 callee_cx.eval(&body.value)?
383 },
384 hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
385 Ok(val) => val,
386 Err(err) => signal!(e, err),
387 },
388 hir::ExprBlock(ref block) => {
389 match block.expr {
390 Some(ref expr) => cx.eval(expr)?,
391 None => Tuple(vec![]),
392 }
393 }
394 hir::ExprType(ref e, _) => cx.eval(e)?,
395 hir::ExprTup(ref fields) => {
396 Tuple(fields.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
397 }
398 hir::ExprStruct(_, ref fields, _) => {
399 Struct(fields.iter().map(|f| {
400 cx.eval(&f.expr).map(|v| (f.name.node, v))
401 }).collect::<Result<_, _>>()?)
402 }
403 hir::ExprIndex(ref arr, ref idx) => {
404 if !tcx.sess.features.borrow().const_indexing {
405 signal!(e, IndexOpFeatureGated);
406 }
407 let arr = cx.eval(arr)?;
408 let idx = match cx.eval(idx)? {
409 Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
410 _ => signal!(idx, IndexNotUsize),
411 };
412 assert_eq!(idx as usize as u64, idx);
413 match arr {
414 Array(ref v) => {
415 if let Some(elem) = v.get(idx as usize) {
416 elem.clone()
417 } else {
418 let n = v.len() as u64;
419 assert_eq!(n as usize as u64, n);
420 signal!(e, IndexOutOfBounds { len: n, index: idx })
421 }
422 }
423
424 Repeat(.., n) if idx >= n => {
425 signal!(e, IndexOutOfBounds { len: n, index: idx })
426 }
427 Repeat(ref elem, _) => (**elem).clone(),
428
429 ByteStr(ref data) if idx >= data.len() as u64 => {
430 signal!(e, IndexOutOfBounds { len: data.len() as u64, index: idx })
431 }
432 ByteStr(data) => {
433 Integral(U8(data[idx as usize]))
434 },
435
436 _ => signal!(e, IndexedNonVec),
437 }
438 }
439 hir::ExprArray(ref v) => {
440 Array(v.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
441 }
442 hir::ExprRepeat(ref elem, _) => {
443 let n = match ety.sty {
444 ty::TyArray(_, n) => n as u64,
445 _ => span_bug!(e.span, "typeck error")
446 };
447 Repeat(Box::new(cx.eval(elem)?), n)
448 },
449 hir::ExprTupField(ref base, index) => {
450 let c = cx.eval(base)?;
451 if let Tuple(ref fields) = c {
452 fields[index.node].clone()
453 } else {
454 signal!(base, ExpectedConstTuple);
455 }
456 }
457 hir::ExprField(ref base, field_name) => {
458 let c = cx.eval(base)?;
459 if let Struct(ref fields) = c {
460 if let Some(f) = fields.get(&field_name.node) {
461 f.clone()
462 } else {
463 signal!(e, MissingStructField);
464 }
465 } else {
466 signal!(base, ExpectedConstStruct);
467 }
468 }
469 hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),
470 _ => signal!(e, MiscCatchAll)
471 };
472
473 Ok(result)
474 }
475
476 fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
477 def_id: DefId,
478 substs: &'tcx Substs<'tcx>)
479 -> Option<(DefId, &'tcx Substs<'tcx>)> {
480 let trait_item = tcx.associated_item(def_id);
481 let trait_id = trait_item.container.id();
482 let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs));
483 debug!("resolve_trait_associated_const: trait_ref={:?}",
484 trait_ref);
485
486 tcx.infer_ctxt().enter(|infcx| {
487 let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
488 let mut selcx = traits::SelectionContext::new(&infcx);
489 let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
490 param_env,
491 trait_ref.to_poly_trait_predicate());
492 let selection = match selcx.select(&obligation) {
493 Ok(Some(vtable)) => vtable,
494 // Still ambiguous, so give up and let the caller decide whether this
495 // expression is really needed yet. Some associated constant values
496 // can't be evaluated until monomorphization is done in trans.
497 Ok(None) => {
498 return None
499 }
500 Err(_) => {
501 return None
502 }
503 };
504
505 // NOTE: this code does not currently account for specialization, but when
506 // it does so, it should hook into the Reveal to determine when the
507 // constant should resolve; this will also require plumbing through to this
508 // function whether we are in "trans mode" to pick the right Reveal
509 // when constructing the inference context above.
510 match selection {
511 traits::VtableImpl(ref impl_data) => {
512 let name = trait_item.name;
513 let ac = tcx.associated_items(impl_data.impl_def_id)
514 .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
515 match ac {
516 // FIXME(eddyb) Use proper Instance resolution to
517 // get the correct Substs returned from here.
518 Some(ic) => Some((ic.def_id, Substs::empty())),
519 None => {
520 if trait_item.defaultness.has_value() {
521 Some((def_id, substs))
522 } else {
523 None
524 }
525 }
526 }
527 }
528 _ => {
529 bug!("resolve_trait_associated_const: unexpected vtable type")
530 }
531 }
532 })
533 }
534
535 fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
536 val: ConstInt,
537 ty: Ty<'tcx>)
538 -> CastResult<'tcx> {
539 let v = val.to_u128_unchecked();
540 match ty.sty {
541 ty::TyBool if v == 0 => Ok(Bool(false)),
542 ty::TyBool if v == 1 => Ok(Bool(true)),
543 ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i128 as i8))),
544 ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i128 as i16))),
545 ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i128 as i32))),
546 ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))),
547 ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))),
548 ty::TyInt(ast::IntTy::Is) => {
549 Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.int_type))))
550 },
551 ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
552 ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
553 ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
554 ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
555 ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))),
556 ty::TyUint(ast::UintTy::Us) => {
557 Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
558 },
559 ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(val.to_f64()))),
560 ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(val.to_f32()))),
561 ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
562 ty::TyChar => match val {
563 U8(u) => Ok(Char(u as char)),
564 _ => bug!(),
565 },
566 _ => Err(CannotCast),
567 }
568 }
569
570 fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
571 val: ConstFloat,
572 ty: Ty<'tcx>) -> CastResult<'tcx> {
573 match ty.sty {
574 ty::TyInt(_) | ty::TyUint(_) => {
575 let i = match val {
576 F32(f) if f >= 0.0 => U128(f as u128),
577 F64(f) if f >= 0.0 => U128(f as u128),
578
579 F32(f) => I128(f as i128),
580 F64(f) => I128(f as i128)
581 };
582
583 if let (I128(_), &ty::TyUint(_)) = (i, &ty.sty) {
584 return Err(CannotCast);
585 }
586
587 cast_const_int(tcx, i, ty)
588 }
589 ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val {
590 F32(f) => f as f64,
591 F64(f) => f
592 }))),
593 ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val {
594 F64(f) => f as f32,
595 F32(f) => f
596 }))),
597 _ => Err(CannotCast),
598 }
599 }
600
601 fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
602 val: ConstVal<'tcx>,
603 ty: Ty<'tcx>)
604 -> CastResult<'tcx> {
605 match val {
606 Integral(i) => cast_const_int(tcx, i, ty),
607 Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
608 Float(f) => cast_const_float(tcx, f, ty),
609 Char(c) => cast_const_int(tcx, U32(c as u32), ty),
610 Variant(v) => {
611 let adt = tcx.adt_def(tcx.parent_def_id(v).unwrap());
612 let idx = adt.variant_index_with_id(v);
613 cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty)
614 }
615 Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
616 ByteStr(b) => match ty.sty {
617 ty::TyRawPtr(_) => {
618 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
619 },
620 ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
621 ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)),
622 ty::TySlice(_) => {
623 Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
624 },
625 _ => Err(CannotCast),
626 },
627 _ => Err(CannotCast),
628 },
629 Str(s) => match ty.sty {
630 ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
631 ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
632 ty::TyStr => Ok(Str(s)),
633 _ => Err(CannotCast),
634 },
635 _ => Err(CannotCast),
636 },
637 _ => Err(CannotCast),
638 }
639 }
640
641 fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
642 tcx: TyCtxt<'a, 'tcx, 'tcx>,
643 mut ty: Ty<'tcx>)
644 -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
645 use syntax::ast::*;
646 use syntax::ast::LitIntType::*;
647
648 if let ty::TyAdt(adt, _) = ty.sty {
649 if adt.is_enum() {
650 ty = adt.repr.discr_type().to_ty(tcx)
651 }
652 }
653
654 match *lit {
655 LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
656 LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
657 LitKind::Byte(n) => Ok(Integral(U8(n))),
658 LitKind::Int(n, hint) => {
659 match (&ty.sty, hint) {
660 (&ty::TyInt(ity), _) |
661 (_, Signed(ity)) => {
662 Ok(Integral(ConstInt::new_signed_truncating(n as i128,
663 ity, tcx.sess.target.int_type)))
664 }
665 (&ty::TyUint(uty), _) |
666 (_, Unsigned(uty)) => {
667 Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
668 uty, tcx.sess.target.uint_type)))
669 }
670 _ => bug!()
671 }
672 }
673 LitKind::Float(n, fty) => {
674 parse_float(&n.as_str(), fty).map(Float)
675 }
676 LitKind::FloatUnsuffixed(n) => {
677 let fty = match ty.sty {
678 ty::TyFloat(fty) => fty,
679 _ => bug!()
680 };
681 parse_float(&n.as_str(), fty).map(Float)
682 }
683 LitKind::Bool(b) => Ok(Bool(b)),
684 LitKind::Char(c) => Ok(Char(c)),
685 }
686 }
687
688 fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
689 -> Result<ConstFloat, ErrKind<'tcx>> {
690 let val = match fty {
691 ast::FloatTy::F32 => num.parse::<f32>().map(F32),
692 ast::FloatTy::F64 => num.parse::<f64>().map(F64)
693 };
694 val.map_err(|_| {
695 // FIXME(#31407) this is only necessary because float parsing is buggy
696 UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
697 })
698 }
699
700 pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
701 -> Result<Ordering, ErrorReported>
702 {
703 let result = match (a, b) {
704 (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
705 (&Float(a), &Float(b)) => a.try_cmp(b).ok(),
706 (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
707 (&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
708 (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
709 (&Char(a), &Char(ref b)) => Some(a.cmp(b)),
710 _ => None,
711 };
712
713 match result {
714 Some(result) => Ok(result),
715 None => {
716 // FIXME: can this ever be reached?
717 span_err!(tcx.sess, span, E0298,
718 "type mismatch comparing {} and {}",
719 a.description(),
720 b.description());
721 Err(ErrorReported)
722 }
723 }
724 }
725
726 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
727 pub fn compare_lit_exprs(&self,
728 span: Span,
729 a: &Expr,
730 b: &Expr) -> Result<Ordering, ErrorReported> {
731 let tcx = self.tcx;
732 let a = match self.eval(a) {
733 Ok(a) => a,
734 Err(e) => {
735 e.report(tcx, a.span, "expression");
736 return Err(ErrorReported);
737 }
738 };
739 let b = match self.eval(b) {
740 Ok(b) => b,
741 Err(e) => {
742 e.report(tcx, b.span, "expression");
743 return Err(ErrorReported);
744 }
745 };
746 compare_const_vals(tcx, span, &a, &b)
747 }
748 }
749
750 pub fn provide(providers: &mut Providers) {
751 *providers = Providers {
752 const_eval,
753 ..*providers
754 };
755 }
756
757 fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
758 (def_id, substs): (DefId, &'tcx Substs<'tcx>))
759 -> EvalResult<'tcx> {
760 let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, def_id, substs) {
761 resolved
762 } else {
763 return Err(ConstEvalErr {
764 span: tcx.def_span(def_id),
765 kind: TypeckError
766 });
767 };
768
769 let cx = ConstContext {
770 tcx,
771 tables: tcx.typeck_tables_of(def_id),
772 substs: substs,
773 fn_args: None
774 };
775
776 let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
777 tcx.mir_const_qualif(def_id);
778 tcx.hir.body(tcx.hir.body_owned_by(id))
779 } else {
780 tcx.sess.cstore.item_body(tcx, def_id)
781 };
782 cx.eval(&body.value)
783 }