1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![allow(non_camel_case_types)]
12 #![allow(unsigned_negate)]
13
14 use metadata::csearch;
15 use middle::astencode;
16
17 use middle::ty;
18 use middle::typeck::astconv;
19 use util::nodemap::{DefIdMap};
20
21 use syntax::ast::*;
22 use syntax::parse::token::InternedString;
23 use syntax::visit::Visitor;
24 use syntax::visit;
25 use syntax::{ast, ast_map, ast_util};
26
27 use std::rc::Rc;
28
29 //
30 // This pass classifies expressions by their constant-ness.
31 //
32 // Constant-ness comes in 3 flavours:
33 //
34 // - Integer-constants: can be evaluated by the frontend all the way down
35 // to their actual value. They are used in a few places (enum
36 // discriminants, switch arms) and are a subset of
37 // general-constants. They cover all the integer and integer-ish
38 // literals (nil, bool, int, uint, char, iNN, uNN) and all integer
39 // operators and copies applied to them.
40 //
41 // - General-constants: can be evaluated by LLVM but not necessarily by
42 // the frontend; usually due to reliance on target-specific stuff such
43 // as "where in memory the value goes" or "what floating point mode the
44 // target uses". This _includes_ integer-constants, plus the following
45 // constructors:
46 //
47 // fixed-size vectors and strings: [] and ""/_
48 // vector and string slices: &[] and &""
49 // tuples: (,)
50 // records: {...}
51 // enums: foo(...)
52 // floating point literals and operators
53 // & and * pointers
54 // copies of general constants
55 //
56 // (in theory, probably not at first: if/match on integer-const
57 // conditions / descriminants)
58 //
59 // - Non-constants: everything else.
60 //
61
62 pub enum constness {
63 integral_const,
64 general_const,
65 non_const
66 }
67
68 type constness_cache = DefIdMap<constness>;
69
70 pub fn join(a: constness, b: constness) -> constness {
71 match (a, b) {
72 (integral_const, integral_const) => integral_const,
73 (integral_const, general_const)
74 | (general_const, integral_const)
75 | (general_const, general_const) => general_const,
76 _ => non_const
77 }
78 }
79
80 pub fn join_all<It: Iterator<constness>>(mut cs: It) -> constness {
81 cs.fold(integral_const, |a, b| join(a, b))
82 }
83
84 pub fn lookup_const(tcx: &ty::ctxt, e: &Expr) -> Option<@Expr> {
85 let opt_def = tcx.def_map.borrow().find_copy(&e.id);
86 match opt_def {
87 Some(ast::DefStatic(def_id, false)) => {
88 lookup_const_by_id(tcx, def_id)
89 }
90 Some(ast::DefVariant(enum_def, variant_def, _)) => {
91 lookup_variant_by_id(tcx, enum_def, variant_def)
92 }
93 _ => None
94 }
95 }
96
97 pub fn lookup_variant_by_id(tcx: &ty::ctxt,
98 enum_def: ast::DefId,
99 variant_def: ast::DefId)
100 -> Option<@Expr> {
101 fn variant_expr(variants: &[ast::P<ast::Variant>], id: ast::NodeId) -> Option<@Expr> {
102 for variant in variants.iter() {
103 if variant.node.id == id {
104 return variant.node.disr_expr;
105 }
106 }
107 None
108 }
109
110 if ast_util::is_local(enum_def) {
111 {
112 match tcx.map.find(enum_def.node) {
113 None => None,
114 Some(ast_map::NodeItem(it)) => match it.node {
115 ItemEnum(ast::EnumDef { variants: ref variants }, _) => {
116 variant_expr(variants.as_slice(), variant_def.node)
117 }
118 _ => None
119 },
120 Some(_) => None
121 }
122 }
123 } else {
124 match tcx.extern_const_variants.borrow().find(&variant_def) {
125 Some(&e) => return e,
126 None => {}
127 }
128 let e = match csearch::maybe_get_item_ast(tcx, enum_def,
129 |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
130 csearch::found(ast::IIItem(item)) => match item.node {
131 ItemEnum(ast::EnumDef { variants: ref variants }, _) => {
132 variant_expr(variants.as_slice(), variant_def.node)
133 }
134 _ => None
135 },
136 _ => None
137 };
138 tcx.extern_const_variants.borrow_mut().insert(variant_def, e);
139 return e;
140 }
141 }
142
143 pub fn lookup_const_by_id(tcx: &ty::ctxt, def_id: ast::DefId)
144 -> Option<@Expr> {
145 if ast_util::is_local(def_id) {
146 {
147 match tcx.map.find(def_id.node) {
148 None => None,
149 Some(ast_map::NodeItem(it)) => match it.node {
150 ItemStatic(_, ast::MutImmutable, const_expr) => {
151 Some(const_expr)
152 }
153 _ => None
154 },
155 Some(_) => None
156 }
157 }
158 } else {
159 match tcx.extern_const_statics.borrow().find(&def_id) {
160 Some(&e) => return e,
161 None => {}
162 }
163 let e = match csearch::maybe_get_item_ast(tcx, def_id,
164 |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
165 csearch::found(ast::IIItem(item)) => match item.node {
166 ItemStatic(_, ast::MutImmutable, const_expr) => Some(const_expr),
167 _ => None
168 },
169 _ => None
170 };
171 tcx.extern_const_statics.borrow_mut().insert(def_id, e);
172 return e;
173 }
174 }
175
176 struct ConstEvalVisitor<'a> {
177 tcx: &'a ty::ctxt,
178 ccache: constness_cache,
179 }
180
181 impl<'a> ConstEvalVisitor<'a> {
182 fn classify(&mut self, e: &Expr) -> constness {
183 let did = ast_util::local_def(e.id);
184 match self.ccache.find(&did) {
185 Some(&x) => return x,
186 None => {}
187 }
188 let cn = match e.node {
189 ast::ExprLit(lit) => {
190 match lit.node {
191 ast::LitStr(..) | ast::LitFloat(..) => general_const,
192 _ => integral_const
193 }
194 }
195
196 ast::ExprUnary(_, inner) | ast::ExprParen(inner) =>
197 self.classify(inner),
198
199 ast::ExprBinary(_, a, b) =>
200 join(self.classify(a), self.classify(b)),
201
202 ast::ExprTup(ref es) |
203 ast::ExprVec(ref es) =>
204 join_all(es.iter().map(|e| self.classify(*e))),
205
206 ast::ExprVstore(e, vstore) => {
207 match vstore {
208 ast::ExprVstoreSlice => self.classify(e),
209 ast::ExprVstoreUniq |
210 ast::ExprVstoreMutSlice => non_const
211 }
212 }
213
214 ast::ExprStruct(_, ref fs, None) => {
215 let cs = fs.iter().map(|f| self.classify(f.expr));
216 join_all(cs)
217 }
218
219 ast::ExprCast(base, _) => {
220 let ty = ty::expr_ty(self.tcx, e);
221 let base = self.classify(base);
222 if ty::type_is_integral(ty) {
223 join(integral_const, base)
224 } else if ty::type_is_fp(ty) {
225 join(general_const, base)
226 } else {
227 non_const
228 }
229 }
230
231 ast::ExprField(base, _, _) => self.classify(base),
232
233 ast::ExprIndex(base, idx) =>
234 join(self.classify(base), self.classify(idx)),
235
236 ast::ExprAddrOf(ast::MutImmutable, base) => self.classify(base),
237
238 // FIXME: (#3728) we can probably do something CCI-ish
239 // surrounding nonlocal constants. But we don't yet.
240 ast::ExprPath(_) => self.lookup_constness(e),
241
242 ast::ExprRepeat(..) => general_const,
243
244 _ => non_const
245 };
246 self.ccache.insert(did, cn);
247 cn
248 }
249
250 fn lookup_constness(&self, e: &Expr) -> constness {
251 match lookup_const(self.tcx, e) {
252 Some(rhs) => {
253 let ty = ty::expr_ty(self.tcx, rhs);
254 if ty::type_is_integral(ty) {
255 integral_const
256 } else {
257 general_const
258 }
259 }
260 None => non_const
261 }
262 }
263
264 }
265
266 impl<'a> Visitor<()> for ConstEvalVisitor<'a> {
267 fn visit_expr_post(&mut self, e: &Expr, _: ()) {
268 self.classify(e);
269 }
270 }
271
272 pub fn process_crate(krate: &ast::Crate,
273 tcx: &ty::ctxt) {
274 let mut v = ConstEvalVisitor {
275 tcx: tcx,
276 ccache: DefIdMap::new(),
277 };
278 visit::walk_crate(&mut v, krate, ());
279 tcx.sess.abort_if_errors();
280 }
281
282
283 // FIXME (#33): this doesn't handle big integer/float literals correctly
284 // (nor does the rest of our literal handling).
285 #[deriving(Clone, Eq)]
286 pub enum const_val {
287 const_float(f64),
288 const_int(i64),
289 const_uint(u64),
290 const_str(InternedString),
291 const_binary(Rc<Vec<u8> >),
292 const_bool(bool)
293 }
294
295 pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> const_val {
296 match eval_const_expr_partial(tcx, e) {
297 Ok(r) => r,
298 Err(s) => tcx.sess.span_fatal(e.span, s)
299 }
300 }
301
302 pub fn eval_const_expr_partial<T: ty::ExprTyProvider>(tcx: &T, e: &Expr)
303 -> Result<const_val, ~str> {
304 fn fromb(b: bool) -> Result<const_val, ~str> { Ok(const_int(b as i64)) }
305 match e.node {
306 ExprUnary(UnNeg, inner) => {
307 match eval_const_expr_partial(tcx, inner) {
308 Ok(const_float(f)) => Ok(const_float(-f)),
309 Ok(const_int(i)) => Ok(const_int(-i)),
310 Ok(const_uint(i)) => Ok(const_uint(-i)),
311 Ok(const_str(_)) => Err("negate on string".to_owned()),
312 Ok(const_bool(_)) => Err("negate on boolean".to_owned()),
313 ref err => ((*err).clone())
314 }
315 }
316 ExprUnary(UnNot, inner) => {
317 match eval_const_expr_partial(tcx, inner) {
318 Ok(const_int(i)) => Ok(const_int(!i)),
319 Ok(const_uint(i)) => Ok(const_uint(!i)),
320 Ok(const_bool(b)) => Ok(const_bool(!b)),
321 _ => Err("not on float or string".to_owned())
322 }
323 }
324 ExprBinary(op, a, b) => {
325 match (eval_const_expr_partial(tcx, a),
326 eval_const_expr_partial(tcx, b)) {
327 (Ok(const_float(a)), Ok(const_float(b))) => {
328 match op {
329 BiAdd => Ok(const_float(a + b)),
330 BiSub => Ok(const_float(a - b)),
331 BiMul => Ok(const_float(a * b)),
332 BiDiv => Ok(const_float(a / b)),
333 BiRem => Ok(const_float(a % b)),
334 BiEq => fromb(a == b),
335 BiLt => fromb(a < b),
336 BiLe => fromb(a <= b),
337 BiNe => fromb(a != b),
338 BiGe => fromb(a >= b),
339 BiGt => fromb(a > b),
340 _ => Err("can't do this op on floats".to_owned())
341 }
342 }
343 (Ok(const_int(a)), Ok(const_int(b))) => {
344 match op {
345 BiAdd => Ok(const_int(a + b)),
346 BiSub => Ok(const_int(a - b)),
347 BiMul => Ok(const_int(a * b)),
348 BiDiv if b == 0 => Err("attempted to divide by zero".to_owned()),
349 BiDiv => Ok(const_int(a / b)),
350 BiRem if b == 0 => Err("attempted remainder with a divisor of zero".to_owned()),
351 BiRem => Ok(const_int(a % b)),
352 BiAnd | BiBitAnd => Ok(const_int(a & b)),
353 BiOr | BiBitOr => Ok(const_int(a | b)),
354 BiBitXor => Ok(const_int(a ^ b)),
355 BiShl => Ok(const_int(a << b)),
356 BiShr => Ok(const_int(a >> b)),
357 BiEq => fromb(a == b),
358 BiLt => fromb(a < b),
359 BiLe => fromb(a <= b),
360 BiNe => fromb(a != b),
361 BiGe => fromb(a >= b),
362 BiGt => fromb(a > b)
363 }
364 }
365 (Ok(const_uint(a)), Ok(const_uint(b))) => {
366 match op {
367 BiAdd => Ok(const_uint(a + b)),
368 BiSub => Ok(const_uint(a - b)),
369 BiMul => Ok(const_uint(a * b)),
370 BiDiv if b == 0 => Err("attempted to divide by zero".to_owned()),
371 BiDiv => Ok(const_uint(a / b)),
372 BiRem if b == 0 => Err("attempted remainder with a divisor of zero".to_owned()),
373 BiRem => Ok(const_uint(a % b)),
374 BiAnd | BiBitAnd => Ok(const_uint(a & b)),
375 BiOr | BiBitOr => Ok(const_uint(a | b)),
376 BiBitXor => Ok(const_uint(a ^ b)),
377 BiShl => Ok(const_uint(a << b)),
378 BiShr => Ok(const_uint(a >> b)),
379 BiEq => fromb(a == b),
380 BiLt => fromb(a < b),
381 BiLe => fromb(a <= b),
382 BiNe => fromb(a != b),
383 BiGe => fromb(a >= b),
384 BiGt => fromb(a > b),
385 }
386 }
387 // shifts can have any integral type as their rhs
388 (Ok(const_int(a)), Ok(const_uint(b))) => {
389 match op {
390 BiShl => Ok(const_int(a << b)),
391 BiShr => Ok(const_int(a >> b)),
392 _ => Err("can't do this op on an int and uint".to_owned())
393 }
394 }
395 (Ok(const_uint(a)), Ok(const_int(b))) => {
396 match op {
397 BiShl => Ok(const_uint(a << b)),
398 BiShr => Ok(const_uint(a >> b)),
399 _ => Err("can't do this op on a uint and int".to_owned())
400 }
401 }
402 (Ok(const_bool(a)), Ok(const_bool(b))) => {
403 Ok(const_bool(match op {
404 BiAnd => a && b,
405 BiOr => a || b,
406 BiBitXor => a ^ b,
407 BiBitAnd => a & b,
408 BiBitOr => a | b,
409 BiEq => a == b,
410 BiNe => a != b,
411 _ => return Err("can't do this op on bools".to_owned())
412 }))
413 }
414 _ => Err("bad operands for binary".to_owned())
415 }
416 }
417 ExprCast(base, target_ty) => {
418 // This tends to get called w/o the type actually having been
419 // populated in the ctxt, which was causing things to blow up
420 // (#5900). Fall back to doing a limited lookup to get past it.
421 let ety = ty::expr_ty_opt(tcx.ty_ctxt(), e)
422 .or_else(|| astconv::ast_ty_to_prim_ty(tcx.ty_ctxt(), target_ty))
423 .unwrap_or_else(|| tcx.ty_ctxt().sess.span_fatal(
424 target_ty.span,
425 format!("target type not found for const cast")
426 ));
427
428 let base = eval_const_expr_partial(tcx, base);
429 match base {
430 Err(_) => base,
431 Ok(val) => {
432 match ty::get(ety).sty {
433 ty::ty_float(_) => {
434 match val {
435 const_uint(u) => Ok(const_float(u as f64)),
436 const_int(i) => Ok(const_float(i as f64)),
437 const_float(f) => Ok(const_float(f)),
438 _ => Err("can't cast float to str".to_owned()),
439 }
440 }
441 ty::ty_uint(_) => {
442 match val {
443 const_uint(u) => Ok(const_uint(u)),
444 const_int(i) => Ok(const_uint(i as u64)),
445 const_float(f) => Ok(const_uint(f as u64)),
446 _ => Err("can't cast str to uint".to_owned()),
447 }
448 }
449 ty::ty_int(_) | ty::ty_bool => {
450 match val {
451 const_uint(u) => Ok(const_int(u as i64)),
452 const_int(i) => Ok(const_int(i)),
453 const_float(f) => Ok(const_int(f as i64)),
454 _ => Err("can't cast str to int".to_owned()),
455 }
456 }
457 _ => Err("can't cast this type".to_owned())
458 }
459 }
460 }
461 }
462 ExprPath(_) => {
463 match lookup_const(tcx.ty_ctxt(), e) {
464 Some(actual_e) => eval_const_expr_partial(tcx.ty_ctxt(), actual_e),
465 None => Err("non-constant path in constant expr".to_owned())
466 }
467 }
468 ExprLit(lit) => Ok(lit_to_const(lit)),
469 // If we have a vstore, just keep going; it has to be a string
470 ExprVstore(e, _) => eval_const_expr_partial(tcx, e),
471 ExprParen(e) => eval_const_expr_partial(tcx, e),
472 _ => Err("unsupported constant expr".to_owned())
473 }
474 }
475
476 pub fn lit_to_const(lit: &Lit) -> const_val {
477 match lit.node {
478 LitStr(ref s, _) => const_str((*s).clone()),
479 LitBinary(ref data) => {
480 const_binary(Rc::new(data.iter().map(|x| *x).collect()))
481 }
482 LitChar(n) => const_uint(n as u64),
483 LitInt(n, _) => const_int(n),
484 LitUint(n, _) => const_uint(n),
485 LitIntUnsuffixed(n) => const_int(n),
486 LitFloat(ref n, _) | LitFloatUnsuffixed(ref n) => {
487 const_float(from_str::<f64>(n.get()).unwrap() as f64)
488 }
489 LitNil => const_int(0i64),
490 LitBool(b) => const_bool(b)
491 }
492 }
493
494 fn compare_vals<T: Ord>(a: T, b: T) -> Option<int> {
495 Some(if a == b { 0 } else if a < b { -1 } else { 1 })
496 }
497 pub fn compare_const_vals(a: &const_val, b: &const_val) -> Option<int> {
498 match (a, b) {
499 (&const_int(a), &const_int(b)) => compare_vals(a, b),
500 (&const_uint(a), &const_uint(b)) => compare_vals(a, b),
501 (&const_float(a), &const_float(b)) => compare_vals(a, b),
502 (&const_str(ref a), &const_str(ref b)) => compare_vals(a, b),
503 (&const_bool(a), &const_bool(b)) => compare_vals(a, b),
504 _ => None
505 }
506 }
507
508 pub fn compare_lit_exprs(tcx: &ty::ctxt, a: &Expr, b: &Expr) -> Option<int> {
509 compare_const_vals(&eval_const_expr(tcx, a), &eval_const_expr(tcx, b))
510 }
librustc/middle/const_eval.rs:304:4-304:4 -fn- definition:
fn fromb(b: bool) -> Result<const_val, ~str> { Ok(const_int(b as i64)) }
match e.node {
ExprUnary(UnNeg, inner) => {
references:- 18336: BiLe => fromb(a <= b),
337: BiNe => fromb(a != b),
338: BiGe => fromb(a >= b),
--
361: BiGe => fromb(a >= b),
362: BiGt => fromb(a > b)
363: }
--
380: BiLt => fromb(a < b),
381: BiLe => fromb(a <= b),
382: BiNe => fromb(a != b),
383: BiGe => fromb(a >= b),
384: BiGt => fromb(a > b),
385: }
librustc/middle/const_eval.rs:507:1-507:1 -fn- definition:
pub fn compare_lit_exprs(tcx: &ty::ctxt, a: &Expr, b: &Expr) -> Option<int> {
compare_const_vals(&eval_const_expr(tcx, a), &eval_const_expr(tcx, b))
}
references:- 4librustc/middle/trans/_match.rs:
277: (&range(a1, a2), &range(b1, b2)) => {
278: let m1 = const_eval::compare_lit_exprs(tcx, a1, b1);
279: let m2 = const_eval::compare_lit_exprs(tcx, a2, b2);
280: match (m1, m2) {
librustc/middle/typeck/check/mod.rs:
1430: -> Option<bool> {
1431: match const_eval::compare_lit_exprs(ccx.tcx, from, to) {
1432: Some(val) => Some(val <= 0),
librustc/middle/const_eval.rs:69:1-69:1 -fn- definition:
pub fn join(a: constness, b: constness) -> constness {
match (a, b) {
(integral_const, integral_const) => integral_const,
references:- 580: pub fn join_all<It: Iterator<constness>>(mut cs: It) -> constness {
81: cs.fold(integral_const, |a, b| join(a, b))
82: }
--
199: ast::ExprBinary(_, a, b) =>
200: join(self.classify(a), self.classify(b)),
--
222: if ty::type_is_integral(ty) {
223: join(integral_const, base)
224: } else if ty::type_is_fp(ty) {
225: join(general_const, base)
226: } else {
--
233: ast::ExprIndex(base, idx) =>
234: join(self.classify(base), self.classify(idx)),
librustc/middle/const_eval.rs:142:1-142:1 -fn- definition:
pub fn lookup_const_by_id(tcx: &ty::ctxt, def_id: ast::DefId)
-> Option<@Expr> {
if ast_util::is_local(def_id) {
references:- 687: Some(ast::DefStatic(def_id, false)) => {
88: lookup_const_by_id(tcx, def_id)
89: }
librustc/middle/trans/_match.rs:
260: ExprLit(existing_a_expr) => existing_a_expr,
261: ConstLit(a_const) => const_eval::lookup_const_by_id(tcx, a_const).unwrap(),
262: UnitLikeStructLit(_) => fail!("lit_to_expr: unexpected struct lit"),
librustc/middle/check_match.rs:
594: let const_expr =
595: lookup_const_by_id(cx.tcx, did).unwrap();
596: let e_v = eval_const_expr(cx.tcx, const_expr);
--
640: let const_expr =
641: lookup_const_by_id(cx.tcx, did).unwrap();
642: let e_v = eval_const_expr(cx.tcx, const_expr);
librustc/middle/const_eval.rs:175:1-175:1 -struct- definition:
struct ConstEvalVisitor<'a> {
tcx: &'a ty::ctxt,
ccache: constness_cache,
references:- 3181: impl<'a> ConstEvalVisitor<'a> {
182: fn classify(&mut self, e: &Expr) -> constness {
--
266: impl<'a> Visitor<()> for ConstEvalVisitor<'a> {
267: fn visit_expr_post(&mut self, e: &Expr, _: ()) {
--
273: tcx: &ty::ctxt) {
274: let mut v = ConstEvalVisitor {
275: tcx: tcx,
librustc/middle/const_eval.rs:101:4-101:4 -fn- definition:
fn variant_expr(variants: &[ast::P<ast::Variant>], id: ast::NodeId) -> Option<@Expr> {
for variant in variants.iter() {
if variant.node.id == id {
references:- 2115: ItemEnum(ast::EnumDef { variants: ref variants }, _) => {
116: variant_expr(variants.as_slice(), variant_def.node)
117: }
--
131: ItemEnum(ast::EnumDef { variants: ref variants }, _) => {
132: variant_expr(variants.as_slice(), variant_def.node)
133: }
librustc/middle/const_eval.rs:294:1-294:1 -fn- definition:
pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> const_val {
match eval_const_expr_partial(tcx, e) {
Ok(r) => r,
references:- 14508: pub fn compare_lit_exprs(tcx: &ty::ctxt, a: &Expr, b: &Expr) -> Option<int> {
509: compare_const_vals(&eval_const_expr(tcx, a), &eval_const_expr(tcx, b))
510: }
librustc/middle/trans/consts.rs:
427: let (bv, inlineable) = const_expr(cx, base, is_local);
428: let iv = match const_eval::eval_const_expr(cx.tcx(), index) {
429: const_eval::const_int(i) => i as u64,
--
599: let llunitty = type_of::type_of(cx, unit_ty);
600: let n = match const_eval::eval_const_expr(cx.tcx(), count) {
601: const_eval::const_int(i) => i as uint,
librustc/middle/check_match.rs:
791: };
792: let v_lo = eval_const_expr(cx.tcx, lo);
793: let v_hi = eval_const_expr(cx.tcx, hi);
librustc/middle/const_eval.rs:83:1-83:1 -fn- definition:
pub fn lookup_const(tcx: &ty::ctxt, e: &Expr) -> Option<@Expr> {
let opt_def = tcx.def_map.borrow().find_copy(&e.id);
match opt_def {
references:- 2462: ExprPath(_) => {
463: match lookup_const(tcx.ty_ctxt(), e) {
464: Some(actual_e) => eval_const_expr_partial(tcx.ty_ctxt(), actual_e),
librustc/middle/const_eval.rs:496:2-496:2 -fn- definition:
}
pub fn compare_const_vals(a: &const_val, b: &const_val) -> Option<int> {
match (a, b) {
references:- 12508: pub fn compare_lit_exprs(tcx: &ty::ctxt, a: &Expr, b: &Expr) -> Option<int> {
509: compare_const_vals(&eval_const_expr(tcx, a), &eval_const_expr(tcx, b))
510: }
librustc/middle/check_match.rs:
795: let m1 = compare_const_vals(&c_lo, &v_lo);
796: let m2 = compare_const_vals(&c_hi, &v_hi);
797: match (m1, m2) {
librustc/middle/const_eval.rs:61:1-61:1 -enum- definition:
pub enum constness {
integral_const,
general_const,
references:- 8181: impl<'a> ConstEvalVisitor<'a> {
182: fn classify(&mut self, e: &Expr) -> constness {
183: let did = ast_util::local_def(e.id);
--
250: fn lookup_constness(&self, e: &Expr) -> constness {
251: match lookup_const(self.tcx, e) {
librustc/middle/const_eval.rs:493:1-493:1 -fn- definition:
fn compare_vals<T: Ord>(a: T, b: T) -> Option<int> {
Some(if a == b { 0 } else if a < b { -1 } else { 1 })
}
references:- 5499: (&const_int(a), &const_int(b)) => compare_vals(a, b),
500: (&const_uint(a), &const_uint(b)) => compare_vals(a, b),
501: (&const_float(a), &const_float(b)) => compare_vals(a, b),
502: (&const_str(ref a), &const_str(ref b)) => compare_vals(a, b),
503: (&const_bool(a), &const_bool(b)) => compare_vals(a, b),
504: _ => None
librustc/middle/const_eval.rs:285:23-285:23 -enum- definition:
pub enum const_val {
const_float(f64),
const_int(i64),
references:- 14284: // (nor does the rest of our literal handling).
286: pub enum const_val {
--
295: pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> const_val {
296: match eval_const_expr_partial(tcx, e) {
--
496: }
497: pub fn compare_const_vals(a: &const_val, b: &const_val) -> Option<int> {
498: match (a, b) {
librustc/middle/check_match.rs:
215: variant(DefId),
216: val(const_val),
217: range(const_val, const_val),
218: vec(uint)
librustc/middle/const_eval.rs:
496: }
497: pub fn compare_const_vals(a: &const_val, b: &const_val) -> Option<int> {
498: match (a, b) {
librustc/middle/const_eval.rs:301:1-301:1 -fn- definition:
pub fn eval_const_expr_partial<T: ty::ExprTyProvider>(tcx: &T, e: &Expr)
-> Result<const_val, ~str> {
fn fromb(b: bool) -> Result<const_val, ~str> { Ok(const_int(b as i64)) }
references:- 13316: ExprUnary(UnNot, inner) => {
317: match eval_const_expr_partial(tcx, inner) {
318: Ok(const_int(i)) => Ok(const_int(!i)),
--
324: ExprBinary(op, a, b) => {
325: match (eval_const_expr_partial(tcx, a),
326: eval_const_expr_partial(tcx, b)) {
327: (Ok(const_float(a)), Ok(const_float(b))) => {
--
469: // If we have a vstore, just keep going; it has to be a string
470: ExprVstore(e, _) => eval_const_expr_partial(tcx, e),
471: ExprParen(e) => eval_const_expr_partial(tcx, e),
472: _ => Err("unsupported constant expr".to_owned())
librustc/middle/ty.rs:
4183: pub fn eval_repeat_count<T: ExprTyProvider>(tcx: &T, count_expr: &ast::Expr) -> uint {
4184: match const_eval::eval_const_expr_partial(tcx, count_expr) {
4185: Ok(ref const_val) => match *const_val {
librustc/middle/typeck/check/mod.rs:
3685: match const_eval::eval_const_expr_partial(ccx.tcx, e) {
3686: Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
librustc/middle/typeck/astconv.rs:
688: ast::TyFixedLengthVec(ty, e) => {
689: match const_eval::eval_const_expr_partial(tcx, e) {
690: Ok(ref r) => {
librustc/middle/ty.rs:
3802: match variant.node.disr_expr {
3803: Some(e) => match const_eval::eval_const_expr_partial(cx, e) {
3804: Ok(const_eval::const_int(val)) => {
librustc/middle/const_eval.rs:79:1-79:1 -fn- definition:
pub fn join_all<It: Iterator<constness>>(mut cs: It) -> constness {
cs.fold(integral_const, |a, b| join(a, b))
}
references:- 2203: ast::ExprVec(ref es) =>
204: join_all(es.iter().map(|e| self.classify(*e))),
--
215: let cs = fs.iter().map(|f| self.classify(f.expr));
216: join_all(cs)
217: }