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