diff --git a/src/rustc/middle/check_alt.rs b/src/rustc/middle/check_alt.rs index 31ef3703c0b..1a97b276afe 100644 --- a/src/rustc/middle/check_alt.rs +++ b/src/rustc/middle/check_alt.rs @@ -1,7 +1,7 @@ import syntax::ast::*; -import syntax::ast_util::{variant_def_ids, dummy_sp, compare_lit_exprs, - lit_expr_eq, unguarded_pat}; +import syntax::ast_util::{variant_def_ids, dummy_sp, unguarded_pat}; +import middle::const_eval::{compare_lit_exprs, lit_expr_eq}; import syntax::codemap::span; import pat_util::*; import syntax::visit; diff --git a/src/rustc/middle/const_eval.rs b/src/rustc/middle/const_eval.rs new file mode 100644 index 00000000000..ca066b127bc --- /dev/null +++ b/src/rustc/middle/const_eval.rs @@ -0,0 +1,167 @@ +import syntax::ast::*; + +// FIXME this doesn't handle big integer/float literals correctly (nor does +// the rest of our literal handling) +enum const_val { + const_float(float), + const_int(i64), + const_uint(u64), + const_str(str), +} + +// FIXME: issue #1417 +fn eval_const_expr(tcx: middle::ty::ctxt, e: @expr) -> const_val { + import middle::ty; + fn fromb(b: bool) -> const_val { const_int(b as i64) } + alt check e.node { + expr_unary(neg, inner) { + alt check eval_const_expr(tcx, inner) { + const_float(f) { const_float(-f) } + const_int(i) { const_int(-i) } + const_uint(i) { const_uint(-i) } + } + } + expr_unary(not, inner) { + alt check eval_const_expr(tcx, inner) { + const_int(i) { const_int(!i) } + const_uint(i) { const_uint(!i) } + } + } + expr_binary(op, a, b) { + alt check (eval_const_expr(tcx, a), eval_const_expr(tcx, b)) { + (const_float(a), const_float(b)) { + alt check op { + add { const_float(a + b) } subtract { const_float(a - b) } + mul { const_float(a * b) } div { const_float(a / b) } + rem { const_float(a % b) } eq { fromb(a == b) } + lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) } + ge { fromb(a >= b) } gt { fromb(a > b) } + } + } + (const_int(a), const_int(b)) { + alt check op { + add { const_int(a + b) } subtract { const_int(a - b) } + mul { const_int(a * b) } div { const_int(a / b) } + rem { const_int(a % b) } and | bitand { const_int(a & b) } + or | bitor { const_int(a | b) } bitxor { const_int(a ^ b) } + lsl { const_int(a << b) } lsr { const_int(a >> b) } + asr { const_int(a >>> b) } + eq { fromb(a == b) } lt { fromb(a < b) } + le { fromb(a <= b) } ne { fromb(a != b) } + ge { fromb(a >= b) } gt { fromb(a > b) } + } + + } + (const_uint(a), const_uint(b)) { + alt check op { + add { const_uint(a + b) } subtract { const_uint(a - b) } + mul { const_uint(a * b) } div { const_uint(a / b) } + rem { const_uint(a % b) } and | bitand { const_uint(a & b) } + or | bitor { const_uint(a | b) } bitxor { const_uint(a ^ b) } + lsl { const_int((a << b) as i64) } + lsr { const_int((a >> b) as i64) } + asr { const_int((a >>> b) as i64) } + eq { fromb(a == b) } lt { fromb(a < b) } + le { fromb(a <= b) } ne { fromb(a != b) } + ge { fromb(a >= b) } gt { fromb(a > b) } + } + } + } + } + expr_cast(base, _) { + let ety = ty::expr_ty(tcx, e); + let base = eval_const_expr(tcx, base); + alt check ty::get(ety).struct { + ty::ty_float(_) { + alt check base { + const_uint(u) { const_float(u as f64) } + const_int(i) { const_float(i as f64) } + const_float(_) { base } + } + } + ty::ty_uint(_) { + alt check base { + const_uint(_) { base } + const_int(i) { const_uint(i as u64) } + const_float(f) { const_uint(f as u64) } + } + } + ty::ty_int(_) | ty::ty_bool { + alt check base { + const_uint(u) { const_int(u as i64) } + const_int(_) { base } + const_float(f) { const_int(f as i64) } + } + } + } + } + expr_lit(lit) { lit_to_const(lit) } + } +} + +fn lit_to_const(lit: @lit) -> const_val { + alt lit.node { + lit_str(s) { const_str(s) } + lit_int(n, _) { const_int(n) } + lit_uint(n, _) { const_uint(n) } + lit_float(n, _) { const_float(option::get(float::from_str(n))) } + lit_nil { const_int(0i64) } + lit_bool(b) { const_int(b as i64) } + } +} + +fn compare_const_vals(a: const_val, b: const_val) -> int { + alt (a, b) { + (const_int(a), const_int(b)) { + if a == b { + 0 + } else if a < b { + -1 + } else { + 1 + } + } + (const_uint(a), const_uint(b)) { + if a == b { + 0 + } else if a < b { + -1 + } else { + 1 + } + } + (const_float(a), const_float(b)) { + if a == b { + 0 + } else if a < b { + -1 + } else { + 1 + } + } + (const_str(a), const_str(b)) { + if a == b { + 0 + } else if a < b { + -1 + } else { + 1 + } + } + _ { + fail "compare_const_vals: ill-typed comparison"; + } + } +} + +fn compare_lit_exprs(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> int { + compare_const_vals(eval_const_expr(tcx, a), eval_const_expr(tcx, b)) +} + +fn lit_expr_eq(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> bool { + compare_lit_exprs(tcx, a, b) == 0 +} + +fn lit_eq(a: @lit, b: @lit) -> bool { + compare_const_vals(lit_to_const(a), lit_to_const(b)) == 0 +} diff --git a/src/rustc/middle/trans/alt.rs b/src/rustc/middle/trans/alt.rs index a3d5dba565a..8b8ee1fe81b 100644 --- a/src/rustc/middle/trans/alt.rs +++ b/src/rustc/middle/trans/alt.rs @@ -25,10 +25,10 @@ enum opt { } fn opt_eq(tcx: ty::ctxt, a: opt, b: opt) -> bool { alt (a, b) { - (lit(a), lit(b)) { ast_util::compare_lit_exprs(tcx, a, b) == 0 } + (lit(a), lit(b)) { const_eval::compare_lit_exprs(tcx, a, b) == 0 } (range(a1, a2), range(b1, b2)) { - ast_util::compare_lit_exprs(tcx, a1, b1) == 0 && - ast_util::compare_lit_exprs(tcx, a2, b2) == 0 + const_eval::compare_lit_exprs(tcx, a1, b1) == 0 && + const_eval::compare_lit_exprs(tcx, a2, b2) == 0 } (var(a, _), var(b, _)) { a == b } _ { false } diff --git a/src/rustc/middle/tstate/auxiliary.rs b/src/rustc/middle/tstate/auxiliary.rs index b2ed35d8f13..c973d15b40d 100644 --- a/src/rustc/middle/tstate/auxiliary.rs +++ b/src/rustc/middle/tstate/auxiliary.rs @@ -676,7 +676,7 @@ fn pred_args_matches(pattern: [constr_arg_general_], desc: pred_args) -> carg_base { if n != carg_base { ret false; } } carg_lit(l) { alt n { - carg_lit(m) { if !lit_eq(l, m) { ret false; } } + carg_lit(m) { if !const_eval::lit_eq(l, m) { ret false; } } _ { ret false; } } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 8fac6b536c0..deeef4f6826 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -1306,7 +1306,7 @@ fn arg_eq(eq: fn(T, T) -> bool, } ast::carg_lit(l) { alt b.node { - ast::carg_lit(m) { ret ast_util::lit_eq(l, m); } _ { ret false; } + ast::carg_lit(m) { ret const_eval::lit_eq(l, m); } _ { ret false; } } } } @@ -1894,8 +1894,8 @@ fn enum_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] { alt variant.node.disr_expr { some (ex) { // FIXME: issue #1417 - disr_val = alt syntax::ast_util::eval_const_expr(cx, ex) { - ast_util::const_int(val) {val as int} + disr_val = alt const_eval::eval_const_expr(cx, ex) { + const_eval::const_int(val) {val as int} _ { cx.sess.bug("tag_variants: bad disr expr"); } } } diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 165ca33a15f..8ef8841754c 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -1645,7 +1645,7 @@ fn check_lit(ccx: @crate_ctxt, lit: @ast::lit) -> ty::t { fn valid_range_bounds(tcx: ty::ctxt, from: @ast::expr, to: @ast::expr) -> bool { - ast_util::compare_lit_exprs(tcx, from, to) <= 0 + const_eval::compare_lit_exprs(tcx, from, to) <= 0 } type pat_ctxt = { @@ -3404,8 +3404,8 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant], // Also, check_expr (from check_const pass) doesn't guarantee that // the expression in an form that eval_const_expr can handle, so // we may still get an internal compiler error - alt syntax::ast_util::eval_const_expr(ccx.tcx, e) { - syntax::ast_util::const_int(val) { + alt const_eval::eval_const_expr(ccx.tcx, e) { + const_eval::const_int(val) { disr_val = val as int; } _ { diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc index 0c780f15b8b..4993f63cfc0 100644 --- a/src/rustc/rustc.rc +++ b/src/rustc/rustc.rc @@ -50,6 +50,7 @@ mod middle { mod pat_util; mod region; mod regionck; + mod const_eval; mod tstate { mod ck; diff --git a/src/rustc/syntax/ast_util.rs b/src/rustc/syntax/ast_util.rs index 308b13be882..4ab7c325a69 100644 --- a/src/rustc/syntax/ast_util.rs +++ b/src/rustc/syntax/ast_util.rs @@ -242,172 +242,6 @@ fn default_block(stmts1: [@stmt], expr1: option<@expr>, id1: node_id) -> {view_items: [], stmts: stmts1, expr: expr1, id: id1, rules: default_blk} } -// FIXME this doesn't handle big integer/float literals correctly (nor does -// the rest of our literal handling) -enum const_val { - const_float(float), - const_int(i64), - const_uint(u64), - const_str(str), -} - -// FIXME: issue #1417 -fn eval_const_expr(tcx: middle::ty::ctxt, e: @expr) -> const_val { - import middle::ty; - fn fromb(b: bool) -> const_val { const_int(b as i64) } - alt check e.node { - expr_unary(neg, inner) { - alt check eval_const_expr(tcx, inner) { - const_float(f) { const_float(-f) } - const_int(i) { const_int(-i) } - const_uint(i) { const_uint(-i) } - } - } - expr_unary(not, inner) { - alt check eval_const_expr(tcx, inner) { - const_int(i) { const_int(!i) } - const_uint(i) { const_uint(!i) } - } - } - expr_binary(op, a, b) { - alt check (eval_const_expr(tcx, a), eval_const_expr(tcx, b)) { - (const_float(a), const_float(b)) { - alt check op { - add { const_float(a + b) } subtract { const_float(a - b) } - mul { const_float(a * b) } div { const_float(a / b) } - rem { const_float(a % b) } eq { fromb(a == b) } - lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) } - ge { fromb(a >= b) } gt { fromb(a > b) } - } - } - (const_int(a), const_int(b)) { - alt check op { - add { const_int(a + b) } subtract { const_int(a - b) } - mul { const_int(a * b) } div { const_int(a / b) } - rem { const_int(a % b) } and | bitand { const_int(a & b) } - or | bitor { const_int(a | b) } bitxor { const_int(a ^ b) } - lsl { const_int(a << b) } lsr { const_int(a >> b) } - asr { const_int(a >>> b) } - eq { fromb(a == b) } lt { fromb(a < b) } - le { fromb(a <= b) } ne { fromb(a != b) } - ge { fromb(a >= b) } gt { fromb(a > b) } - } - - } - (const_uint(a), const_uint(b)) { - alt check op { - add { const_uint(a + b) } subtract { const_uint(a - b) } - mul { const_uint(a * b) } div { const_uint(a / b) } - rem { const_uint(a % b) } and | bitand { const_uint(a & b) } - or | bitor { const_uint(a | b) } bitxor { const_uint(a ^ b) } - lsl { const_int((a << b) as i64) } - lsr { const_int((a >> b) as i64) } - asr { const_int((a >>> b) as i64) } - eq { fromb(a == b) } lt { fromb(a < b) } - le { fromb(a <= b) } ne { fromb(a != b) } - ge { fromb(a >= b) } gt { fromb(a > b) } - } - } - } - } - expr_cast(base, _) { - let ety = ty::expr_ty(tcx, e); - let base = eval_const_expr(tcx, base); - alt check ty::get(ety).struct { - ty::ty_float(_) { - alt check base { - const_uint(u) { const_float(u as f64) } - const_int(i) { const_float(i as f64) } - const_float(_) { base } - } - } - ty::ty_uint(_) { - alt check base { - const_uint(_) { base } - const_int(i) { const_uint(i as u64) } - const_float(f) { const_uint(f as u64) } - } - } - ty::ty_int(_) | ty::ty_bool { - alt check base { - const_uint(u) { const_int(u as i64) } - const_int(_) { base } - const_float(f) { const_int(f as i64) } - } - } - } - } - expr_lit(lit) { lit_to_const(lit) } - } -} - -fn lit_to_const(lit: @lit) -> const_val { - alt lit.node { - lit_str(s) { const_str(s) } - lit_int(n, _) { const_int(n) } - lit_uint(n, _) { const_uint(n) } - lit_float(n, _) { const_float(option::get(float::from_str(n))) } - lit_nil { const_int(0i64) } - lit_bool(b) { const_int(b as i64) } - } -} - -fn compare_const_vals(a: const_val, b: const_val) -> int { - alt (a, b) { - (const_int(a), const_int(b)) { - if a == b { - 0 - } else if a < b { - -1 - } else { - 1 - } - } - (const_uint(a), const_uint(b)) { - if a == b { - 0 - } else if a < b { - -1 - } else { - 1 - } - } - (const_float(a), const_float(b)) { - if a == b { - 0 - } else if a < b { - -1 - } else { - 1 - } - } - (const_str(a), const_str(b)) { - if a == b { - 0 - } else if a < b { - -1 - } else { - 1 - } - } - _ { - fail "compare_const_vals: ill-typed comparison"; - } - } -} - -fn compare_lit_exprs(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> int { - compare_const_vals(eval_const_expr(tcx, a), eval_const_expr(tcx, b)) -} - -fn lit_expr_eq(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> bool { - compare_lit_exprs(tcx, a, b) == 0 -} - -fn lit_eq(a: @lit, b: @lit) -> bool { - compare_const_vals(lit_to_const(a), lit_to_const(b)) == 0 -} - fn ident_to_path(s: span, i: ident) -> @path { @respan(s, {global: false, idents: [i], types: []}) }