diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2012-10-24 18:47:59 -0700 |
|---|---|---|
| committer | Patrick Walton <pcwalton@mimiga.net> | 2012-10-25 13:59:10 -0700 |
| commit | 57cd6b3e3f0fc3d1805a167dfa2b4d5afc2f43a5 (patch) | |
| tree | 3f707466cbd8e540a73a711faf78e3b2c980516c /src/rustc | |
| parent | 65ee0e1dedf76a49de03e7ecb5eed03d47d54a5e (diff) | |
| download | rust-57cd6b3e3f0fc3d1805a167dfa2b4d5afc2f43a5.tar.gz rust-57cd6b3e3f0fc3d1805a167dfa2b4d5afc2f43a5.zip | |
rustc: Translate and check exhaustiveness of struct-like enum variant patterns. r=nmatsakis
Diffstat (limited to 'src/rustc')
| -rw-r--r-- | src/rustc/middle/check_alt.rs | 57 | ||||
| -rw-r--r-- | src/rustc/middle/pat_util.rs | 2 | ||||
| -rw-r--r-- | src/rustc/middle/trans/alt.rs | 66 |
3 files changed, 105 insertions, 20 deletions
diff --git a/src/rustc/middle/check_alt.rs b/src/rustc/middle/check_alt.rs index fc040ecc4cd..7ed7829cf34 100644 --- a/src/rustc/middle/check_alt.rs +++ b/src/rustc/middle/check_alt.rs @@ -234,8 +234,14 @@ fn pat_ctor_id(tcx: ty::ctxt, p: @pat) -> Option<ctor> { pat_range(lo, hi) => { Some(range(eval_const_expr(tcx, lo), eval_const_expr(tcx, hi))) } - pat_box(_) | pat_uniq(_) | pat_rec(_, _) | pat_tup(_) | pat_region(*) | pat_struct(*) => { + match tcx.def_map.find(pat.id) { + Some(def_variant(_, id)) => Some(variant(id)), + _ => Some(single) + } + } + pat_box(_) | pat_uniq(_) | pat_rec(_, _) | pat_tup(_) | + pat_region(*) => { Some(single) } } @@ -366,25 +372,44 @@ fn specialize(tcx: ty::ctxt, r: ~[@pat], ctor_id: ctor, arity: uint, Some(vec::append(args, vec::tail(r))) } pat_struct(_, flds, _) => { - // Grab the class data that we care about. - let class_fields, class_id; - match ty::get(left_ty).sty { - ty::ty_class(cid, _) => { - class_id = cid; - class_fields = ty::lookup_class_fields(tcx, class_id); + // Is this a struct or an enum variant? + match tcx.def_map.get(r0.id) { + def_variant(_, variant_id) => { + if variant(variant_id) == ctor_id { + // XXX: Is this right? --pcw + let args = flds.map(|ty_f| { + match vec::find(flds, |f| f.ident == ty_f.ident) { + Some(f) => f.pat, + _ => wild() + } + }); + Some(vec::append(args, vec::tail(r))) + } else { + None + } } _ => { - tcx.sess.span_bug(r0.span, ~"struct pattern didn't resolve \ - to a struct"); + // Grab the class data that we care about. + let class_fields, class_id; + match ty::get(left_ty).sty { + ty::ty_class(cid, _) => { + class_id = cid; + class_fields = ty::lookup_class_fields(tcx, class_id); + } + _ => { + tcx.sess.span_bug(r0.span, ~"struct pattern didn't \ + resolve to a struct"); + } + } + let args = vec::map(class_fields, |class_field| { + match vec::find(flds, |f| f.ident == class_field.ident ) { + Some(f) => f.pat, + _ => wild() + } + }); + Some(vec::append(args, vec::tail(r))) } } - let args = vec::map(class_fields, |class_field| { - match vec::find(flds, |f| f.ident == class_field.ident ) { - Some(f) => f.pat, - _ => wild() - } - }); - Some(vec::append(args, vec::tail(r))) } pat_tup(args) => Some(vec::append(args, vec::tail(r))), pat_box(a) | pat_uniq(a) | pat_region(a) => diff --git a/src/rustc/middle/pat_util.rs b/src/rustc/middle/pat_util.rs index 006065988b9..48ebda9a67e 100644 --- a/src/rustc/middle/pat_util.rs +++ b/src/rustc/middle/pat_util.rs @@ -24,7 +24,7 @@ fn pat_id_map(dm: resolve::DefMap, pat: @pat) -> PatIdMap { fn pat_is_variant(dm: resolve::DefMap, pat: @pat) -> bool { match pat.node { pat_enum(_, _) => true, - pat_ident(_, _, None) => match dm.find(pat.id) { + pat_ident(_, _, None) | pat_struct(*) => match dm.find(pat.id) { Some(def_variant(_, _)) => true, _ => false }, diff --git a/src/rustc/middle/trans/alt.rs b/src/rustc/middle/trans/alt.rs index c1b499567ed..b3776e49994 100644 --- a/src/rustc/middle/trans/alt.rs +++ b/src/rustc/middle/trans/alt.rs @@ -369,6 +369,30 @@ fn enter_default(bcx: block, dm: DefMap, m: &[@Match/&r], } } +// <pcwalton> nmatsakis: what does enter_opt do? +// <pcwalton> in trans/alt +// <pcwalton> trans/alt.rs is like stumbling around in a dark cave +// <nmatsakis> pcwalton: the enter family of functions adjust the set of +// patterns as needed +// <nmatsakis> yeah, at some point I kind of achieved some level of +// understanding +// <nmatsakis> anyhow, they adjust the patterns given that something of that +// kind has been found +// <nmatsakis> pcwalton: ok, right, so enter_XXX() adjusts the patterns, as I +// said +// <nmatsakis> enter_match() kind of embodies the generic code +// <nmatsakis> it is provided with a function that tests each pattern to see +// if it might possibly apply and so forth +// <nmatsakis> so, if you have a pattern like {a: _, b: _, _} and one like _ +// <nmatsakis> then _ would be expanded to (_, _) +// <nmatsakis> one spot for each of the sub-patterns +// <nmatsakis> enter_opt() is one of the more complex; it covers the fallible +// cases +// <nmatsakis> enter_rec_or_struct() or enter_tuple() are simpler, since they +// are infallible patterns +// <nmatsakis> so all patterns must either be records (resp. tuples) or +// wildcards + fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint, variant_size: uint, val: ValueRef) -> ~[@Match/&r] @@ -406,6 +430,35 @@ fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint, ast::pat_range(l1, l2) => { 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) { + // Look up the struct variant ID. + let struct_id; + match tcx.def_map.get(p.id) { + ast::def_variant(_, found_struct_id) => { + struct_id = found_struct_id; + } + _ => { + tcx.sess.span_bug(p.span, ~"expected enum \ + variant def"); + } + } + + // Reorder the patterns into the same order they were + // specified in the struct definition. Also fill in + // unspecified fields with dummy. + let reordered_patterns = dvec::DVec(); + for ty::lookup_class_fields(tcx, struct_id).each |field| { + match field_pats.find(|p| p.ident == field.ident) { + None => reordered_patterns.push(dummy), + Some(fp) => reordered_patterns.push(fp.pat) + } + } + Some(dvec::unwrap(move reordered_patterns)) + } else { + None + } + } _ => { assert_is_binding_or_wild(bcx, p); Some(vec::from_elem(variant_size, dummy)) @@ -599,12 +652,19 @@ fn extract_variant_args(bcx: block, pat_id: ast::node_id, return {vals: args, bcx: bcx}; } -fn collect_record_or_struct_fields(m: &[@Match], col: uint) -> ~[ast::ident] { +// NB: This function does not collect fields from struct-like enum variants. +fn collect_record_or_struct_fields(bcx: block, m: &[@Match], col: uint) -> + ~[ast::ident] { let mut fields: ~[ast::ident] = ~[]; for vec::each(m) |br| { match br.pats[col].node { ast::pat_rec(fs, _) => extend(&mut fields, fs), - ast::pat_struct(_, fs, _) => extend(&mut fields, fs), + ast::pat_struct(_, fs, _) => { + match ty::get(node_id_type(bcx, br.pats[col].id)).sty { + ty::ty_class(*) => extend(&mut fields, fs), + _ => () + } + } _ => () } } @@ -939,7 +999,7 @@ fn compile_submatch(bcx: block, root_pats_as_necessary(bcx, m, col, val); - let rec_fields = collect_record_or_struct_fields(m, col); + let rec_fields = collect_record_or_struct_fields(bcx, m, col); if rec_fields.len() > 0 { let pat_ty = node_id_type(bcx, pat_id); do expr::with_field_tys(tcx, pat_ty, None) |_has_dtor, field_tys| { |
