(index<- )        ./librustc/middle/const_eval.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   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(aconstness, bconstness) -> 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 csIt) -> 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_defast::DefId,
  99                              variant_defast::DefId)
 100                         -> Option<@Expr> {
 101      fn variant_expr(variants&[ast::P<ast::Variant>], idast::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_idast::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(bbool) -> 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>(aT, bT) -> 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:- 18
336:               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:- 4
librustc/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:- 5
80: 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:- 6
87:         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:- 3
181: 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:- 2
115:                     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:- 14
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/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:- 2
462:       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:- 12
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/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:- 8
181: 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:- 5
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


librustc/middle/const_eval.rs:285:23-285:23 -enum- definition:
pub enum const_val {
    const_float(f64),
    const_int(i64),
references:- 14
284: // (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:- 13
316:       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:- 2
203:             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:             }