Add new syntax for patterns that match the head constructor only

Adds a new kind of pattern C(*) where C is a constructor that may
have any number of fields. This pattern matches any value
constructed with C, without binding names for any of the fields.

Closes #1701.
This commit is contained in:
Tim Chevalier
2012-04-20 00:54:42 -07:00
parent 087b12ac29
commit 37b0549730
12 changed files with 105 additions and 44 deletions

View File

@@ -600,11 +600,11 @@ fn pattern_roots(tcx: ty::ctxt, mutbl: option<unsafe_ty>, pat: @ast::pat)
if !pat_util::pat_is_variant(tcx.def_map, pat) {
set += [{id: pat.id, name: path_to_ident(nm), mutbl: mutbl,
span: pat.span}];
alt sub { some(p) { walk(tcx, mutbl, p, set); } _ {} }
option::iter(sub) {|p| walk(tcx, mutbl, p, set); };
}
ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) |
ast::pat_ident(_, _) {}
ast::pat_enum(_, ps) | ast::pat_tup(ps) {
ast::pat_ident(_, _) | ast::pat_enum(_, none) {}
ast::pat_enum(_, some(ps)) | ast::pat_tup(ps) {
for ps.each {|p| walk(tcx, mutbl, p, set); }
}
ast::pat_rec(fs, _) {

View File

@@ -3,6 +3,7 @@ import syntax::ast::*;
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 syntax::print::pprust::pat_to_str;
import pat_util::*;
import syntax::visit;
import driver::session::session;
@@ -166,13 +167,22 @@ fn check_exhaustive_enum(tcx: ty::ctxt, enum_id: def_id, sp: span,
def_variant(_, id) {
let variant_idx =
option::get(vec::position(*variants, {|v| v.id == id}));
let arg_len = variants[variant_idx].args.len();
columns_by_variant[variant_idx].seen = true;
alt pat.node {
pat_enum(_, args) {
pat_enum(_, some(args)) {
vec::iteri(args) {|i, p|
columns_by_variant[variant_idx].cols[i] += [p];
}
}
pat_enum(_, none) {
/* (*) pattern -- we fill in n '_' patterns, if the variant
has n args */
let wild_pat = @{id: tcx.sess.next_node_id(),
node: pat_wild, span: pat.span};
uint::range(0u, arg_len) {|i|
columns_by_variant[variant_idx].cols[i] += [wild_pat]};
}
_ {}
}
}
@@ -225,9 +235,12 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
}
pat_enum(va, suba) {
alt b.node {
pat_enum(vb, subb) {
pat_enum(vb, some(subb)) {
tcx.def_map.get(a.id) == tcx.def_map.get(b.id) &&
patterns_supersede(tcx, suba, subb)
alt suba { none { true }
some(subaa) {
patterns_supersede(tcx, subaa, subb)
}}
}
_ { false }
}
@@ -310,10 +323,11 @@ fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool {
for elts.each {|elt| if is_refutable(tcx, elt) { ret true; } }
false
}
pat_enum(_, args) {
for args.each {|p| if is_refutable(tcx, p) { ret true; } }
pat_enum(_, some(args)) {
for args.each {|p| if is_refutable(tcx, p) { ret true; } };
false
}
pat_enum(_,_) { false }
}
}

View File

@@ -56,9 +56,10 @@ fn walk_pat(pat: @pat, it: fn(@pat)) {
alt pat.node {
pat_ident(pth, some(p)) { walk_pat(p, it); }
pat_rec(fields, _) { for fields.each {|f| walk_pat(f.pat, it); } }
pat_enum(_, s) | pat_tup(s) { for s.each {|p| walk_pat(p, it); } }
pat_enum(_, some(s)) | pat_tup(s) { for s.each {|p| walk_pat(p, it); } }
pat_box(s) | pat_uniq(s) { walk_pat(s, it); }
pat_wild | pat_lit(_) | pat_range(_, _) | pat_ident(_, none) {}
pat_wild | pat_lit(_) | pat_range(_, _) | pat_ident(_, _)
| pat_enum(_, _) {}
}
}

View File

@@ -163,7 +163,8 @@ fn enter_opt(tcx: ty::ctxt, m: match, opt: opt, col: uint,
enter_match(tcx.def_map, m, col, val) {|p|
alt p.node {
ast::pat_enum(_, subpats) {
if opt_eq(tcx, variant_opt(tcx, p.id), opt) { some(subpats) }
if opt_eq(tcx, variant_opt(tcx, p.id), opt) {
some(option::get_or_default(subpats, [])) }
else { none }
}
ast::pat_ident(_, none) if pat_is_variant(tcx.def_map, p) {
@@ -700,16 +701,15 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
let vdefs = ast_util::variant_def_ids(ccx.tcx.def_map.get(pat.id));
let args = extract_variant_args(bcx, pat.id, vdefs, val);
let mut i = 0;
for vec::each(args.vals) {|argval|
option::iter(sub) {|sub| for vec::each(args.vals) {|argval|
bcx = bind_irrefutable_pat(bcx, sub[i], argval, make_copy);
i += 1;
}
}}
}
ast::pat_rec(fields, _) {
let rec_fields = ty::get_fields(node_id_type(bcx, pat.id));
for vec::each(fields) {|f|
let ix = option::get(ty::field_idx(f.ident, rec_fields));
// how to get rid of this check?
let fldptr = GEPi(bcx, val, [0, ix as int]);
bcx = bind_irrefutable_pat(bcx, f.pat, fldptr, make_copy);
}

View File

@@ -2046,7 +2046,7 @@ fn universally_quantify_before_call(fcx: @fn_ctxt,
}
fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
subpats: [@ast::pat], expected: ty::t) {
subpats: option<[@ast::pat]>, expected: ty::t) {
// Typecheck the path.
let fcx = pcx.fcx;
@@ -2075,8 +2075,9 @@ fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
tcx, v_def_ids.enm, v_def_ids.var);
vinfo.args.map { |t| ty::subst(tcx, expected_substs, t) }
};
let subpats_len = subpats.len(), arg_len = arg_types.len();
let arg_len = arg_types.len(), subpats_len = alt subpats {
none { arg_len }
some(ps) { ps.len() }};
if arg_len > 0u {
// N-ary variant.
if arg_len != subpats_len {
@@ -2089,9 +2090,11 @@ fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
tcx.sess.span_fatal(pat.span, s);
}
vec::iter2(subpats, arg_types) {|subpat, arg_ty|
check_pat(pcx, subpat, arg_ty);
}
option::iter(subpats) {|pats|
vec::iter2(pats, arg_types) {|subpat, arg_ty|
check_pat(pcx, subpat, arg_ty);
}
};
} else if subpats_len > 0u {
tcx.sess.span_fatal
(pat.span, #fmt["this pattern has %u field%s, \
@@ -2159,8 +2162,8 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
_ {}
}
}
ast::pat_ident(path, _) {
check_pat_variant(pcx, pat, path, [], expected);
ast::pat_ident(path, c) {
check_pat_variant(pcx, pat, path, some([]), expected);
}
ast::pat_enum(path, subpats) {
check_pat_variant(pcx, pat, path, subpats, expected);
@@ -3885,7 +3888,7 @@ fn check_enum_variants(ccx: @crate_ctxt,
}) {
ccx.tcx.sess.span_err(sp, "illegal recursive enum type. \
wrap the inner value in a box to \
make it represenable");
make it representable");
}
// Check that it is possible to instantiate this enum: