diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 2db3cae74e33..e3f719229aff 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -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, 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, +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,