Convert match on enums to use trans::adt.
This commit is contained in:
parent
626ad484fe
commit
c4682dcabe
1 changed files with 51 additions and 83 deletions
|
|
@ -151,6 +151,7 @@ use middle::const_eval;
|
|||
use middle::borrowck::root_map_key;
|
||||
use middle::pat_util::*;
|
||||
use middle::resolve::DefMap;
|
||||
use middle::trans::adt;
|
||||
use middle::trans::base::*;
|
||||
use middle::trans::build::*;
|
||||
use middle::trans::callee;
|
||||
|
|
@ -191,15 +192,15 @@ pub enum Lit {
|
|||
// range)
|
||||
pub enum Opt {
|
||||
lit(Lit),
|
||||
var(/* disr val */int, /* variant dids (enm, var) */(def_id, def_id)),
|
||||
var(/* disr val */int, adt::Repr),
|
||||
range(@ast::expr, @ast::expr),
|
||||
vec_len_eq(uint),
|
||||
vec_len_ge(uint)
|
||||
}
|
||||
|
||||
pub fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool {
|
||||
match (*a, *b) {
|
||||
(lit(a), lit(b)) => {
|
||||
match (a, b) {
|
||||
(&lit(a), &lit(b)) => {
|
||||
match (a, b) {
|
||||
(UnitLikeStructLit(a), UnitLikeStructLit(b)) => a == b,
|
||||
_ => {
|
||||
|
|
@ -233,13 +234,13 @@ pub fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool {
|
|||
}
|
||||
}
|
||||
}
|
||||
(range(a1, a2), range(b1, b2)) => {
|
||||
(&range(a1, a2), &range(b1, b2)) => {
|
||||
const_eval::compare_lit_exprs(tcx, a1, b1) == 0 &&
|
||||
const_eval::compare_lit_exprs(tcx, a2, b2) == 0
|
||||
}
|
||||
(var(a, _), var(b, _)) => a == b,
|
||||
(vec_len_eq(a), vec_len_eq(b)) => a == b,
|
||||
(vec_len_ge(a), vec_len_ge(b)) => a == b,
|
||||
(&var(a, _), &var(b, _)) => a == b,
|
||||
(&vec_len_eq(a), &vec_len_eq(b)) => a == b,
|
||||
(&vec_len_ge(a), &vec_len_ge(b)) => a == b,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
|
@ -267,8 +268,8 @@ pub fn trans_opt(bcx: block, o: &Opt) -> opt_result {
|
|||
let llval = consts::get_const_val(bcx.ccx(), lit_id);
|
||||
return single_result(rslt(bcx, llval));
|
||||
}
|
||||
var(disr_val, _) => {
|
||||
return single_result(rslt(bcx, C_int(ccx, disr_val)));
|
||||
var(disr_val, ref repr) => {
|
||||
return adt::trans_case(bcx, repr, disr_val);
|
||||
}
|
||||
range(l1, l2) => {
|
||||
return range_result(rslt(bcx, consts::const_expr(ccx, l1)),
|
||||
|
|
@ -283,13 +284,16 @@ pub fn trans_opt(bcx: block, o: &Opt) -> opt_result {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn variant_opt(tcx: ty::ctxt, pat_id: ast::node_id) -> Opt {
|
||||
match tcx.def_map.get(&pat_id) {
|
||||
pub fn variant_opt(bcx: block, pat_id: ast::node_id)
|
||||
-> Opt {
|
||||
let ccx = bcx.ccx();
|
||||
match ccx.tcx.def_map.get(&pat_id) {
|
||||
ast::def_variant(enum_id, var_id) => {
|
||||
let variants = ty::enum_variants(tcx, enum_id);
|
||||
let variants = ty::enum_variants(ccx.tcx, enum_id);
|
||||
for vec::each(*variants) |v| {
|
||||
if var_id == v.id {
|
||||
return var(v.disr_val, (enum_id, var_id));
|
||||
return var(v.disr_val,
|
||||
adt::represent_node(bcx, pat_id))
|
||||
}
|
||||
}
|
||||
::core::util::unreachable();
|
||||
|
|
@ -298,7 +302,7 @@ pub fn variant_opt(tcx: ty::ctxt, pat_id: ast::node_id) -> Opt {
|
|||
return lit(UnitLikeStructLit(pat_id));
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.bug(~"non-variant or struct in variant_opt()");
|
||||
ccx.sess.bug(~"non-variant or struct in variant_opt()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -505,7 +509,7 @@ pub fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint,
|
|||
do enter_match(bcx, tcx.def_map, m, col, val) |p| {
|
||||
match /*bad*/copy p.node {
|
||||
ast::pat_enum(_, subpats) => {
|
||||
if opt_eq(tcx, &variant_opt(tcx, p.id), opt) {
|
||||
if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
|
||||
Some(option::get_or_default(subpats,
|
||||
vec::from_elem(variant_size,
|
||||
dummy)))
|
||||
|
|
@ -515,7 +519,7 @@ pub fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint,
|
|||
}
|
||||
ast::pat_ident(_, _, None)
|
||||
if pat_is_variant_or_struct(tcx.def_map, p) => {
|
||||
if opt_eq(tcx, &variant_opt(tcx, p.id), opt) {
|
||||
if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
|
||||
Some(~[])
|
||||
} else {
|
||||
None
|
||||
|
|
@ -537,7 +541,7 @@ pub fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint,
|
|||
if opt_eq(tcx, &range(l1, l2), opt) {Some(~[])} else {None}
|
||||
}
|
||||
ast::pat_struct(_, field_pats, _) => {
|
||||
if opt_eq(tcx, &variant_opt(tcx, p.id), opt) {
|
||||
if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
|
||||
// Look up the struct variant ID.
|
||||
let struct_id;
|
||||
match tcx.def_map.get(&p.id) {
|
||||
|
|
@ -762,8 +766,9 @@ pub fn enter_region(bcx: block,
|
|||
// Returns the options in one column of matches. An option is something that
|
||||
// needs to be conditionally matched at runtime; for example, the discriminant
|
||||
// on a set of enum variants or a literal.
|
||||
pub fn get_options(ccx: @CrateContext, m: &[@Match], col: uint) -> ~[Opt] {
|
||||
fn add_to_set(tcx: ty::ctxt, set: &DVec<Opt>, val: Opt) {
|
||||
pub fn get_options(bcx: block, m: &[@Match], col: uint) -> ~[Opt] {
|
||||
let ccx = bcx.ccx();
|
||||
fn add_to_set(tcx: ty::ctxt, set: &DVec<Opt>, +val: Opt) {
|
||||
if set.any(|l| opt_eq(tcx, l, &val)) {return;}
|
||||
set.push(val);
|
||||
}
|
||||
|
|
@ -781,7 +786,7 @@ pub fn get_options(ccx: @CrateContext, m: &[@Match], col: uint) -> ~[Opt] {
|
|||
match ccx.tcx.def_map.find(&cur.id) {
|
||||
Some(ast::def_variant(*)) => {
|
||||
add_to_set(ccx.tcx, &found,
|
||||
variant_opt(ccx.tcx, cur.id));
|
||||
variant_opt(bcx, cur.id));
|
||||
}
|
||||
Some(ast::def_struct(*)) => {
|
||||
add_to_set(ccx.tcx, &found,
|
||||
|
|
@ -800,7 +805,7 @@ pub fn get_options(ccx: @CrateContext, m: &[@Match], col: uint) -> ~[Opt] {
|
|||
match ccx.tcx.def_map.find(&cur.id) {
|
||||
Some(ast::def_variant(*)) => {
|
||||
add_to_set(ccx.tcx, &found,
|
||||
variant_opt(ccx.tcx, cur.id));
|
||||
variant_opt(bcx, cur.id));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -827,34 +832,13 @@ pub struct ExtractedBlock {
|
|||
}
|
||||
|
||||
pub fn extract_variant_args(bcx: block,
|
||||
pat_id: ast::node_id,
|
||||
vdefs: (def_id, def_id),
|
||||
repr: &adt::Repr,
|
||||
disr_val: int,
|
||||
val: ValueRef)
|
||||
-> ExtractedBlock {
|
||||
let (enm, evar) = vdefs;
|
||||
-> ExtractedBlock {
|
||||
let _icx = bcx.insn_ctxt("match::extract_variant_args");
|
||||
let ccx = *bcx.fcx.ccx;
|
||||
let enum_ty_substs = match ty::get(node_id_type(bcx, pat_id)).sty {
|
||||
ty::ty_enum(id, ref substs) => {
|
||||
assert id == enm;
|
||||
/*bad*/copy (*substs).tps
|
||||
}
|
||||
_ => bcx.sess().bug(~"extract_variant_args: pattern has non-enum type")
|
||||
};
|
||||
let mut blobptr = val;
|
||||
let variants = ty::enum_variants(ccx.tcx, enm);
|
||||
let size = ty::enum_variant_with_id(ccx.tcx, enm,
|
||||
evar).args.len();
|
||||
if size > 0u && (*variants).len() != 1u {
|
||||
let enumptr =
|
||||
PointerCast(bcx, val, T_opaque_enum_ptr(ccx));
|
||||
blobptr = GEPi(bcx, enumptr, [0u, 1u]);
|
||||
}
|
||||
let vdefs_tg = enm;
|
||||
let vdefs_var = evar;
|
||||
let args = do vec::from_fn(size) |i| {
|
||||
GEP_enum(bcx, blobptr, vdefs_tg, vdefs_var,
|
||||
/*bad*/copy enum_ty_substs, i)
|
||||
let args = do vec::from_fn(adt::num_args(repr, disr_val)) |i| {
|
||||
adt::trans_GEP(bcx, repr, val, disr_val, i)
|
||||
};
|
||||
|
||||
ExtractedBlock { vals: args, bcx: bcx }
|
||||
|
|
@ -1365,37 +1349,15 @@ pub fn compile_submatch(bcx: block,
|
|||
}
|
||||
|
||||
// Decide what kind of branch we need
|
||||
let opts = get_options(ccx, m, col);
|
||||
let opts = get_options(bcx, m, col);
|
||||
let mut kind = no_branch;
|
||||
let mut test_val = val;
|
||||
if opts.len() > 0u {
|
||||
match opts[0] {
|
||||
var(_, (enm, _)) => {
|
||||
let variants = ty::enum_variants(tcx, enm);
|
||||
if variants.len() == 1 {
|
||||
kind = single;
|
||||
} else {
|
||||
let enumptr =
|
||||
PointerCast(bcx, val, T_opaque_enum_ptr(ccx));
|
||||
let discrimptr = GEPi(bcx, enumptr, [0u, 0u]);
|
||||
|
||||
|
||||
assert variants.len() > 1;
|
||||
let min_discrim = do variants.foldr(0) |&x, y| {
|
||||
int::min(x.disr_val, y)
|
||||
};
|
||||
let max_discrim = do variants.foldr(0) |&x, y| {
|
||||
int::max(x.disr_val, y)
|
||||
};
|
||||
|
||||
test_val = LoadRangeAssert(bcx, discrimptr,
|
||||
min_discrim as c_ulonglong,
|
||||
(max_discrim + 1)
|
||||
as c_ulonglong,
|
||||
lib::llvm::True);
|
||||
|
||||
kind = switch;
|
||||
}
|
||||
var(_, ref repr) => {
|
||||
let (the_kind, val_opt) = adt::trans_switch(bcx, repr, val);
|
||||
kind = the_kind;
|
||||
for val_opt.each |&tval| { test_val = tval; }
|
||||
}
|
||||
lit(_) => {
|
||||
let pty = node_id_type(bcx, pat_id);
|
||||
|
|
@ -1544,11 +1506,12 @@ pub fn compile_submatch(bcx: block,
|
|||
let mut size = 0u;
|
||||
let mut unpacked = ~[];
|
||||
match *opt {
|
||||
var(_, vdef) => {
|
||||
let args = extract_variant_args(opt_cx, pat_id, vdef, val);
|
||||
size = args.vals.len();
|
||||
unpacked = /*bad*/copy args.vals;
|
||||
opt_cx = args.bcx;
|
||||
var(disr_val, ref repr) => {
|
||||
let ExtractedBlock {vals: argvals, bcx: new_bcx} =
|
||||
extract_variant_args(opt_cx, repr, disr_val, val);
|
||||
size = argvals.len();
|
||||
unpacked = argvals;
|
||||
opt_cx = new_bcx;
|
||||
}
|
||||
vec_len_eq(n) | vec_len_ge(n) => {
|
||||
let tail = match *opt {
|
||||
|
|
@ -1757,10 +1720,15 @@ pub fn bind_irrefutable_pat(bcx: block,
|
|||
}
|
||||
ast::pat_enum(_, sub_pats) => {
|
||||
match bcx.tcx().def_map.find(&pat.id) {
|
||||
Some(ast::def_variant(*)) => {
|
||||
let pat_def = ccx.tcx.def_map.get(&pat.id);
|
||||
let vdefs = ast_util::variant_def_ids(pat_def);
|
||||
let args = extract_variant_args(bcx, pat.id, vdefs, val);
|
||||
Some(ast::def_variant(enum_id, var_id)) => {
|
||||
let repr = adt::represent_node(bcx, pat.id);
|
||||
let vinfo = ty::enum_variant_with_id(ccx.tcx,
|
||||
enum_id,
|
||||
var_id);
|
||||
let args = extract_variant_args(bcx,
|
||||
&repr,
|
||||
vinfo.disr_val,
|
||||
val);
|
||||
for sub_pats.each |sub_pat| {
|
||||
for vec::eachi(args.vals) |i, argval| {
|
||||
bcx = bind_irrefutable_pat(bcx,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue