]> git.proxmox.com Git - rustc.git/blame - src/librustc/middle/const_eval.rs
Imported Upstream version 1.8.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 19use middle::cstore::{self, CrateStore, InlinedItem};
7453a54e
SL
20use middle::{infer, subst, traits};
21use middle::def::Def;
9cc50fc6 22use middle::subst::Subst;
b039eaaf 23use middle::def_id::DefId;
1a4d82fc 24use middle::pat_util::def_to_path;
85aaf69f 25use middle::ty::{self, Ty};
c34b1796 26use middle::astconv_util::ast_ty_to_prim_ty;
9346a6ac 27use util::num::ToPrimitive;
b039eaaf 28use util::nodemap::NodeMap;
7453a54e 29use session::Session;
223e47cc 30
9cc50fc6 31use graphviz::IntoCow;
7453a54e
SL
32use syntax::ast;
33use rustc_front::hir::{Expr, PatKind};
e9174d1e 34use rustc_front::hir;
92a42be0 35use rustc_front::intravisit::FnKind;
85aaf69f 36use syntax::codemap::Span;
1a4d82fc
JJ
37use syntax::parse::token::InternedString;
38use syntax::ptr::P;
e9174d1e 39use syntax::codemap;
223e47cc 40
9cc50fc6 41use std::borrow::Cow;
85aaf69f 42use std::cmp::Ordering;
1a4d82fc 43use std::collections::hash_map::Entry::Vacant;
92a42be0 44use std::hash;
b039eaaf 45use std::mem::transmute;
62682a34 46use std::{i8, i16, i32, i64, u8, u16, u32, u64};
1a4d82fc 47use std::rc::Rc;
223e47cc 48
1a4d82fc 49fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt,
e9174d1e
SL
50 enum_def: DefId,
51 variant_def: DefId)
1a4d82fc 52 -> Option<&'a Expr> {
92a42be0 53 fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId)
1a4d82fc 54 -> Option<&'a Expr> {
85aaf69f 55 for variant in variants {
b039eaaf 56 if variant.node.data.id() == id {
1a4d82fc
JJ
57 return variant.node.disr_expr.as_ref().map(|e| &**e);
58 }
59 }
60 None
61 }
62
b039eaaf
SL
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) {
1a4d82fc
JJ
66 None => None,
67 Some(ast_map::NodeItem(it)) => match it.node {
e9174d1e 68 hir::ItemEnum(hir::EnumDef { ref variants }, _) => {
92a42be0 69 variant_expr(variants, variant_node_id)
223e47cc 70 }
1a4d82fc
JJ
71 _ => None
72 },
73 Some(_) => None
74 }
75 } else {
b039eaaf 76 None
1a4d82fc
JJ
77 }
78}
223e47cc 79
9cc50fc6
SL
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.
d9579d0f 87pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
e9174d1e 88 def_id: DefId,
9cc50fc6
SL
89 maybe_ref_id: Option<ast::NodeId>,
90 param_substs: Option<&'tcx subst::Substs<'tcx>>)
d9579d0f 91 -> Option<&'tcx Expr> {
b039eaaf
SL
92 if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
93 match tcx.map.find(node_id) {
1a4d82fc
JJ
94 None => None,
95 Some(ast_map::NodeItem(it)) => match it.node {
e9174d1e 96 hir::ItemConst(_, ref const_expr) => {
7453a54e 97 Some(&const_expr)
d9579d0f
AL
98 }
99 _ => None
100 },
101 Some(ast_map::NodeTraitItem(ti)) => match ti.node {
e9174d1e 102 hir::ConstTraitItem(_, _) => {
d9579d0f
AL
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) => {
c1a9b12d 109 let trait_id = tcx.trait_of_item(def_id)
d9579d0f 110 .unwrap();
9cc50fc6
SL
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 }
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) => {
7453a54e 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) => {
9cc50fc6
SL
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 }
d9579d0f 166 resolve_trait_associated_const(tcx, ti, trait_id,
62682a34 167 substs).map(|e| e.id)
d9579d0f
AL
168 }
169 None => None
170 }
171 }
172 _ => None
173 },
92a42be0
SL
174 cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref ii)) => match ii.node {
175 hir::ImplItemKind::Const(_, ref expr) => Some(expr.id),
d9579d0f
AL
176 _ => None
177 },
1a4d82fc
JJ
178 _ => None
179 };
d9579d0f
AL
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 }
1a4d82fc
JJ
188 expr_id.map(|id| tcx.map.expect_expr(id))
189 }
190}
223e47cc 191
e9174d1e 192fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: DefId)
62682a34
SL
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
92a42be0 200 if !tcx.sess.cstore.is_const_fn(def_id) {
62682a34
SL
201 tcx.extern_const_fns.borrow_mut().insert(def_id, ast::DUMMY_NODE_ID);
202 return None;
203 }
204
92a42be0
SL
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),
62682a34
SL
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
e9174d1e 215pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId)
62682a34
SL
216 -> Option<FnLikeNode<'tcx>>
217{
b039eaaf
SL
218 let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
219 node_id
220 } else {
62682a34
SL
221 if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
222 fn_id
223 } else {
224 return None;
225 }
62682a34
SL
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() {
e9174d1e 234 FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _) => {
62682a34
SL
235 Some(fn_like)
236 }
e9174d1e
SL
237 FnKind::Method(_, m, _) => {
238 if m.constness == hir::Constness::Const {
62682a34
SL
239 Some(fn_like)
240 } else {
241 None
242 }
243 }
244 _ => None
245 }
246}
247
9cc50fc6 248#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
62682a34
SL
249pub enum ConstVal {
250 Float(f64),
251 Int(i64),
252 Uint(u64),
253 Str(InternedString),
e9174d1e 254 ByteStr(Rc<Vec<u8>>),
62682a34 255 Bool(bool),
c34b1796 256 Struct(ast::NodeId),
62682a34 257 Tuple(ast::NodeId),
b039eaaf 258 Function(DefId),
92a42be0
SL
259 Array(ast::NodeId, u64),
260 Repeat(ast::NodeId, u64),
261}
262
263impl 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 }
b039eaaf
SL
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).
285impl 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,
92a42be0
SL
297 (&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
298 (&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
b039eaaf
SL
299 _ => false,
300 }
301 }
223e47cc
LB
302}
303
92a42be0
SL
304impl Eq for ConstVal { }
305
c1a9b12d
SL
306impl 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",
e9174d1e 314 ByteStr(_) => "byte string literal",
c1a9b12d
SL
315 Bool(_) => "boolean",
316 Struct(_) => "struct",
317 Tuple(_) => "tuple",
b039eaaf 318 Function(_) => "function definition",
92a42be0
SL
319 Array(..) => "array",
320 Repeat(..) => "repeat",
c1a9b12d
SL
321 }
322 }
323}
324
e9174d1e 325pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<hir::Pat> {
1a4d82fc 326 let pat = match expr.node {
e9174d1e 327 hir::ExprTup(ref exprs) =>
7453a54e 328 PatKind::Tup(exprs.iter().map(|expr| const_expr_to_pat(tcx, &expr, span)).collect()),
1a4d82fc 329
e9174d1e 330 hir::ExprCall(ref callee, ref args) => {
c34b1796 331 let def = *tcx.def_map.borrow().get(&callee.id).unwrap();
1a4d82fc
JJ
332 if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) {
333 entry.insert(def);
334 }
c34b1796 335 let path = match def.full_def() {
7453a54e
SL
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 {
9cc50fc6 339 id: expr.id,
7453a54e 340 node: PatKind::Lit(P(expr.clone())),
9cc50fc6
SL
341 span: span,
342 }),
1a4d82fc
JJ
343 _ => unreachable!()
344 };
7453a54e
SL
345 let pats = args.iter().map(|expr| const_expr_to_pat(tcx, &expr, span)).collect();
346 PatKind::TupleStruct(path, Some(pats))
1a4d82fc
JJ
347 }
348
e9174d1e 349 hir::ExprStruct(ref path, ref fields, None) => {
1a4d82fc
JJ
350 let field_pats = fields.iter().map(|field| codemap::Spanned {
351 span: codemap::DUMMY_SP,
e9174d1e 352 node: hir::FieldPat {
b039eaaf 353 name: field.name.node,
7453a54e 354 pat: const_expr_to_pat(tcx, &field.expr, span),
1a4d82fc
JJ
355 is_shorthand: false,
356 },
357 }).collect();
7453a54e 358 PatKind::Struct(path.clone(), field_pats, false)
1a4d82fc
JJ
359 }
360
e9174d1e 361 hir::ExprVec(ref exprs) => {
7453a54e
SL
362 let pats = exprs.iter().map(|expr| const_expr_to_pat(tcx, &expr, span)).collect();
363 PatKind::Vec(pats, None, hir::HirVec::new())
1a4d82fc
JJ
364 }
365
e9174d1e 366 hir::ExprPath(_, ref path) => {
c34b1796 367 let opt_def = tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def());
1a4d82fc 368 match opt_def {
7453a54e
SL
369 Some(Def::Struct(..)) | Some(Def::Variant(..)) =>
370 PatKind::Path(path.clone()),
371 Some(Def::Const(def_id)) |
372 Some(Def::AssociatedConst(def_id)) => {
9cc50fc6
SL
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!(),
1a4d82fc
JJ
377 }
378 }
379
7453a54e 380 _ => PatKind::Lit(P(expr.clone()))
1a4d82fc 381 };
e9174d1e 382 P(hir::Pat { id: expr.id, node: pat, span: span })
1a4d82fc
JJ
383}
384
62682a34 385pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> ConstVal {
b039eaaf 386 match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
970d7e83 387 Ok(r) => r,
c34b1796
AL
388 Err(s) => tcx.sess.span_fatal(s.span, &s.description())
389 }
390}
391
b039eaaf 392pub type FnArgMap<'a> = Option<&'a NodeMap<ConstVal>>;
c34b1796
AL
393
394#[derive(Clone)]
395pub struct ConstEvalErr {
396 pub span: Span,
397 pub kind: ErrKind,
398}
399
400#[derive(Clone)]
401pub enum ErrKind {
402 CannotCast,
403 CannotCastTo(&'static str),
92a42be0
SL
404 InvalidOpForInts(hir::BinOp_),
405 InvalidOpForUInts(hir::BinOp_),
e9174d1e
SL
406 InvalidOpForBools(hir::BinOp_),
407 InvalidOpForFloats(hir::BinOp_),
408 InvalidOpForIntUint(hir::BinOp_),
409 InvalidOpForUintInt(hir::BinOp_),
c1a9b12d
SL
410 NegateOn(ConstVal),
411 NotOn(ConstVal),
92a42be0 412 CallOn(ConstVal),
c34b1796
AL
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,
92a42be0 429 UnimplementedConstVal(&'static str),
b039eaaf 430 UnresolvedPath,
c34b1796
AL
431 ExpectedConstTuple,
432 ExpectedConstStruct,
433 TupleIndexOutOfBounds,
92a42be0
SL
434 IndexedNonVec,
435 IndexNegative,
436 IndexNotInt,
437 IndexOutOfBounds,
438 RepeatCountNotNatural,
439 RepeatCountNotInt,
c34b1796
AL
440
441 MiscBinaryOp,
442 MiscCatchAll,
92a42be0
SL
443
444 IndexOpFeatureGated,
c34b1796
AL
445}
446
447impl 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(),
92a42be0
SL
454 InvalidOpForInts(_) => "can't do this op on signed integrals".into_cow(),
455 InvalidOpForUInts(_) => "can't do this op on unsigned integrals".into_cow(),
c34b1796
AL
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(),
c1a9b12d
SL
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(),
92a42be0 462 CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(),
c34b1796
AL
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(),
b039eaaf 478 NonConstPath => "non-constant path in constant expression".into_cow(),
92a42be0
SL
479 UnimplementedConstVal(what) =>
480 format!("unimplemented constant expression: {}", what).into_cow(),
b039eaaf 481 UnresolvedPath => "unresolved path in constant expression".into_cow(),
c34b1796
AL
482 ExpectedConstTuple => "expected constant tuple".into_cow(),
483 ExpectedConstStruct => "expected constant struct".into_cow(),
484 TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
92a42be0
SL
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(),
c34b1796
AL
491
492 MiscBinaryOp => "bad operands for binary".into_cow(),
493 MiscCatchAll => "unsupported constant expr".into_cow(),
92a42be0 494 IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(),
c34b1796
AL
495 }
496 }
497}
498
62682a34
SL
499pub type EvalResult = Result<ConstVal, ConstEvalErr>;
500pub type CastResult = Result<ConstVal, ErrKind>;
c34b1796 501
c1a9b12d
SL
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)]
510pub 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
92a42be0
SL
524impl<'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
c34b1796
AL
539#[derive(Copy, Clone, PartialEq, Debug)]
540pub enum IntTy { I8, I16, I32, I64 }
541#[derive(Copy, Clone, PartialEq, Debug)]
542pub enum UintTy { U8, U16, U32, U64 }
543
544impl IntTy {
b039eaaf 545 pub fn from(tcx: &ty::ctxt, t: ast::IntTy) -> IntTy {
7453a54e 546 let t = if let ast::IntTy::Is = t {
c34b1796
AL
547 tcx.sess.target.int_type
548 } else {
549 t
550 };
551 match t {
7453a54e
SL
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,
c34b1796
AL
557 }
558 }
559}
560
561impl UintTy {
b039eaaf 562 pub fn from(tcx: &ty::ctxt, t: ast::UintTy) -> UintTy {
7453a54e 563 let t = if let ast::UintTy::Us = t {
c34b1796
AL
564 tcx.sess.target.uint_type
565 } else {
566 t
567 };
568 match t {
7453a54e
SL
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,
c34b1796
AL
574 }
575 }
576}
577
578macro_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
600pub 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 {
62682a34 617 Ok(Int(-a))
c34b1796
AL
618 }
619}
620
621pub 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`.
62682a34
SL
624 Ok(Uint((!a).wrapping_add(1)))
625}
626
627fn 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)
c34b1796
AL
635}
636
637macro_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
674macro_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
683macro_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
692macro_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
701macro_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
710macro_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 }
223e47cc
LB
722 }
723}
724
c34b1796 725pub_fn_checked_op!{ const_int_checked_add(a: i64, b: i64,.. IntTy) {
62682a34 726 int_arith_body overflowing_add Int AddiWithOverflow(a, b)
c34b1796
AL
727}}
728
729pub_fn_checked_op!{ const_int_checked_sub(a: i64, b: i64,.. IntTy) {
62682a34 730 int_arith_body overflowing_sub Int SubiWithOverflow(a, b)
c34b1796
AL
731}}
732
733pub_fn_checked_op!{ const_int_checked_mul(a: i64, b: i64,.. IntTy) {
62682a34 734 int_arith_body overflowing_mul Int MuliWithOverflow(a, b)
c34b1796
AL
735}}
736
737pub 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);
62682a34 741 if !oflo { Ok(Int(ret)) } else { signal!(e, DivideWithOverflow) }
c34b1796
AL
742}
743
744pub 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);
62682a34 748 if !oflo { Ok(Int(ret)) } else { signal!(e, ModuloWithOverflow) }
c34b1796
AL
749}
750
751pub_fn_checked_op!{ const_int_checked_shl(a: i64, b: i64,.. IntTy) {
62682a34 752 int_shift_body overflowing_shl Int ShiftLeftWithOverflow
c34b1796
AL
753}}
754
755pub_fn_checked_op!{ const_int_checked_shl_via_uint(a: i64, b: u64,.. IntTy) {
62682a34 756 int_shift_body overflowing_shl Int ShiftLeftWithOverflow
c34b1796
AL
757}}
758
759pub_fn_checked_op!{ const_int_checked_shr(a: i64, b: i64,.. IntTy) {
62682a34 760 int_shift_body overflowing_shr Int ShiftRightWithOverflow
c34b1796
AL
761}}
762
763pub_fn_checked_op!{ const_int_checked_shr_via_uint(a: i64, b: u64,.. IntTy) {
62682a34 764 int_shift_body overflowing_shr Int ShiftRightWithOverflow
c34b1796
AL
765}}
766
767pub_fn_checked_op!{ const_uint_checked_add(a: u64, b: u64,.. UintTy) {
62682a34 768 uint_arith_body overflowing_add Uint AdduWithOverflow(a, b)
c34b1796
AL
769}}
770
771pub_fn_checked_op!{ const_uint_checked_sub(a: u64, b: u64,.. UintTy) {
62682a34 772 uint_arith_body overflowing_sub Uint SubuWithOverflow(a, b)
c34b1796
AL
773}}
774
775pub_fn_checked_op!{ const_uint_checked_mul(a: u64, b: u64,.. UintTy) {
62682a34 776 uint_arith_body overflowing_mul Uint MuluWithOverflow(a, b)
c34b1796
AL
777}}
778
779pub 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);
62682a34 783 if !oflo { Ok(Uint(ret)) } else { signal!(e, DivideWithOverflow) }
c34b1796
AL
784}
785
786pub 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);
62682a34 790 if !oflo { Ok(Uint(ret)) } else { signal!(e, ModuloWithOverflow) }
c34b1796
AL
791}
792
793pub_fn_checked_op!{ const_uint_checked_shl(a: u64, b: u64,.. UintTy) {
62682a34 794 uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
c34b1796
AL
795}}
796
797pub_fn_checked_op!{ const_uint_checked_shl_via_int(a: u64, b: i64,.. UintTy) {
62682a34 798 uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
c34b1796
AL
799}}
800
801pub_fn_checked_op!{ const_uint_checked_shr(a: u64, b: u64,.. UintTy) {
62682a34 802 uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
c34b1796
AL
803}}
804
805pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
62682a34 806 uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
c34b1796
AL
807}}
808
c1a9b12d
SL
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.)
85aaf69f
SL
813pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
814 e: &Expr,
b039eaaf
SL
815 ty_hint: EvalHint<'tcx>,
816 fn_args: FnArgMap) -> EvalResult {
c1a9b12d
SL
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 };
85aaf69f 836
c34b1796
AL
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| {
62682a34 841 if let ty::TyInt(t) = ty.sty {
c34b1796
AL
842 Some(IntTy::from(tcx, t)) } else { None }
843 });
844 let expr_uint_type = ety.and_then(|ty| {
62682a34 845 if let ty::TyUint(t) = ty.sty {
c34b1796
AL
846 Some(UintTy::from(tcx, t)) } else { None }
847 });
848
849 let result = match e.node {
e9174d1e 850 hir::ExprUnary(hir::UnNeg, ref inner) => {
7453a54e 851 match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
62682a34
SL
852 Float(f) => Float(-f),
853 Int(n) => try!(const_int_checked_neg(n, e, expr_int_type)),
854 Uint(i) => {
c34b1796
AL
855 try!(const_uint_checked_neg(i, e, expr_uint_type))
856 }
c1a9b12d 857 const_val => signal!(e, NegateOn(const_val)),
223e47cc
LB
858 }
859 }
e9174d1e 860 hir::ExprUnary(hir::UnNot, ref inner) => {
7453a54e 861 match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
62682a34
SL
862 Int(i) => Int(!i),
863 Uint(i) => const_uint_not(i, expr_uint_type),
864 Bool(b) => Bool(!b),
c1a9b12d 865 const_val => signal!(e, NotOn(const_val)),
223e47cc
LB
866 }
867 }
e9174d1e 868 hir::ExprBinary(op, ref a, ref b) => {
85aaf69f 869 let b_ty = match op.node {
92a42be0 870 hir::BiShl | hir::BiShr => ty_hint.checked_or(tcx.types.usize),
c1a9b12d 871 _ => ty_hint
85aaf69f 872 };
7453a54e
SL
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))) {
62682a34 875 (Float(a), Float(b)) => {
85aaf69f 876 match op.node {
e9174d1e
SL
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),
92a42be0
SL
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)),
223e47cc
LB
889 }
890 }
62682a34 891 (Int(a), Int(b)) => {
85aaf69f 892 match op.node {
e9174d1e
SL
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)),
92a42be0
SL
898 hir::BiBitAnd => Int(a & b),
899 hir::BiBitOr => Int(a | b),
e9174d1e
SL
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)),
92a42be0
SL
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)),
223e47cc
LB
910 }
911 }
62682a34 912 (Uint(a), Uint(b)) => {
85aaf69f 913 match op.node {
e9174d1e
SL
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)),
92a42be0
SL
919 hir::BiBitAnd => Uint(a & b),
920 hir::BiBitOr => Uint(a | b),
e9174d1e
SL
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)),
92a42be0
SL
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)),
223e47cc
LB
931 }
932 }
933 // shifts can have any integral type as their rhs
62682a34 934 (Int(a), Uint(b)) => {
85aaf69f 935 match op.node {
e9174d1e
SL
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)),
c34b1796 938 _ => signal!(e, InvalidOpForIntUint(op.node)),
223e47cc
LB
939 }
940 }
62682a34 941 (Uint(a), Int(b)) => {
85aaf69f 942 match op.node {
e9174d1e
SL
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)),
c34b1796 945 _ => signal!(e, InvalidOpForUintInt(op.node)),
223e47cc
LB
946 }
947 }
62682a34
SL
948 (Bool(a), Bool(b)) => {
949 Bool(match op.node {
e9174d1e
SL
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,
c34b1796
AL
957 _ => signal!(e, InvalidOpForBools(op.node)),
958 })
223e47cc 959 }
c34b1796
AL
960
961 _ => signal!(e, MiscBinaryOp),
223e47cc
LB
962 }
963 }
e9174d1e 964 hir::ExprCast(ref base, ref target_ty) => {
7453a54e 965 let ety = ety.or_else(|| ast_ty_to_prim_ty(tcx, &target_ty))
1a4d82fc
JJ
966 .unwrap_or_else(|| {
967 tcx.sess.span_fatal(target_ty.span,
968 "target type not found for const cast")
969 });
c34b1796 970
c1a9b12d
SL
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
7453a54e 983 let val = try!(eval_const_expr_partial(tcx, &base, base_hint, fn_args));
c34b1796
AL
984 match cast_const(tcx, val, ety) {
985 Ok(val) => val,
986 Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
987 }
223e47cc 988 }
e9174d1e 989 hir::ExprPath(..) => {
b039eaaf
SL
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 };
85aaf69f 1004 let (const_expr, const_ty) = match opt_def {
7453a54e 1005 Some(Def::Const(def_id)) => {
b039eaaf
SL
1006 if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
1007 match tcx.map.find(node_id) {
85aaf69f 1008 Some(ast_map::NodeItem(it)) => match it.node {
e9174d1e 1009 hir::ItemConst(ref ty, ref expr) => {
85aaf69f
SL
1010 (Some(&**expr), Some(&**ty))
1011 }
1012 _ => (None, None)
1013 },
1014 _ => (None, None)
1015 }
1016 } else {
9cc50fc6 1017 (lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
d9579d0f
AL
1018 }
1019 }
7453a54e 1020 Some(Def::AssociatedConst(def_id)) => {
b039eaaf 1021 if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
7453a54e 1022 match impl_or_trait_container(tcx, def_id) {
b039eaaf 1023 ty::TraitContainer(trait_id) => match tcx.map.find(node_id) {
d9579d0f 1024 Some(ast_map::NodeTraitItem(ti)) => match ti.node {
e9174d1e 1025 hir::ConstTraitItem(ref ty, _) => {
c1a9b12d
SL
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 }
d9579d0f
AL
1036 }
1037 _ => (None, None)
1038 },
1039 _ => (None, None)
1040 },
b039eaaf 1041 ty::ImplContainer(_) => match tcx.map.find(node_id) {
d9579d0f 1042 Some(ast_map::NodeImplItem(ii)) => match ii.node {
92a42be0 1043 hir::ImplItemKind::Const(ref ty, ref expr) => {
d9579d0f
AL
1044 (Some(&**expr), Some(&**ty))
1045 }
1046 _ => (None, None)
1047 },
1048 _ => (None, None)
1049 },
1050 }
1051 } else {
9cc50fc6 1052 (lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
85aaf69f
SL
1053 }
1054 }
7453a54e 1055 Some(Def::Variant(enum_def, variant_def)) => {
85aaf69f
SL
1056 (lookup_variant_by_id(tcx, enum_def, variant_def), None)
1057 }
7453a54e 1058 Some(Def::Struct(..)) => {
c1a9b12d
SL
1059 return Ok(ConstVal::Struct(e.id))
1060 }
7453a54e
SL
1061 Some(Def::Local(_, id)) => {
1062 debug!("Def::Local({:?}): {:?}", id, fn_args);
b039eaaf
SL
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 },
7453a54e 1069 Some(Def::Method(id)) | Some(Def::Fn(id)) => return Ok(Function(id)),
85aaf69f
SL
1070 _ => (None, None)
1071 };
1072 let const_expr = match const_expr {
1073 Some(actual_e) => actual_e,
c34b1796 1074 None => signal!(e, NonConstPath)
85aaf69f 1075 };
c1a9b12d
SL
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 };
b039eaaf 1087 try!(eval_const_expr_partial(tcx, const_expr, item_hint, fn_args))
85aaf69f 1088 }
b039eaaf 1089 hir::ExprCall(ref callee, ref args) => {
92a42be0
SL
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));
7453a54e
SL
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");
b039eaaf 1102 assert_eq!(decl.inputs.len(), args.len());
b039eaaf
SL
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 }
b039eaaf 1116 debug!("const call({:?})", call_args);
7453a54e 1117 try!(eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args)))
b039eaaf 1118 },
7453a54e 1119 hir::ExprLit(ref lit) => lit_to_const(tcx.sess, e.span, &lit, ety),
e9174d1e 1120 hir::ExprBlock(ref block) => {
1a4d82fc 1121 match block.expr {
7453a54e 1122 Some(ref expr) => try!(eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)),
92a42be0 1123 None => unreachable!(),
1a4d82fc
JJ
1124 }
1125 }
7453a54e 1126 hir::ExprType(ref e, _) => try!(eval_const_expr_partial(tcx, &e, ty_hint, fn_args)),
e9174d1e
SL
1127 hir::ExprTup(_) => Tuple(e.id),
1128 hir::ExprStruct(..) => Struct(e.id),
92a42be0
SL
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),
c1a9b12d 1141 };
92a42be0
SL
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 {
7453a54e 1145 try!(eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args))
92a42be0
SL
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,
7453a54e 1153 &tcx.map.expect_expr(elem),
92a42be0
SL
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,
7453a54e 1173 match try!(eval_const_expr_partial(tcx, &n, len_hint, fn_args)) {
92a42be0
SL
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();
9cc50fc6
SL
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)
c34b1796 1188 } else {
9cc50fc6 1189 signal!(e, TupleIndexOutOfBounds);
c34b1796 1190 }
1a4d82fc 1191 } else {
9cc50fc6 1192 unreachable!()
1a4d82fc 1193 }
c34b1796 1194 } else {
9cc50fc6 1195 signal!(base, ExpectedConstTuple);
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
9cc50fc6
SL
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) {
7453a54e 1208 return eval_const_expr_partial(tcx, &f.expr, base_hint, fn_args)
c34b1796 1209 } else {
9cc50fc6 1210 signal!(e, MissingStructField);
c34b1796 1211 }
1a4d82fc 1212 } else {
9cc50fc6 1213 unreachable!()
1a4d82fc 1214 }
c34b1796 1215 } else {
9cc50fc6 1216 signal!(base, ExpectedConstStruct);
1a4d82fc 1217 }
1a4d82fc 1218 }
c34b1796
AL
1219 _ => signal!(e, MiscCatchAll)
1220 };
1221
1222 Ok(result)
223e47cc
LB
1223}
1224
7453a54e
SL
1225fn 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
d9579d0f 1242fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
e9174d1e
SL
1243 ti: &'tcx hir::TraitItem,
1244 trait_id: DefId,
62682a34 1245 rcvr_substs: subst::Substs<'tcx>)
d9579d0f
AL
1246 -> Option<&'tcx Expr>
1247{
7453a54e
SL
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);
d9579d0f 1253
c1a9b12d 1254 tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
7453a54e 1255 let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
d9579d0f 1256
c1a9b12d 1257 let mut selcx = traits::SelectionContext::new(&infcx);
d9579d0f
AL
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 }
9cc50fc6
SL
1268 Err(_) => {
1269 return None
d9579d0f
AL
1270 }
1271 };
1272
1273 match selection {
1274 traits::VtableImpl(ref impl_data) => {
c1a9b12d 1275 match tcx.associated_consts(impl_data.impl_def_id)
b039eaaf 1276 .iter().find(|ic| ic.name == ti.name) {
9cc50fc6 1277 Some(ic) => lookup_const_by_id(tcx, ic.def_id, None, None),
d9579d0f 1278 None => match ti.node {
e9174d1e 1279 hir::ConstTraitItem(_, Some(ref expr)) => Some(&*expr),
d9579d0f
AL
1280 _ => None,
1281 },
1282 }
1283 }
1284 _ => {
1285 tcx.sess.span_bug(
1286 ti.span,
92a42be0 1287 "resolve_trait_associated_const: unexpected vtable type")
d9579d0f
AL
1288 }
1289 }
1290}
1291
62682a34 1292fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: ConstVal, ty: Ty) -> CastResult {
c34b1796
AL
1293 macro_rules! convert_val {
1294 ($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
1295 match val {
62682a34
SL
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)),
c34b1796
AL
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) {
7453a54e
SL
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"),
c34b1796 1310
7453a54e
SL
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"),
c34b1796
AL
1314
1315 _ => {}
85aaf69f
SL
1316 }
1317
c34b1796 1318 match ty.sty {
7453a54e
SL
1319 ty::TyInt(ast::IntTy::Is) => unreachable!(),
1320 ty::TyUint(ast::UintTy::Us) => unreachable!(),
c34b1796 1321
7453a54e
SL
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),
c34b1796 1326
7453a54e
SL
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),
c34b1796 1331
7453a54e
SL
1332 ty::TyFloat(ast::FloatTy::F32) => convert_val!(f32, Float, f64),
1333 ty::TyFloat(ast::FloatTy::F64) => convert_val!(f64, Float, f64),
c34b1796 1334 _ => Err(ErrKind::CannotCast),
85aaf69f
SL
1335 }
1336}
1337
7453a54e 1338fn lit_to_const(sess: &Session, span: Span, lit: &ast::Lit, ty_hint: Option<Ty>) -> ConstVal {
223e47cc 1339 match lit.node {
7453a54e
SL
1340 ast::LitKind::Str(ref s, _) => Str((*s).clone()),
1341 ast::LitKind::ByteStr(ref data) => {
e9174d1e 1342 ByteStr(data.clone())
1a4d82fc 1343 }
7453a54e
SL
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) => {
85aaf69f 1348 match ty_hint.map(|ty| &ty.sty) {
62682a34
SL
1349 Some(&ty::TyUint(_)) => Uint(n),
1350 _ => Int(n as i64)
85aaf69f
SL
1351 }
1352 }
7453a54e
SL
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 }
1a4d82fc 1362 }
7453a54e 1363 ast::LitKind::Bool(b) => Bool(b)
223e47cc
LB
1364 }
1365}
1366
62682a34 1367pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
85aaf69f 1368 Some(match (a, b) {
62682a34
SL
1369 (&Int(a), &Int(b)) => a.cmp(&b),
1370 (&Uint(a), &Uint(b)) => a.cmp(&b),
1371 (&Float(a), &Float(b)) => {
85aaf69f
SL
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 }
62682a34
SL
1381 (&Str(ref a), &Str(ref b)) => a.cmp(b),
1382 (&Bool(a), &Bool(b)) => a.cmp(&b),
e9174d1e 1383 (&ByteStr(ref a), &ByteStr(ref b)) => a.cmp(b),
85aaf69f
SL
1384 _ => return None
1385 })
223e47cc
LB
1386}
1387
c1a9b12d
SL
1388pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
1389 a: &Expr,
1390 b: &Expr) -> Option<Ordering> {
b039eaaf 1391 let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) {
85aaf69f 1392 Ok(a) => a,
c34b1796
AL
1393 Err(e) => {
1394 tcx.sess.span_err(a.span, &e.description());
85aaf69f
SL
1395 return None;
1396 }
1397 };
b039eaaf 1398 let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) {
85aaf69f 1399 Ok(b) => b,
c34b1796
AL
1400 Err(e) => {
1401 tcx.sess.span_err(b.span, &e.description());
85aaf69f
SL
1402 return None;
1403 }
1404 };
1405 compare_const_vals(&a, &b)
223e47cc 1406}