]>
Commit | Line | Data |
---|---|---|
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 | 13 | use self::ConstVal::*; |
c34b1796 | 14 | use self::ErrKind::*; |
c1a9b12d | 15 | use self::EvalHint::*; |
c34b1796 | 16 | |
e9174d1e SL |
17 | use front::map as ast_map; |
18 | use front::map::blocks::FnLikeNode; | |
92a42be0 | 19 | use middle::cstore::{self, CrateStore, InlinedItem}; |
7453a54e SL |
20 | use middle::{infer, subst, traits}; |
21 | use middle::def::Def; | |
9cc50fc6 | 22 | use middle::subst::Subst; |
b039eaaf | 23 | use middle::def_id::DefId; |
1a4d82fc | 24 | use middle::pat_util::def_to_path; |
85aaf69f | 25 | use middle::ty::{self, Ty}; |
c34b1796 | 26 | use middle::astconv_util::ast_ty_to_prim_ty; |
9346a6ac | 27 | use util::num::ToPrimitive; |
b039eaaf | 28 | use util::nodemap::NodeMap; |
7453a54e | 29 | use session::Session; |
223e47cc | 30 | |
9cc50fc6 | 31 | use graphviz::IntoCow; |
7453a54e SL |
32 | use syntax::ast; |
33 | use rustc_front::hir::{Expr, PatKind}; | |
e9174d1e | 34 | use rustc_front::hir; |
92a42be0 | 35 | use rustc_front::intravisit::FnKind; |
85aaf69f | 36 | use syntax::codemap::Span; |
1a4d82fc JJ |
37 | use syntax::parse::token::InternedString; |
38 | use syntax::ptr::P; | |
e9174d1e | 39 | use syntax::codemap; |
223e47cc | 40 | |
9cc50fc6 | 41 | use std::borrow::Cow; |
85aaf69f | 42 | use std::cmp::Ordering; |
1a4d82fc | 43 | use std::collections::hash_map::Entry::Vacant; |
92a42be0 | 44 | use std::hash; |
b039eaaf | 45 | use std::mem::transmute; |
62682a34 | 46 | use std::{i8, i16, i32, i64, u8, u16, u32, u64}; |
1a4d82fc | 47 | use std::rc::Rc; |
223e47cc | 48 | |
1a4d82fc | 49 | fn 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 | 87 | pub 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 | 192 | fn 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 | 215 | pub 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 |
249 | pub 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 | ||
263 | impl hash::Hash for ConstVal { | |
264 | fn hash<H: hash::Hasher>(&self, state: &mut H) { | |
265 | match *self { | |
266 | Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state), | |
267 | Int(a) => a.hash(state), | |
268 | Uint(a) => a.hash(state), | |
269 | Str(ref a) => a.hash(state), | |
270 | ByteStr(ref a) => a.hash(state), | |
271 | Bool(a) => a.hash(state), | |
272 | Struct(a) => a.hash(state), | |
273 | Tuple(a) => a.hash(state), | |
274 | Function(a) => a.hash(state), | |
275 | Array(a, n) => { a.hash(state); n.hash(state) }, | |
276 | Repeat(a, n) => { a.hash(state); n.hash(state) }, | |
277 | } | |
278 | } | |
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). | |
285 | impl PartialEq for ConstVal { | |
286 | fn eq(&self, other: &ConstVal) -> bool { | |
287 | match (self, other) { | |
288 | (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}, | |
289 | (&Int(a), &Int(b)) => a == b, | |
290 | (&Uint(a), &Uint(b)) => a == b, | |
291 | (&Str(ref a), &Str(ref b)) => a == b, | |
292 | (&ByteStr(ref a), &ByteStr(ref b)) => a == b, | |
293 | (&Bool(a), &Bool(b)) => a == b, | |
294 | (&Struct(a), &Struct(b)) => a == b, | |
295 | (&Tuple(a), &Tuple(b)) => a == b, | |
296 | (&Function(a), &Function(b)) => a == b, | |
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 |
304 | impl Eq for ConstVal { } |
305 | ||
c1a9b12d SL |
306 | impl ConstVal { |
307 | pub fn description(&self) -> &'static str { | |
308 | match *self { | |
309 | Float(_) => "float", | |
310 | Int(i) if i < 0 => "negative integer", | |
311 | Int(_) => "positive integer", | |
312 | Uint(_) => "unsigned integer", | |
313 | Str(_) => "string literal", | |
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 | 325 | pub 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 | 385 | pub 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 | 392 | pub type FnArgMap<'a> = Option<&'a NodeMap<ConstVal>>; |
c34b1796 AL |
393 | |
394 | #[derive(Clone)] | |
395 | pub struct ConstEvalErr { | |
396 | pub span: Span, | |
397 | pub kind: ErrKind, | |
398 | } | |
399 | ||
400 | #[derive(Clone)] | |
401 | pub enum ErrKind { | |
402 | CannotCast, | |
403 | CannotCastTo(&'static str), | |
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 | ||
447 | impl ConstEvalErr { | |
448 | pub fn description(&self) -> Cow<str> { | |
449 | use self::ErrKind::*; | |
450 | ||
451 | match self.kind { | |
452 | CannotCast => "can't cast this type".into_cow(), | |
453 | CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(), | |
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 |
499 | pub type EvalResult = Result<ConstVal, ConstEvalErr>; |
500 | pub 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)] | |
510 | pub enum EvalHint<'tcx> { | |
511 | /// We have a type-checked expression. | |
512 | ExprTypeChecked, | |
513 | /// We have an expression which hasn't been type-checked, but we have | |
514 | /// an idea of what the type will be because of the context. For example, | |
515 | /// the length of an array is always `usize`. (This is referred to as | |
516 | /// a hint because it isn't guaranteed to be consistent with what | |
517 | /// type-checking would compute.) | |
518 | UncheckedExprHint(Ty<'tcx>), | |
519 | /// We have an expression which has not yet been type-checked, and | |
520 | /// and we have no clue what the type will be. | |
521 | UncheckedExprNoHint, | |
522 | } | |
523 | ||
92a42be0 SL |
524 | impl<'tcx> EvalHint<'tcx> { |
525 | fn erase_hint(&self) -> EvalHint<'tcx> { | |
526 | match *self { | |
527 | ExprTypeChecked => ExprTypeChecked, | |
528 | UncheckedExprHint(_) | UncheckedExprNoHint => UncheckedExprNoHint, | |
529 | } | |
530 | } | |
531 | fn checked_or(&self, ty: Ty<'tcx>) -> EvalHint<'tcx> { | |
532 | match *self { | |
533 | ExprTypeChecked => ExprTypeChecked, | |
534 | _ => UncheckedExprHint(ty), | |
535 | } | |
536 | } | |
537 | } | |
538 | ||
c34b1796 AL |
539 | #[derive(Copy, Clone, PartialEq, Debug)] |
540 | pub enum IntTy { I8, I16, I32, I64 } | |
541 | #[derive(Copy, Clone, PartialEq, Debug)] | |
542 | pub enum UintTy { U8, U16, U32, U64 } | |
543 | ||
544 | impl IntTy { | |
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 | ||
561 | impl 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 | ||
578 | macro_rules! signal { | |
579 | ($e:expr, $exn:expr) => { | |
580 | return Err(ConstEvalErr { span: $e.span, kind: $exn }) | |
581 | } | |
582 | } | |
583 | ||
584 | // The const_{int,uint}_checked_{neg,add,sub,mul,div,shl,shr} family | |
585 | // of functions catch and signal overflow errors during constant | |
586 | // evaluation. | |
587 | // | |
588 | // They all take the operator's arguments (`a` and `b` if binary), the | |
589 | // overall expression (`e`) and, if available, whole expression's | |
590 | // concrete type (`opt_ety`). | |
591 | // | |
592 | // If the whole expression's concrete type is None, then this is a | |
593 | // constant evaluation happening before type check (e.g. in the check | |
594 | // to confirm that a pattern range's left-side is not greater than its | |
595 | // right-side). We do not do arithmetic modulo the type's bitwidth in | |
596 | // such a case; we just do 64-bit arithmetic and assume that later | |
597 | // passes will do it again with the type information, and thus do the | |
598 | // overflow checks then. | |
599 | ||
600 | pub fn const_int_checked_neg<'a>( | |
601 | a: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult { | |
602 | ||
603 | let (min,max) = match opt_ety { | |
604 | // (-i8::MIN is itself not an i8, etc, but this is an easy way | |
605 | // to allow literals to pass the check. Of course that does | |
606 | // not work for i64::MIN.) | |
607 | Some(IntTy::I8) => (-(i8::MAX as i64), -(i8::MIN as i64)), | |
608 | Some(IntTy::I16) => (-(i16::MAX as i64), -(i16::MIN as i64)), | |
609 | Some(IntTy::I32) => (-(i32::MAX as i64), -(i32::MIN as i64)), | |
610 | None | Some(IntTy::I64) => (-i64::MAX, -(i64::MIN+1)), | |
611 | }; | |
612 | ||
613 | let oflo = a < min || a > max; | |
614 | if oflo { | |
615 | signal!(e, NegateWithOverflow(a)); | |
616 | } else { | |
62682a34 | 617 | Ok(Int(-a)) |
c34b1796 AL |
618 | } |
619 | } | |
620 | ||
621 | pub fn const_uint_checked_neg<'a>( | |
622 | a: u64, _e: &'a Expr, _opt_ety: Option<UintTy>) -> EvalResult { | |
623 | // This always succeeds, and by definition, returns `(!a)+1`. | |
62682a34 SL |
624 | Ok(Uint((!a).wrapping_add(1))) |
625 | } | |
626 | ||
627 | fn const_uint_not(a: u64, opt_ety: Option<UintTy>) -> ConstVal { | |
628 | let mask = match opt_ety { | |
629 | Some(UintTy::U8) => u8::MAX as u64, | |
630 | Some(UintTy::U16) => u16::MAX as u64, | |
631 | Some(UintTy::U32) => u32::MAX as u64, | |
632 | None | Some(UintTy::U64) => u64::MAX, | |
633 | }; | |
634 | Uint(!a & mask) | |
c34b1796 AL |
635 | } |
636 | ||
637 | macro_rules! overflow_checking_body { | |
638 | ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident, | |
639 | lhs: $to_8_lhs:ident $to_16_lhs:ident $to_32_lhs:ident, | |
640 | rhs: $to_8_rhs:ident $to_16_rhs:ident $to_32_rhs:ident $to_64_rhs:ident, | |
641 | $EnumTy:ident $T8: ident $T16: ident $T32: ident $T64: ident, | |
642 | $result_type: ident) => { { | |
643 | let (a,b,opt_ety) = ($a,$b,$ety); | |
644 | match opt_ety { | |
645 | Some($EnumTy::$T8) => match (a.$to_8_lhs(), b.$to_8_rhs()) { | |
646 | (Some(a), Some(b)) => { | |
647 | let (a, oflo) = a.$overflowing_op(b); | |
648 | (a as $result_type, oflo) | |
649 | } | |
650 | (None, _) | (_, None) => (0, true) | |
651 | }, | |
652 | Some($EnumTy::$T16) => match (a.$to_16_lhs(), b.$to_16_rhs()) { | |
653 | (Some(a), Some(b)) => { | |
654 | let (a, oflo) = a.$overflowing_op(b); | |
655 | (a as $result_type, oflo) | |
656 | } | |
657 | (None, _) | (_, None) => (0, true) | |
658 | }, | |
659 | Some($EnumTy::$T32) => match (a.$to_32_lhs(), b.$to_32_rhs()) { | |
660 | (Some(a), Some(b)) => { | |
661 | let (a, oflo) = a.$overflowing_op(b); | |
662 | (a as $result_type, oflo) | |
663 | } | |
664 | (None, _) | (_, None) => (0, true) | |
665 | }, | |
666 | None | Some($EnumTy::$T64) => match b.$to_64_rhs() { | |
667 | Some(b) => a.$overflowing_op(b), | |
668 | None => (0, true), | |
669 | } | |
670 | } | |
671 | } } | |
672 | } | |
673 | ||
674 | macro_rules! int_arith_body { | |
675 | ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => { | |
676 | overflow_checking_body!( | |
677 | $a, $b, $ety, $overflowing_op, | |
678 | lhs: to_i8 to_i16 to_i32, | |
679 | rhs: to_i8 to_i16 to_i32 to_i64, IntTy I8 I16 I32 I64, i64) | |
680 | } | |
681 | } | |
682 | ||
683 | macro_rules! uint_arith_body { | |
684 | ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => { | |
685 | overflow_checking_body!( | |
686 | $a, $b, $ety, $overflowing_op, | |
687 | lhs: to_u8 to_u16 to_u32, | |
688 | rhs: to_u8 to_u16 to_u32 to_u64, UintTy U8 U16 U32 U64, u64) | |
689 | } | |
690 | } | |
691 | ||
692 | macro_rules! int_shift_body { | |
693 | ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => { | |
694 | overflow_checking_body!( | |
695 | $a, $b, $ety, $overflowing_op, | |
696 | lhs: to_i8 to_i16 to_i32, | |
697 | rhs: to_u32 to_u32 to_u32 to_u32, IntTy I8 I16 I32 I64, i64) | |
698 | } | |
699 | } | |
700 | ||
701 | macro_rules! uint_shift_body { | |
702 | ($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => { | |
703 | overflow_checking_body!( | |
704 | $a, $b, $ety, $overflowing_op, | |
705 | lhs: to_u8 to_u16 to_u32, | |
706 | rhs: to_u32 to_u32 to_u32 to_u32, UintTy U8 U16 U32 U64, u64) | |
707 | } | |
708 | } | |
709 | ||
710 | macro_rules! pub_fn_checked_op { | |
711 | {$fn_name:ident ($a:ident : $a_ty:ty, $b:ident : $b_ty:ty,.. $WhichTy:ident) { | |
712 | $ret_oflo_body:ident $overflowing_op:ident | |
713 | $const_ty:ident $signal_exn:expr | |
714 | }} => { | |
715 | pub fn $fn_name<'a>($a: $a_ty, | |
716 | $b: $b_ty, | |
717 | e: &'a Expr, | |
718 | opt_ety: Option<$WhichTy>) -> EvalResult { | |
719 | let (ret, oflo) = $ret_oflo_body!($a, $b, opt_ety, $overflowing_op); | |
720 | if !oflo { Ok($const_ty(ret)) } else { signal!(e, $signal_exn) } | |
721 | } | |
223e47cc LB |
722 | } |
723 | } | |
724 | ||
c34b1796 | 725 | pub_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 | ||
729 | pub_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 | ||
733 | pub_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 | ||
737 | pub fn const_int_checked_div<'a>( | |
738 | a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult { | |
739 | if b == 0 { signal!(e, DivideByZero); } | |
740 | let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_div); | |
62682a34 | 741 | if !oflo { Ok(Int(ret)) } else { signal!(e, DivideWithOverflow) } |
c34b1796 AL |
742 | } |
743 | ||
744 | pub fn const_int_checked_rem<'a>( | |
745 | a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult { | |
746 | if b == 0 { signal!(e, ModuloByZero); } | |
747 | let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_rem); | |
62682a34 | 748 | if !oflo { Ok(Int(ret)) } else { signal!(e, ModuloWithOverflow) } |
c34b1796 AL |
749 | } |
750 | ||
751 | pub_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 | ||
755 | pub_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 | ||
759 | pub_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 | ||
763 | pub_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 | ||
767 | pub_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 | ||
771 | pub_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 | ||
775 | pub_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 | ||
779 | pub fn const_uint_checked_div<'a>( | |
780 | a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult { | |
781 | if b == 0 { signal!(e, DivideByZero); } | |
782 | let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_div); | |
62682a34 | 783 | if !oflo { Ok(Uint(ret)) } else { signal!(e, DivideWithOverflow) } |
c34b1796 AL |
784 | } |
785 | ||
786 | pub fn const_uint_checked_rem<'a>( | |
787 | a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult { | |
788 | if b == 0 { signal!(e, ModuloByZero); } | |
789 | let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_rem); | |
62682a34 | 790 | if !oflo { Ok(Uint(ret)) } else { signal!(e, ModuloWithOverflow) } |
c34b1796 AL |
791 | } |
792 | ||
793 | pub_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 | ||
797 | pub_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 | ||
801 | pub_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 | ||
805 | pub_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 |
813 | pub 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 |
1225 | fn impl_or_trait_container(tcx: &ty::ctxt, def_id: DefId) -> ty::ImplOrTraitItemContainer { |
1226 | // This is intended to be equivalent to tcx.impl_or_trait_item(def_id).container() | |
1227 | // for local def_id, but it can be called before tcx.impl_or_trait_items is complete. | |
1228 | if let Some(node_id) = tcx.map.as_local_node_id(def_id) { | |
1229 | if let Some(ast_map::NodeItem(item)) = tcx.map.find(tcx.map.get_parent_node(node_id)) { | |
1230 | let container_id = tcx.map.local_def_id(item.id); | |
1231 | match item.node { | |
1232 | hir::ItemImpl(..) => return ty::ImplContainer(container_id), | |
1233 | hir::ItemTrait(..) => return ty::TraitContainer(container_id), | |
1234 | _ => () | |
1235 | } | |
1236 | } | |
1237 | panic!("No impl or trait container for {:?}", def_id); | |
1238 | } | |
1239 | panic!("{:?} is not local", def_id); | |
1240 | } | |
1241 | ||
d9579d0f | 1242 | fn 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 | 1292 | fn 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 | 1338 | fn 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 | 1367 | pub 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 |
1388 | pub 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 | } |