]> git.proxmox.com Git - rustc.git/blob - src/librustc/middle/const_eval.rs
Imported Upstream version 1.8.0+dfsg1
[rustc.git] / src / librustc / middle / const_eval.rs
1 // Copyright 2012-2015 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 //#![allow(non_camel_case_types)]
12
13 use self::ConstVal::*;
14 use self::ErrKind::*;
15 use self::EvalHint::*;
16
17 use front::map as ast_map;
18 use front::map::blocks::FnLikeNode;
19 use middle::cstore::{self, CrateStore, InlinedItem};
20 use middle::{infer, subst, traits};
21 use middle::def::Def;
22 use middle::subst::Subst;
23 use middle::def_id::DefId;
24 use middle::pat_util::def_to_path;
25 use middle::ty::{self, Ty};
26 use middle::astconv_util::ast_ty_to_prim_ty;
27 use util::num::ToPrimitive;
28 use util::nodemap::NodeMap;
29 use session::Session;
30
31 use graphviz::IntoCow;
32 use syntax::ast;
33 use rustc_front::hir::{Expr, PatKind};
34 use rustc_front::hir;
35 use rustc_front::intravisit::FnKind;
36 use syntax::codemap::Span;
37 use syntax::parse::token::InternedString;
38 use syntax::ptr::P;
39 use syntax::codemap;
40
41 use std::borrow::Cow;
42 use std::cmp::Ordering;
43 use std::collections::hash_map::Entry::Vacant;
44 use std::hash;
45 use std::mem::transmute;
46 use std::{i8, i16, i32, i64, u8, u16, u32, u64};
47 use std::rc::Rc;
48
49 fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt,
50 enum_def: DefId,
51 variant_def: DefId)
52 -> Option<&'a Expr> {
53 fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId)
54 -> Option<&'a Expr> {
55 for variant in variants {
56 if variant.node.data.id() == id {
57 return variant.node.disr_expr.as_ref().map(|e| &**e);
58 }
59 }
60 None
61 }
62
63 if let Some(enum_node_id) = tcx.map.as_local_node_id(enum_def) {
64 let variant_node_id = tcx.map.as_local_node_id(variant_def).unwrap();
65 match tcx.map.find(enum_node_id) {
66 None => None,
67 Some(ast_map::NodeItem(it)) => match it.node {
68 hir::ItemEnum(hir::EnumDef { ref variants }, _) => {
69 variant_expr(variants, variant_node_id)
70 }
71 _ => None
72 },
73 Some(_) => None
74 }
75 } else {
76 None
77 }
78 }
79
80 /// * `def_id` is the id of the constant.
81 /// * `maybe_ref_id` is the id of the expr referencing the constant.
82 /// * `param_substs` is the monomorphization substitution for the expression.
83 ///
84 /// `maybe_ref_id` and `param_substs` are optional and are used for
85 /// finding substitutions in associated constants. This generally
86 /// happens in late/trans const evaluation.
87 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
88 def_id: DefId,
89 maybe_ref_id: Option<ast::NodeId>,
90 param_substs: Option<&'tcx subst::Substs<'tcx>>)
91 -> Option<&'tcx Expr> {
92 if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
93 match tcx.map.find(node_id) {
94 None => None,
95 Some(ast_map::NodeItem(it)) => match it.node {
96 hir::ItemConst(_, ref const_expr) => {
97 Some(&const_expr)
98 }
99 _ => None
100 },
101 Some(ast_map::NodeTraitItem(ti)) => match ti.node {
102 hir::ConstTraitItem(_, _) => {
103 match maybe_ref_id {
104 // If we have a trait item, and we know the expression
105 // that's the source of the obligation to resolve it,
106 // `resolve_trait_associated_const` will select an impl
107 // or the default.
108 Some(ref_id) => {
109 let trait_id = tcx.trait_of_item(def_id)
110 .unwrap();
111 let mut substs = tcx.node_id_item_substs(ref_id)
112 .substs;
113 if let Some(param_substs) = param_substs {
114 substs = substs.subst(tcx, param_substs);
115 }
116 resolve_trait_associated_const(tcx, ti, trait_id,
117 substs)
118 }
119 // Technically, without knowing anything about the
120 // expression that generates the obligation, we could
121 // still return the default if there is one. However,
122 // it's safer to return `None` than to return some value
123 // that may differ from what you would get from
124 // correctly selecting an impl.
125 None => None
126 }
127 }
128 _ => None
129 },
130 Some(ast_map::NodeImplItem(ii)) => match ii.node {
131 hir::ImplItemKind::Const(_, ref expr) => {
132 Some(&expr)
133 }
134 _ => None
135 },
136 Some(_) => None
137 }
138 } else {
139 match tcx.extern_const_statics.borrow().get(&def_id) {
140 Some(&ast::DUMMY_NODE_ID) => return None,
141 Some(&expr_id) => {
142 return Some(tcx.map.expect_expr(expr_id));
143 }
144 None => {}
145 }
146 let mut used_ref_id = false;
147 let expr_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
148 cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node {
149 hir::ItemConst(_, ref const_expr) => Some(const_expr.id),
150 _ => None
151 },
152 cstore::FoundAst::Found(&InlinedItem::TraitItem(trait_id, ref ti)) => match ti.node {
153 hir::ConstTraitItem(_, _) => {
154 used_ref_id = true;
155 match maybe_ref_id {
156 // As mentioned in the comments above for in-crate
157 // constants, we only try to find the expression for
158 // a trait-associated const if the caller gives us
159 // the expression that refers to it.
160 Some(ref_id) => {
161 let mut substs = tcx.node_id_item_substs(ref_id)
162 .substs;
163 if let Some(param_substs) = param_substs {
164 substs = substs.subst(tcx, param_substs);
165 }
166 resolve_trait_associated_const(tcx, ti, trait_id,
167 substs).map(|e| e.id)
168 }
169 None => None
170 }
171 }
172 _ => None
173 },
174 cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref ii)) => match ii.node {
175 hir::ImplItemKind::Const(_, ref expr) => Some(expr.id),
176 _ => None
177 },
178 _ => None
179 };
180 // If we used the reference expression, particularly to choose an impl
181 // of a trait-associated const, don't cache that, because the next
182 // lookup with the same def_id may yield a different result.
183 if !used_ref_id {
184 tcx.extern_const_statics
185 .borrow_mut().insert(def_id,
186 expr_id.unwrap_or(ast::DUMMY_NODE_ID));
187 }
188 expr_id.map(|id| tcx.map.expect_expr(id))
189 }
190 }
191
192 fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: DefId)
193 -> Option<ast::NodeId> {
194 match tcx.extern_const_fns.borrow().get(&def_id) {
195 Some(&ast::DUMMY_NODE_ID) => return None,
196 Some(&fn_id) => return Some(fn_id),
197 None => {}
198 }
199
200 if !tcx.sess.cstore.is_const_fn(def_id) {
201 tcx.extern_const_fns.borrow_mut().insert(def_id, ast::DUMMY_NODE_ID);
202 return None;
203 }
204
205 let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
206 cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => Some(item.id),
207 cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref item)) => Some(item.id),
208 _ => None
209 };
210 tcx.extern_const_fns.borrow_mut().insert(def_id,
211 fn_id.unwrap_or(ast::DUMMY_NODE_ID));
212 fn_id
213 }
214
215 pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId)
216 -> Option<FnLikeNode<'tcx>>
217 {
218 let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
219 node_id
220 } else {
221 if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
222 fn_id
223 } else {
224 return None;
225 }
226 };
227
228 let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) {
229 Some(fn_like) => fn_like,
230 None => return None
231 };
232
233 match fn_like.kind() {
234 FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _) => {
235 Some(fn_like)
236 }
237 FnKind::Method(_, m, _) => {
238 if m.constness == hir::Constness::Const {
239 Some(fn_like)
240 } else {
241 None
242 }
243 }
244 _ => None
245 }
246 }
247
248 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
249 pub enum ConstVal {
250 Float(f64),
251 Int(i64),
252 Uint(u64),
253 Str(InternedString),
254 ByteStr(Rc<Vec<u8>>),
255 Bool(bool),
256 Struct(ast::NodeId),
257 Tuple(ast::NodeId),
258 Function(DefId),
259 Array(ast::NodeId, u64),
260 Repeat(ast::NodeId, u64),
261 }
262
263 impl hash::Hash for ConstVal {
264 fn hash<H: hash::Hasher>(&self, state: &mut H) {
265 match *self {
266 Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
267 Int(a) => a.hash(state),
268 Uint(a) => a.hash(state),
269 Str(ref a) => a.hash(state),
270 ByteStr(ref a) => a.hash(state),
271 Bool(a) => a.hash(state),
272 Struct(a) => a.hash(state),
273 Tuple(a) => a.hash(state),
274 Function(a) => a.hash(state),
275 Array(a, n) => { a.hash(state); n.hash(state) },
276 Repeat(a, n) => { a.hash(state); n.hash(state) },
277 }
278 }
279 }
280
281 /// Note that equality for `ConstVal` means that the it is the same
282 /// constant, not that the rust values are equal. In particular, `NaN
283 /// == NaN` (at least if it's the same NaN; distinct encodings for NaN
284 /// are considering unequal).
285 impl PartialEq for ConstVal {
286 fn eq(&self, other: &ConstVal) -> bool {
287 match (self, other) {
288 (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
289 (&Int(a), &Int(b)) => a == b,
290 (&Uint(a), &Uint(b)) => a == b,
291 (&Str(ref a), &Str(ref b)) => a == b,
292 (&ByteStr(ref a), &ByteStr(ref b)) => a == b,
293 (&Bool(a), &Bool(b)) => a == b,
294 (&Struct(a), &Struct(b)) => a == b,
295 (&Tuple(a), &Tuple(b)) => a == b,
296 (&Function(a), &Function(b)) => a == b,
297 (&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
298 (&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
299 _ => false,
300 }
301 }
302 }
303
304 impl Eq for ConstVal { }
305
306 impl ConstVal {
307 pub fn description(&self) -> &'static str {
308 match *self {
309 Float(_) => "float",
310 Int(i) if i < 0 => "negative integer",
311 Int(_) => "positive integer",
312 Uint(_) => "unsigned integer",
313 Str(_) => "string literal",
314 ByteStr(_) => "byte string literal",
315 Bool(_) => "boolean",
316 Struct(_) => "struct",
317 Tuple(_) => "tuple",
318 Function(_) => "function definition",
319 Array(..) => "array",
320 Repeat(..) => "repeat",
321 }
322 }
323 }
324
325 pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<hir::Pat> {
326 let pat = match expr.node {
327 hir::ExprTup(ref exprs) =>
328 PatKind::Tup(exprs.iter().map(|expr| const_expr_to_pat(tcx, &expr, span)).collect()),
329
330 hir::ExprCall(ref callee, ref args) => {
331 let def = *tcx.def_map.borrow().get(&callee.id).unwrap();
332 if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) {
333 entry.insert(def);
334 }
335 let path = match def.full_def() {
336 Def::Struct(def_id) => def_to_path(tcx, def_id),
337 Def::Variant(_, variant_did) => def_to_path(tcx, variant_did),
338 Def::Fn(..) => return P(hir::Pat {
339 id: expr.id,
340 node: PatKind::Lit(P(expr.clone())),
341 span: span,
342 }),
343 _ => unreachable!()
344 };
345 let pats = args.iter().map(|expr| const_expr_to_pat(tcx, &expr, span)).collect();
346 PatKind::TupleStruct(path, Some(pats))
347 }
348
349 hir::ExprStruct(ref path, ref fields, None) => {
350 let field_pats = fields.iter().map(|field| codemap::Spanned {
351 span: codemap::DUMMY_SP,
352 node: hir::FieldPat {
353 name: field.name.node,
354 pat: const_expr_to_pat(tcx, &field.expr, span),
355 is_shorthand: false,
356 },
357 }).collect();
358 PatKind::Struct(path.clone(), field_pats, false)
359 }
360
361 hir::ExprVec(ref exprs) => {
362 let pats = exprs.iter().map(|expr| const_expr_to_pat(tcx, &expr, span)).collect();
363 PatKind::Vec(pats, None, hir::HirVec::new())
364 }
365
366 hir::ExprPath(_, ref path) => {
367 let opt_def = tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def());
368 match opt_def {
369 Some(Def::Struct(..)) | Some(Def::Variant(..)) =>
370 PatKind::Path(path.clone()),
371 Some(Def::Const(def_id)) |
372 Some(Def::AssociatedConst(def_id)) => {
373 let expr = lookup_const_by_id(tcx, def_id, Some(expr.id), None).unwrap();
374 return const_expr_to_pat(tcx, expr, span);
375 },
376 _ => unreachable!(),
377 }
378 }
379
380 _ => PatKind::Lit(P(expr.clone()))
381 };
382 P(hir::Pat { id: expr.id, node: pat, span: span })
383 }
384
385 pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> ConstVal {
386 match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
387 Ok(r) => r,
388 Err(s) => tcx.sess.span_fatal(s.span, &s.description())
389 }
390 }
391
392 pub type FnArgMap<'a> = Option<&'a NodeMap<ConstVal>>;
393
394 #[derive(Clone)]
395 pub struct ConstEvalErr {
396 pub span: Span,
397 pub kind: ErrKind,
398 }
399
400 #[derive(Clone)]
401 pub enum ErrKind {
402 CannotCast,
403 CannotCastTo(&'static str),
404 InvalidOpForInts(hir::BinOp_),
405 InvalidOpForUInts(hir::BinOp_),
406 InvalidOpForBools(hir::BinOp_),
407 InvalidOpForFloats(hir::BinOp_),
408 InvalidOpForIntUint(hir::BinOp_),
409 InvalidOpForUintInt(hir::BinOp_),
410 NegateOn(ConstVal),
411 NotOn(ConstVal),
412 CallOn(ConstVal),
413
414 NegateWithOverflow(i64),
415 AddiWithOverflow(i64, i64),
416 SubiWithOverflow(i64, i64),
417 MuliWithOverflow(i64, i64),
418 AdduWithOverflow(u64, u64),
419 SubuWithOverflow(u64, u64),
420 MuluWithOverflow(u64, u64),
421 DivideByZero,
422 DivideWithOverflow,
423 ModuloByZero,
424 ModuloWithOverflow,
425 ShiftLeftWithOverflow,
426 ShiftRightWithOverflow,
427 MissingStructField,
428 NonConstPath,
429 UnimplementedConstVal(&'static str),
430 UnresolvedPath,
431 ExpectedConstTuple,
432 ExpectedConstStruct,
433 TupleIndexOutOfBounds,
434 IndexedNonVec,
435 IndexNegative,
436 IndexNotInt,
437 IndexOutOfBounds,
438 RepeatCountNotNatural,
439 RepeatCountNotInt,
440
441 MiscBinaryOp,
442 MiscCatchAll,
443
444 IndexOpFeatureGated,
445 }
446
447 impl ConstEvalErr {
448 pub fn description(&self) -> Cow<str> {
449 use self::ErrKind::*;
450
451 match self.kind {
452 CannotCast => "can't cast this type".into_cow(),
453 CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(),
454 InvalidOpForInts(_) => "can't do this op on signed integrals".into_cow(),
455 InvalidOpForUInts(_) => "can't do this op on unsigned integrals".into_cow(),
456 InvalidOpForBools(_) => "can't do this op on bools".into_cow(),
457 InvalidOpForFloats(_) => "can't do this op on floats".into_cow(),
458 InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
459 InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
460 NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(),
461 NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(),
462 CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(),
463
464 NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
465 AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
466 SubiWithOverflow(..) => "attempted to sub with overflow".into_cow(),
467 MuliWithOverflow(..) => "attempted to mul with overflow".into_cow(),
468 AdduWithOverflow(..) => "attempted to add with overflow".into_cow(),
469 SubuWithOverflow(..) => "attempted to sub with overflow".into_cow(),
470 MuluWithOverflow(..) => "attempted to mul with overflow".into_cow(),
471 DivideByZero => "attempted to divide by zero".into_cow(),
472 DivideWithOverflow => "attempted to divide with overflow".into_cow(),
473 ModuloByZero => "attempted remainder with a divisor of zero".into_cow(),
474 ModuloWithOverflow => "attempted remainder with overflow".into_cow(),
475 ShiftLeftWithOverflow => "attempted left shift with overflow".into_cow(),
476 ShiftRightWithOverflow => "attempted right shift with overflow".into_cow(),
477 MissingStructField => "nonexistent struct field".into_cow(),
478 NonConstPath => "non-constant path in constant expression".into_cow(),
479 UnimplementedConstVal(what) =>
480 format!("unimplemented constant expression: {}", what).into_cow(),
481 UnresolvedPath => "unresolved path in constant expression".into_cow(),
482 ExpectedConstTuple => "expected constant tuple".into_cow(),
483 ExpectedConstStruct => "expected constant struct".into_cow(),
484 TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
485 IndexedNonVec => "indexing is only supported for arrays".into_cow(),
486 IndexNegative => "indices must be non-negative integers".into_cow(),
487 IndexNotInt => "indices must be integers".into_cow(),
488 IndexOutOfBounds => "array index out of bounds".into_cow(),
489 RepeatCountNotNatural => "repeat count must be a natural number".into_cow(),
490 RepeatCountNotInt => "repeat count must be integers".into_cow(),
491
492 MiscBinaryOp => "bad operands for binary".into_cow(),
493 MiscCatchAll => "unsupported constant expr".into_cow(),
494 IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(),
495 }
496 }
497 }
498
499 pub type EvalResult = Result<ConstVal, ConstEvalErr>;
500 pub type CastResult = Result<ConstVal, ErrKind>;
501
502 // FIXME: Long-term, this enum should go away: trying to evaluate
503 // an expression which hasn't been type-checked is a recipe for
504 // disaster. That said, it's not clear how to fix ast_ty_to_ty
505 // to avoid the ordering issue.
506
507 /// Hint to determine how to evaluate constant expressions which
508 /// might not be type-checked.
509 #[derive(Copy, Clone, Debug)]
510 pub enum EvalHint<'tcx> {
511 /// We have a type-checked expression.
512 ExprTypeChecked,
513 /// We have an expression which hasn't been type-checked, but we have
514 /// an idea of what the type will be because of the context. For example,
515 /// the length of an array is always `usize`. (This is referred to as
516 /// a hint because it isn't guaranteed to be consistent with what
517 /// type-checking would compute.)
518 UncheckedExprHint(Ty<'tcx>),
519 /// We have an expression which has not yet been type-checked, and
520 /// and we have no clue what the type will be.
521 UncheckedExprNoHint,
522 }
523
524 impl<'tcx> EvalHint<'tcx> {
525 fn erase_hint(&self) -> EvalHint<'tcx> {
526 match *self {
527 ExprTypeChecked => ExprTypeChecked,
528 UncheckedExprHint(_) | UncheckedExprNoHint => UncheckedExprNoHint,
529 }
530 }
531 fn checked_or(&self, ty: Ty<'tcx>) -> EvalHint<'tcx> {
532 match *self {
533 ExprTypeChecked => ExprTypeChecked,
534 _ => UncheckedExprHint(ty),
535 }
536 }
537 }
538
539 #[derive(Copy, Clone, PartialEq, Debug)]
540 pub enum IntTy { I8, I16, I32, I64 }
541 #[derive(Copy, Clone, PartialEq, Debug)]
542 pub enum UintTy { U8, U16, U32, U64 }
543
544 impl IntTy {
545 pub fn from(tcx: &ty::ctxt, t: ast::IntTy) -> IntTy {
546 let t = if let ast::IntTy::Is = t {
547 tcx.sess.target.int_type
548 } else {
549 t
550 };
551 match t {
552 ast::IntTy::Is => unreachable!(),
553 ast::IntTy::I8 => IntTy::I8,
554 ast::IntTy::I16 => IntTy::I16,
555 ast::IntTy::I32 => IntTy::I32,
556 ast::IntTy::I64 => IntTy::I64,
557 }
558 }
559 }
560
561 impl UintTy {
562 pub fn from(tcx: &ty::ctxt, t: ast::UintTy) -> UintTy {
563 let t = if let ast::UintTy::Us = t {
564 tcx.sess.target.uint_type
565 } else {
566 t
567 };
568 match t {
569 ast::UintTy::Us => unreachable!(),
570 ast::UintTy::U8 => UintTy::U8,
571 ast::UintTy::U16 => UintTy::U16,
572 ast::UintTy::U32 => UintTy::U32,
573 ast::UintTy::U64 => UintTy::U64,
574 }
575 }
576 }
577
578 macro_rules! signal {
579 ($e:expr, $exn:expr) => {
580 return Err(ConstEvalErr { span: $e.span, kind: $exn })
581 }
582 }
583
584 // The const_{int,uint}_checked_{neg,add,sub,mul,div,shl,shr} family
585 // of functions catch and signal overflow errors during constant
586 // evaluation.
587 //
588 // They all take the operator's arguments (`a` and `b` if binary), the
589 // overall expression (`e`) and, if available, whole expression's
590 // concrete type (`opt_ety`).
591 //
592 // If the whole expression's concrete type is None, then this is a
593 // constant evaluation happening before type check (e.g. in the check
594 // to confirm that a pattern range's left-side is not greater than its
595 // right-side). We do not do arithmetic modulo the type's bitwidth in
596 // such a case; we just do 64-bit arithmetic and assume that later
597 // passes will do it again with the type information, and thus do the
598 // overflow checks then.
599
600 pub fn const_int_checked_neg<'a>(
601 a: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
602
603 let (min,max) = match opt_ety {
604 // (-i8::MIN is itself not an i8, etc, but this is an easy way
605 // to allow literals to pass the check. Of course that does
606 // not work for i64::MIN.)
607 Some(IntTy::I8) => (-(i8::MAX as i64), -(i8::MIN as i64)),
608 Some(IntTy::I16) => (-(i16::MAX as i64), -(i16::MIN as i64)),
609 Some(IntTy::I32) => (-(i32::MAX as i64), -(i32::MIN as i64)),
610 None | Some(IntTy::I64) => (-i64::MAX, -(i64::MIN+1)),
611 };
612
613 let oflo = a < min || a > max;
614 if oflo {
615 signal!(e, NegateWithOverflow(a));
616 } else {
617 Ok(Int(-a))
618 }
619 }
620
621 pub fn const_uint_checked_neg<'a>(
622 a: u64, _e: &'a Expr, _opt_ety: Option<UintTy>) -> EvalResult {
623 // This always succeeds, and by definition, returns `(!a)+1`.
624 Ok(Uint((!a).wrapping_add(1)))
625 }
626
627 fn const_uint_not(a: u64, opt_ety: Option<UintTy>) -> ConstVal {
628 let mask = match opt_ety {
629 Some(UintTy::U8) => u8::MAX as u64,
630 Some(UintTy::U16) => u16::MAX as u64,
631 Some(UintTy::U32) => u32::MAX as u64,
632 None | Some(UintTy::U64) => u64::MAX,
633 };
634 Uint(!a & mask)
635 }
636
637 macro_rules! overflow_checking_body {
638 ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident,
639 lhs: $to_8_lhs:ident $to_16_lhs:ident $to_32_lhs:ident,
640 rhs: $to_8_rhs:ident $to_16_rhs:ident $to_32_rhs:ident $to_64_rhs:ident,
641 $EnumTy:ident $T8: ident $T16: ident $T32: ident $T64: ident,
642 $result_type: ident) => { {
643 let (a,b,opt_ety) = ($a,$b,$ety);
644 match opt_ety {
645 Some($EnumTy::$T8) => match (a.$to_8_lhs(), b.$to_8_rhs()) {
646 (Some(a), Some(b)) => {
647 let (a, oflo) = a.$overflowing_op(b);
648 (a as $result_type, oflo)
649 }
650 (None, _) | (_, None) => (0, true)
651 },
652 Some($EnumTy::$T16) => match (a.$to_16_lhs(), b.$to_16_rhs()) {
653 (Some(a), Some(b)) => {
654 let (a, oflo) = a.$overflowing_op(b);
655 (a as $result_type, oflo)
656 }
657 (None, _) | (_, None) => (0, true)
658 },
659 Some($EnumTy::$T32) => match (a.$to_32_lhs(), b.$to_32_rhs()) {
660 (Some(a), Some(b)) => {
661 let (a, oflo) = a.$overflowing_op(b);
662 (a as $result_type, oflo)
663 }
664 (None, _) | (_, None) => (0, true)
665 },
666 None | Some($EnumTy::$T64) => match b.$to_64_rhs() {
667 Some(b) => a.$overflowing_op(b),
668 None => (0, true),
669 }
670 }
671 } }
672 }
673
674 macro_rules! int_arith_body {
675 ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
676 overflow_checking_body!(
677 $a, $b, $ety, $overflowing_op,
678 lhs: to_i8 to_i16 to_i32,
679 rhs: to_i8 to_i16 to_i32 to_i64, IntTy I8 I16 I32 I64, i64)
680 }
681 }
682
683 macro_rules! uint_arith_body {
684 ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
685 overflow_checking_body!(
686 $a, $b, $ety, $overflowing_op,
687 lhs: to_u8 to_u16 to_u32,
688 rhs: to_u8 to_u16 to_u32 to_u64, UintTy U8 U16 U32 U64, u64)
689 }
690 }
691
692 macro_rules! int_shift_body {
693 ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
694 overflow_checking_body!(
695 $a, $b, $ety, $overflowing_op,
696 lhs: to_i8 to_i16 to_i32,
697 rhs: to_u32 to_u32 to_u32 to_u32, IntTy I8 I16 I32 I64, i64)
698 }
699 }
700
701 macro_rules! uint_shift_body {
702 ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
703 overflow_checking_body!(
704 $a, $b, $ety, $overflowing_op,
705 lhs: to_u8 to_u16 to_u32,
706 rhs: to_u32 to_u32 to_u32 to_u32, UintTy U8 U16 U32 U64, u64)
707 }
708 }
709
710 macro_rules! pub_fn_checked_op {
711 {$fn_name:ident ($a:ident : $a_ty:ty, $b:ident : $b_ty:ty,.. $WhichTy:ident) {
712 $ret_oflo_body:ident $overflowing_op:ident
713 $const_ty:ident $signal_exn:expr
714 }} => {
715 pub fn $fn_name<'a>($a: $a_ty,
716 $b: $b_ty,
717 e: &'a Expr,
718 opt_ety: Option<$WhichTy>) -> EvalResult {
719 let (ret, oflo) = $ret_oflo_body!($a, $b, opt_ety, $overflowing_op);
720 if !oflo { Ok($const_ty(ret)) } else { signal!(e, $signal_exn) }
721 }
722 }
723 }
724
725 pub_fn_checked_op!{ const_int_checked_add(a: i64, b: i64,.. IntTy) {
726 int_arith_body overflowing_add Int AddiWithOverflow(a, b)
727 }}
728
729 pub_fn_checked_op!{ const_int_checked_sub(a: i64, b: i64,.. IntTy) {
730 int_arith_body overflowing_sub Int SubiWithOverflow(a, b)
731 }}
732
733 pub_fn_checked_op!{ const_int_checked_mul(a: i64, b: i64,.. IntTy) {
734 int_arith_body overflowing_mul Int MuliWithOverflow(a, b)
735 }}
736
737 pub fn const_int_checked_div<'a>(
738 a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
739 if b == 0 { signal!(e, DivideByZero); }
740 let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_div);
741 if !oflo { Ok(Int(ret)) } else { signal!(e, DivideWithOverflow) }
742 }
743
744 pub fn const_int_checked_rem<'a>(
745 a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
746 if b == 0 { signal!(e, ModuloByZero); }
747 let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_rem);
748 if !oflo { Ok(Int(ret)) } else { signal!(e, ModuloWithOverflow) }
749 }
750
751 pub_fn_checked_op!{ const_int_checked_shl(a: i64, b: i64,.. IntTy) {
752 int_shift_body overflowing_shl Int ShiftLeftWithOverflow
753 }}
754
755 pub_fn_checked_op!{ const_int_checked_shl_via_uint(a: i64, b: u64,.. IntTy) {
756 int_shift_body overflowing_shl Int ShiftLeftWithOverflow
757 }}
758
759 pub_fn_checked_op!{ const_int_checked_shr(a: i64, b: i64,.. IntTy) {
760 int_shift_body overflowing_shr Int ShiftRightWithOverflow
761 }}
762
763 pub_fn_checked_op!{ const_int_checked_shr_via_uint(a: i64, b: u64,.. IntTy) {
764 int_shift_body overflowing_shr Int ShiftRightWithOverflow
765 }}
766
767 pub_fn_checked_op!{ const_uint_checked_add(a: u64, b: u64,.. UintTy) {
768 uint_arith_body overflowing_add Uint AdduWithOverflow(a, b)
769 }}
770
771 pub_fn_checked_op!{ const_uint_checked_sub(a: u64, b: u64,.. UintTy) {
772 uint_arith_body overflowing_sub Uint SubuWithOverflow(a, b)
773 }}
774
775 pub_fn_checked_op!{ const_uint_checked_mul(a: u64, b: u64,.. UintTy) {
776 uint_arith_body overflowing_mul Uint MuluWithOverflow(a, b)
777 }}
778
779 pub fn const_uint_checked_div<'a>(
780 a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
781 if b == 0 { signal!(e, DivideByZero); }
782 let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_div);
783 if !oflo { Ok(Uint(ret)) } else { signal!(e, DivideWithOverflow) }
784 }
785
786 pub fn const_uint_checked_rem<'a>(
787 a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
788 if b == 0 { signal!(e, ModuloByZero); }
789 let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_rem);
790 if !oflo { Ok(Uint(ret)) } else { signal!(e, ModuloWithOverflow) }
791 }
792
793 pub_fn_checked_op!{ const_uint_checked_shl(a: u64, b: u64,.. UintTy) {
794 uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
795 }}
796
797 pub_fn_checked_op!{ const_uint_checked_shl_via_int(a: u64, b: i64,.. UintTy) {
798 uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
799 }}
800
801 pub_fn_checked_op!{ const_uint_checked_shr(a: u64, b: u64,.. UintTy) {
802 uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
803 }}
804
805 pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
806 uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
807 }}
808
809 /// Evaluate a constant expression in a context where the expression isn't
810 /// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
811 /// but a few places need to evaluate constants during type-checking, like
812 /// computing the length of an array. (See also the FIXME above EvalHint.)
813 pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
814 e: &Expr,
815 ty_hint: EvalHint<'tcx>,
816 fn_args: FnArgMap) -> EvalResult {
817 // Try to compute the type of the expression based on the EvalHint.
818 // (See also the definition of EvalHint, and the FIXME above EvalHint.)
819 let ety = match ty_hint {
820 ExprTypeChecked => {
821 // After type-checking, expr_ty is guaranteed to succeed.
822 Some(tcx.expr_ty(e))
823 }
824 UncheckedExprHint(ty) => {
825 // Use the type hint; it's not guaranteed to be right, but it's
826 // usually good enough.
827 Some(ty)
828 }
829 UncheckedExprNoHint => {
830 // This expression might not be type-checked, and we have no hint.
831 // Try to query the context for a type anyway; we might get lucky
832 // (for example, if the expression was imported from another crate).
833 tcx.expr_ty_opt(e)
834 }
835 };
836
837 // If type of expression itself is int or uint, normalize in these
838 // bindings so that isize/usize is mapped to a type with an
839 // inherently known bitwidth.
840 let expr_int_type = ety.and_then(|ty| {
841 if let ty::TyInt(t) = ty.sty {
842 Some(IntTy::from(tcx, t)) } else { None }
843 });
844 let expr_uint_type = ety.and_then(|ty| {
845 if let ty::TyUint(t) = ty.sty {
846 Some(UintTy::from(tcx, t)) } else { None }
847 });
848
849 let result = match e.node {
850 hir::ExprUnary(hir::UnNeg, ref inner) => {
851 match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
852 Float(f) => Float(-f),
853 Int(n) => try!(const_int_checked_neg(n, e, expr_int_type)),
854 Uint(i) => {
855 try!(const_uint_checked_neg(i, e, expr_uint_type))
856 }
857 const_val => signal!(e, NegateOn(const_val)),
858 }
859 }
860 hir::ExprUnary(hir::UnNot, ref inner) => {
861 match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
862 Int(i) => Int(!i),
863 Uint(i) => const_uint_not(i, expr_uint_type),
864 Bool(b) => Bool(!b),
865 const_val => signal!(e, NotOn(const_val)),
866 }
867 }
868 hir::ExprBinary(op, ref a, ref b) => {
869 let b_ty = match op.node {
870 hir::BiShl | hir::BiShr => ty_hint.checked_or(tcx.types.usize),
871 _ => ty_hint
872 };
873 match (try!(eval_const_expr_partial(tcx, &a, ty_hint, fn_args)),
874 try!(eval_const_expr_partial(tcx, &b, b_ty, fn_args))) {
875 (Float(a), Float(b)) => {
876 match op.node {
877 hir::BiAdd => Float(a + b),
878 hir::BiSub => Float(a - b),
879 hir::BiMul => Float(a * b),
880 hir::BiDiv => Float(a / b),
881 hir::BiRem => Float(a % b),
882 hir::BiEq => Bool(a == b),
883 hir::BiLt => Bool(a < b),
884 hir::BiLe => Bool(a <= b),
885 hir::BiNe => Bool(a != b),
886 hir::BiGe => Bool(a >= b),
887 hir::BiGt => Bool(a > b),
888 _ => signal!(e, InvalidOpForFloats(op.node)),
889 }
890 }
891 (Int(a), Int(b)) => {
892 match op.node {
893 hir::BiAdd => try!(const_int_checked_add(a,b,e,expr_int_type)),
894 hir::BiSub => try!(const_int_checked_sub(a,b,e,expr_int_type)),
895 hir::BiMul => try!(const_int_checked_mul(a,b,e,expr_int_type)),
896 hir::BiDiv => try!(const_int_checked_div(a,b,e,expr_int_type)),
897 hir::BiRem => try!(const_int_checked_rem(a,b,e,expr_int_type)),
898 hir::BiBitAnd => Int(a & b),
899 hir::BiBitOr => Int(a | b),
900 hir::BiBitXor => Int(a ^ b),
901 hir::BiShl => try!(const_int_checked_shl(a,b,e,expr_int_type)),
902 hir::BiShr => try!(const_int_checked_shr(a,b,e,expr_int_type)),
903 hir::BiEq => Bool(a == b),
904 hir::BiLt => Bool(a < b),
905 hir::BiLe => Bool(a <= b),
906 hir::BiNe => Bool(a != b),
907 hir::BiGe => Bool(a >= b),
908 hir::BiGt => Bool(a > b),
909 _ => signal!(e, InvalidOpForInts(op.node)),
910 }
911 }
912 (Uint(a), Uint(b)) => {
913 match op.node {
914 hir::BiAdd => try!(const_uint_checked_add(a,b,e,expr_uint_type)),
915 hir::BiSub => try!(const_uint_checked_sub(a,b,e,expr_uint_type)),
916 hir::BiMul => try!(const_uint_checked_mul(a,b,e,expr_uint_type)),
917 hir::BiDiv => try!(const_uint_checked_div(a,b,e,expr_uint_type)),
918 hir::BiRem => try!(const_uint_checked_rem(a,b,e,expr_uint_type)),
919 hir::BiBitAnd => Uint(a & b),
920 hir::BiBitOr => Uint(a | b),
921 hir::BiBitXor => Uint(a ^ b),
922 hir::BiShl => try!(const_uint_checked_shl(a,b,e,expr_uint_type)),
923 hir::BiShr => try!(const_uint_checked_shr(a,b,e,expr_uint_type)),
924 hir::BiEq => Bool(a == b),
925 hir::BiLt => Bool(a < b),
926 hir::BiLe => Bool(a <= b),
927 hir::BiNe => Bool(a != b),
928 hir::BiGe => Bool(a >= b),
929 hir::BiGt => Bool(a > b),
930 _ => signal!(e, InvalidOpForUInts(op.node)),
931 }
932 }
933 // shifts can have any integral type as their rhs
934 (Int(a), Uint(b)) => {
935 match op.node {
936 hir::BiShl => try!(const_int_checked_shl_via_uint(a,b,e,expr_int_type)),
937 hir::BiShr => try!(const_int_checked_shr_via_uint(a,b,e,expr_int_type)),
938 _ => signal!(e, InvalidOpForIntUint(op.node)),
939 }
940 }
941 (Uint(a), Int(b)) => {
942 match op.node {
943 hir::BiShl => try!(const_uint_checked_shl_via_int(a,b,e,expr_uint_type)),
944 hir::BiShr => try!(const_uint_checked_shr_via_int(a,b,e,expr_uint_type)),
945 _ => signal!(e, InvalidOpForUintInt(op.node)),
946 }
947 }
948 (Bool(a), Bool(b)) => {
949 Bool(match op.node {
950 hir::BiAnd => a && b,
951 hir::BiOr => a || b,
952 hir::BiBitXor => a ^ b,
953 hir::BiBitAnd => a & b,
954 hir::BiBitOr => a | b,
955 hir::BiEq => a == b,
956 hir::BiNe => a != b,
957 _ => signal!(e, InvalidOpForBools(op.node)),
958 })
959 }
960
961 _ => signal!(e, MiscBinaryOp),
962 }
963 }
964 hir::ExprCast(ref base, ref target_ty) => {
965 let ety = ety.or_else(|| ast_ty_to_prim_ty(tcx, &target_ty))
966 .unwrap_or_else(|| {
967 tcx.sess.span_fatal(target_ty.span,
968 "target type not found for const cast")
969 });
970
971 let base_hint = if let ExprTypeChecked = ty_hint {
972 ExprTypeChecked
973 } else {
974 // FIXME (#23833): the type-hint can cause problems,
975 // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
976 // type to the sum, and thus no overflow is signaled.
977 match tcx.expr_ty_opt(&base) {
978 Some(t) => UncheckedExprHint(t),
979 None => ty_hint
980 }
981 };
982
983 let val = try!(eval_const_expr_partial(tcx, &base, base_hint, fn_args));
984 match cast_const(tcx, val, ety) {
985 Ok(val) => val,
986 Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
987 }
988 }
989 hir::ExprPath(..) => {
990 let opt_def = if let Some(def) = tcx.def_map.borrow().get(&e.id) {
991 // After type-checking, def_map contains definition of the
992 // item referred to by the path. During type-checking, it
993 // can contain the raw output of path resolution, which
994 // might be a partially resolved path.
995 // FIXME: There's probably a better way to make sure we don't
996 // panic here.
997 if def.depth != 0 {
998 signal!(e, UnresolvedPath);
999 }
1000 Some(def.full_def())
1001 } else {
1002 None
1003 };
1004 let (const_expr, const_ty) = match opt_def {
1005 Some(Def::Const(def_id)) => {
1006 if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
1007 match tcx.map.find(node_id) {
1008 Some(ast_map::NodeItem(it)) => match it.node {
1009 hir::ItemConst(ref ty, ref expr) => {
1010 (Some(&**expr), Some(&**ty))
1011 }
1012 _ => (None, None)
1013 },
1014 _ => (None, None)
1015 }
1016 } else {
1017 (lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
1018 }
1019 }
1020 Some(Def::AssociatedConst(def_id)) => {
1021 if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
1022 match impl_or_trait_container(tcx, def_id) {
1023 ty::TraitContainer(trait_id) => match tcx.map.find(node_id) {
1024 Some(ast_map::NodeTraitItem(ti)) => match ti.node {
1025 hir::ConstTraitItem(ref ty, _) => {
1026 if let ExprTypeChecked = ty_hint {
1027 let substs = tcx.node_id_item_substs(e.id).substs;
1028 (resolve_trait_associated_const(tcx,
1029 ti,
1030 trait_id,
1031 substs),
1032 Some(&**ty))
1033 } else {
1034 (None, None)
1035 }
1036 }
1037 _ => (None, None)
1038 },
1039 _ => (None, None)
1040 },
1041 ty::ImplContainer(_) => match tcx.map.find(node_id) {
1042 Some(ast_map::NodeImplItem(ii)) => match ii.node {
1043 hir::ImplItemKind::Const(ref ty, ref expr) => {
1044 (Some(&**expr), Some(&**ty))
1045 }
1046 _ => (None, None)
1047 },
1048 _ => (None, None)
1049 },
1050 }
1051 } else {
1052 (lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
1053 }
1054 }
1055 Some(Def::Variant(enum_def, variant_def)) => {
1056 (lookup_variant_by_id(tcx, enum_def, variant_def), None)
1057 }
1058 Some(Def::Struct(..)) => {
1059 return Ok(ConstVal::Struct(e.id))
1060 }
1061 Some(Def::Local(_, id)) => {
1062 debug!("Def::Local({:?}): {:?}", id, fn_args);
1063 if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
1064 return Ok(val.clone());
1065 } else {
1066 (None, None)
1067 }
1068 },
1069 Some(Def::Method(id)) | Some(Def::Fn(id)) => return Ok(Function(id)),
1070 _ => (None, None)
1071 };
1072 let const_expr = match const_expr {
1073 Some(actual_e) => actual_e,
1074 None => signal!(e, NonConstPath)
1075 };
1076 let item_hint = if let UncheckedExprNoHint = ty_hint {
1077 match const_ty {
1078 Some(ty) => match ast_ty_to_prim_ty(tcx, ty) {
1079 Some(ty) => UncheckedExprHint(ty),
1080 None => UncheckedExprNoHint
1081 },
1082 None => UncheckedExprNoHint
1083 }
1084 } else {
1085 ty_hint
1086 };
1087 try!(eval_const_expr_partial(tcx, const_expr, item_hint, fn_args))
1088 }
1089 hir::ExprCall(ref callee, ref args) => {
1090 let sub_ty_hint = ty_hint.erase_hint();
1091 let callee_val = try!(eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args));
1092 let did = match callee_val {
1093 Function(did) => did,
1094 callee => signal!(e, CallOn(callee)),
1095 };
1096 let (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) {
1097 (fn_like.decl(), &fn_like.body().expr)
1098 } else {
1099 signal!(e, NonConstPath)
1100 };
1101 let result = result.as_ref().expect("const fn has no result expression");
1102 assert_eq!(decl.inputs.len(), args.len());
1103
1104 let mut call_args = NodeMap();
1105 for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) {
1106 let arg_val = try!(eval_const_expr_partial(
1107 tcx,
1108 arg_expr,
1109 sub_ty_hint,
1110 fn_args
1111 ));
1112 debug!("const call arg: {:?}", arg);
1113 let old = call_args.insert(arg.pat.id, arg_val);
1114 assert!(old.is_none());
1115 }
1116 debug!("const call({:?})", call_args);
1117 try!(eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args)))
1118 },
1119 hir::ExprLit(ref lit) => lit_to_const(tcx.sess, e.span, &lit, ety),
1120 hir::ExprBlock(ref block) => {
1121 match block.expr {
1122 Some(ref expr) => try!(eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)),
1123 None => unreachable!(),
1124 }
1125 }
1126 hir::ExprType(ref e, _) => try!(eval_const_expr_partial(tcx, &e, ty_hint, fn_args)),
1127 hir::ExprTup(_) => Tuple(e.id),
1128 hir::ExprStruct(..) => Struct(e.id),
1129 hir::ExprIndex(ref arr, ref idx) => {
1130 if !tcx.sess.features.borrow().const_indexing {
1131 signal!(e, IndexOpFeatureGated);
1132 }
1133 let arr_hint = ty_hint.erase_hint();
1134 let arr = try!(eval_const_expr_partial(tcx, arr, arr_hint, fn_args));
1135 let idx_hint = ty_hint.checked_or(tcx.types.usize);
1136 let idx = match try!(eval_const_expr_partial(tcx, idx, idx_hint, fn_args)) {
1137 Int(i) if i >= 0 => i as u64,
1138 Int(_) => signal!(idx, IndexNegative),
1139 Uint(i) => i,
1140 _ => signal!(idx, IndexNotInt),
1141 };
1142 match arr {
1143 Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
1144 Array(v, _) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
1145 try!(eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args))
1146 } else {
1147 unreachable!()
1148 },
1149
1150 Repeat(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
1151 Repeat(elem, _) => try!(eval_const_expr_partial(
1152 tcx,
1153 &tcx.map.expect_expr(elem),
1154 ty_hint,
1155 fn_args,
1156 )),
1157
1158 ByteStr(ref data) if idx as usize >= data.len()
1159 => signal!(e, IndexOutOfBounds),
1160 ByteStr(data) => Uint(data[idx as usize] as u64),
1161
1162 Str(ref s) if idx as usize >= s.len()
1163 => signal!(e, IndexOutOfBounds),
1164 Str(_) => unimplemented!(), // there's no const_char type
1165 _ => signal!(e, IndexedNonVec),
1166 }
1167 }
1168 hir::ExprVec(ref v) => Array(e.id, v.len() as u64),
1169 hir::ExprRepeat(_, ref n) => {
1170 let len_hint = ty_hint.checked_or(tcx.types.usize);
1171 Repeat(
1172 e.id,
1173 match try!(eval_const_expr_partial(tcx, &n, len_hint, fn_args)) {
1174 Int(i) if i >= 0 => i as u64,
1175 Int(_) => signal!(e, RepeatCountNotNatural),
1176 Uint(i) => i,
1177 _ => signal!(e, RepeatCountNotInt),
1178 },
1179 )
1180 },
1181 hir::ExprTupField(ref base, index) => {
1182 let base_hint = ty_hint.erase_hint();
1183 let c = try!(eval_const_expr_partial(tcx, base, base_hint, fn_args));
1184 if let Tuple(tup_id) = c {
1185 if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
1186 if index.node < fields.len() {
1187 return eval_const_expr_partial(tcx, &fields[index.node], base_hint, fn_args)
1188 } else {
1189 signal!(e, TupleIndexOutOfBounds);
1190 }
1191 } else {
1192 unreachable!()
1193 }
1194 } else {
1195 signal!(base, ExpectedConstTuple);
1196 }
1197 }
1198 hir::ExprField(ref base, field_name) => {
1199 let base_hint = ty_hint.erase_hint();
1200 // Get the base expression if it is a struct and it is constant
1201 let c = try!(eval_const_expr_partial(tcx, base, base_hint, fn_args));
1202 if let Struct(struct_id) = c {
1203 if let hir::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
1204 // Check that the given field exists and evaluate it
1205 // if the idents are compared run-pass/issue-19244 fails
1206 if let Some(f) = fields.iter().find(|f| f.name.node
1207 == field_name.node) {
1208 return eval_const_expr_partial(tcx, &f.expr, base_hint, fn_args)
1209 } else {
1210 signal!(e, MissingStructField);
1211 }
1212 } else {
1213 unreachable!()
1214 }
1215 } else {
1216 signal!(base, ExpectedConstStruct);
1217 }
1218 }
1219 _ => signal!(e, MiscCatchAll)
1220 };
1221
1222 Ok(result)
1223 }
1224
1225 fn impl_or_trait_container(tcx: &ty::ctxt, def_id: DefId) -> ty::ImplOrTraitItemContainer {
1226 // This is intended to be equivalent to tcx.impl_or_trait_item(def_id).container()
1227 // for local def_id, but it can be called before tcx.impl_or_trait_items is complete.
1228 if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
1229 if let Some(ast_map::NodeItem(item)) = tcx.map.find(tcx.map.get_parent_node(node_id)) {
1230 let container_id = tcx.map.local_def_id(item.id);
1231 match item.node {
1232 hir::ItemImpl(..) => return ty::ImplContainer(container_id),
1233 hir::ItemTrait(..) => return ty::TraitContainer(container_id),
1234 _ => ()
1235 }
1236 }
1237 panic!("No impl or trait container for {:?}", def_id);
1238 }
1239 panic!("{:?} is not local", def_id);
1240 }
1241
1242 fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
1243 ti: &'tcx hir::TraitItem,
1244 trait_id: DefId,
1245 rcvr_substs: subst::Substs<'tcx>)
1246 -> Option<&'tcx Expr>
1247 {
1248 let trait_ref = ty::Binder(
1249 rcvr_substs.erase_regions().to_trait_ref(tcx, trait_id)
1250 );
1251 debug!("resolve_trait_associated_const: trait_ref={:?}",
1252 trait_ref);
1253
1254 tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
1255 let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
1256
1257 let mut selcx = traits::SelectionContext::new(&infcx);
1258 let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
1259 trait_ref.to_poly_trait_predicate());
1260 let selection = match selcx.select(&obligation) {
1261 Ok(Some(vtable)) => vtable,
1262 // Still ambiguous, so give up and let the caller decide whether this
1263 // expression is really needed yet. Some associated constant values
1264 // can't be evaluated until monomorphization is done in trans.
1265 Ok(None) => {
1266 return None
1267 }
1268 Err(_) => {
1269 return None
1270 }
1271 };
1272
1273 match selection {
1274 traits::VtableImpl(ref impl_data) => {
1275 match tcx.associated_consts(impl_data.impl_def_id)
1276 .iter().find(|ic| ic.name == ti.name) {
1277 Some(ic) => lookup_const_by_id(tcx, ic.def_id, None, None),
1278 None => match ti.node {
1279 hir::ConstTraitItem(_, Some(ref expr)) => Some(&*expr),
1280 _ => None,
1281 },
1282 }
1283 }
1284 _ => {
1285 tcx.sess.span_bug(
1286 ti.span,
1287 "resolve_trait_associated_const: unexpected vtable type")
1288 }
1289 }
1290 }
1291
1292 fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: ConstVal, ty: Ty) -> CastResult {
1293 macro_rules! convert_val {
1294 ($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
1295 match val {
1296 Bool(b) => Ok($const_type(b as u64 as $intermediate_ty as $target_ty)),
1297 Uint(u) => Ok($const_type(u as $intermediate_ty as $target_ty)),
1298 Int(i) => Ok($const_type(i as $intermediate_ty as $target_ty)),
1299 Float(f) => Ok($const_type(f as $intermediate_ty as $target_ty)),
1300 _ => Err(ErrKind::CannotCastTo(stringify!($const_type))),
1301 }
1302 }
1303 }
1304
1305 // Issue #23890: If isize/usize, then dispatch to appropriate target representation type
1306 match (&ty.sty, tcx.sess.target.int_type, tcx.sess.target.uint_type) {
1307 (&ty::TyInt(ast::IntTy::Is), ast::IntTy::I32, _) => return convert_val!(i32, Int, i64),
1308 (&ty::TyInt(ast::IntTy::Is), ast::IntTy::I64, _) => return convert_val!(i64, Int, i64),
1309 (&ty::TyInt(ast::IntTy::Is), _, _) => panic!("unexpected target.int_type"),
1310
1311 (&ty::TyUint(ast::UintTy::Us), _, ast::UintTy::U32) => return convert_val!(u32, Uint, u64),
1312 (&ty::TyUint(ast::UintTy::Us), _, ast::UintTy::U64) => return convert_val!(u64, Uint, u64),
1313 (&ty::TyUint(ast::UintTy::Us), _, _) => panic!("unexpected target.uint_type"),
1314
1315 _ => {}
1316 }
1317
1318 match ty.sty {
1319 ty::TyInt(ast::IntTy::Is) => unreachable!(),
1320 ty::TyUint(ast::UintTy::Us) => unreachable!(),
1321
1322 ty::TyInt(ast::IntTy::I8) => convert_val!(i8, Int, i64),
1323 ty::TyInt(ast::IntTy::I16) => convert_val!(i16, Int, i64),
1324 ty::TyInt(ast::IntTy::I32) => convert_val!(i32, Int, i64),
1325 ty::TyInt(ast::IntTy::I64) => convert_val!(i64, Int, i64),
1326
1327 ty::TyUint(ast::UintTy::U8) => convert_val!(u8, Uint, u64),
1328 ty::TyUint(ast::UintTy::U16) => convert_val!(u16, Uint, u64),
1329 ty::TyUint(ast::UintTy::U32) => convert_val!(u32, Uint, u64),
1330 ty::TyUint(ast::UintTy::U64) => convert_val!(u64, Uint, u64),
1331
1332 ty::TyFloat(ast::FloatTy::F32) => convert_val!(f32, Float, f64),
1333 ty::TyFloat(ast::FloatTy::F64) => convert_val!(f64, Float, f64),
1334 _ => Err(ErrKind::CannotCast),
1335 }
1336 }
1337
1338 fn lit_to_const(sess: &Session, span: Span, lit: &ast::Lit, ty_hint: Option<Ty>) -> ConstVal {
1339 match lit.node {
1340 ast::LitKind::Str(ref s, _) => Str((*s).clone()),
1341 ast::LitKind::ByteStr(ref data) => {
1342 ByteStr(data.clone())
1343 }
1344 ast::LitKind::Byte(n) => Uint(n as u64),
1345 ast::LitKind::Char(n) => Uint(n as u64),
1346 ast::LitKind::Int(n, ast::LitIntType::Signed(_)) => Int(n as i64),
1347 ast::LitKind::Int(n, ast::LitIntType::Unsuffixed) => {
1348 match ty_hint.map(|ty| &ty.sty) {
1349 Some(&ty::TyUint(_)) => Uint(n),
1350 _ => Int(n as i64)
1351 }
1352 }
1353 ast::LitKind::Int(n, ast::LitIntType::Unsigned(_)) => Uint(n),
1354 ast::LitKind::Float(ref n, _) |
1355 ast::LitKind::FloatUnsuffixed(ref n) => {
1356 if let Ok(x) = n.parse::<f64>() {
1357 Float(x)
1358 } else {
1359 // FIXME(#31407) this is only necessary because float parsing is buggy
1360 sess.span_bug(span, "could not evaluate float literal (see issue #31407)");
1361 }
1362 }
1363 ast::LitKind::Bool(b) => Bool(b)
1364 }
1365 }
1366
1367 pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
1368 Some(match (a, b) {
1369 (&Int(a), &Int(b)) => a.cmp(&b),
1370 (&Uint(a), &Uint(b)) => a.cmp(&b),
1371 (&Float(a), &Float(b)) => {
1372 // This is pretty bad but it is the existing behavior.
1373 if a == b {
1374 Ordering::Equal
1375 } else if a < b {
1376 Ordering::Less
1377 } else {
1378 Ordering::Greater
1379 }
1380 }
1381 (&Str(ref a), &Str(ref b)) => a.cmp(b),
1382 (&Bool(a), &Bool(b)) => a.cmp(&b),
1383 (&ByteStr(ref a), &ByteStr(ref b)) => a.cmp(b),
1384 _ => return None
1385 })
1386 }
1387
1388 pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
1389 a: &Expr,
1390 b: &Expr) -> Option<Ordering> {
1391 let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) {
1392 Ok(a) => a,
1393 Err(e) => {
1394 tcx.sess.span_err(a.span, &e.description());
1395 return None;
1396 }
1397 };
1398 let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) {
1399 Ok(b) => b,
1400 Err(e) => {
1401 tcx.sess.span_err(b.span, &e.description());
1402 return None;
1403 }
1404 };
1405 compare_const_vals(&a, &b)
1406 }