mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-02 19:06:05 +00:00
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:
parent
087b12ac29
commit
37b0549730
@ -148,7 +148,8 @@ enum pat_ {
|
||||
// records this pattern's node_id in an auxiliary
|
||||
// set (of "pat_idents that refer to nullary enums")
|
||||
pat_ident(@path, option<@pat>),
|
||||
pat_enum(@path, [@pat]),
|
||||
pat_enum(@path, option<[@pat]>), // "none" means a * pattern where
|
||||
// we don't bind the fields to names
|
||||
pat_rec([field_pat], bool),
|
||||
pat_tup([@pat]),
|
||||
pat_box(@pat),
|
||||
|
@ -779,7 +779,7 @@ fn ser_enum(cx: ext_ctxt, tps: ser_tps_map, e_name: str,
|
||||
if vec::is_empty(pats) {
|
||||
ast::pat_ident(cx.path(v_span, [v_name]), none)
|
||||
} else {
|
||||
ast::pat_enum(cx.path(v_span, [v_name]), pats)
|
||||
ast::pat_enum(cx.path(v_span, [v_name]), some(pats))
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -348,7 +348,8 @@ fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ {
|
||||
}
|
||||
pat_lit(e) { pat_lit(fld.fold_expr(e)) }
|
||||
pat_enum(pth, pats) {
|
||||
pat_enum(fld.fold_path(pth), vec::map(pats, fld.fold_pat))
|
||||
pat_enum(fld.fold_path(pth), option::map(pats)
|
||||
{|pats| vec::map(pats, fld.fold_pat)})
|
||||
}
|
||||
pat_rec(fields, etc) {
|
||||
let mut fs = [];
|
||||
|
@ -1417,24 +1417,38 @@ fn parse_pat(p: parser) -> @ast::pat {
|
||||
} else {
|
||||
let enum_path = parse_path_and_ty_param_substs(p, true);
|
||||
hi = enum_path.span.hi;
|
||||
let mut args: [@ast::pat];
|
||||
let mut args: [@ast::pat] = [];
|
||||
let mut star_pat = false;
|
||||
alt p.token {
|
||||
token::LPAREN {
|
||||
let a =
|
||||
parse_seq(token::LPAREN, token::RPAREN,
|
||||
seq_sep(token::COMMA), parse_pat, p);
|
||||
args = a.node;
|
||||
hi = a.span.hi;
|
||||
alt p.look_ahead(1u) {
|
||||
token::BINOP(token::STAR) {
|
||||
// This is a "top constructor only" pat
|
||||
p.bump(); p.bump();
|
||||
star_pat = true;
|
||||
expect(p, token::RPAREN);
|
||||
}
|
||||
_ {
|
||||
let a =
|
||||
parse_seq(token::LPAREN, token::RPAREN,
|
||||
seq_sep(token::COMMA), parse_pat, p);
|
||||
args = a.node;
|
||||
hi = a.span.hi;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ { args = []; }
|
||||
_ { }
|
||||
}
|
||||
// at this point, we're not sure whether it's a enum or a bind
|
||||
if vec::len(args) == 0u &&
|
||||
if star_pat {
|
||||
pat = ast::pat_enum(enum_path, none);
|
||||
}
|
||||
else if vec::is_empty(args) &&
|
||||
vec::len(enum_path.node.idents) == 1u {
|
||||
pat = ast::pat_ident(enum_path, none);
|
||||
}
|
||||
else {
|
||||
pat = ast::pat_enum(enum_path, args);
|
||||
pat = ast::pat_enum(enum_path, some(args));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1248,16 +1248,21 @@ fn print_pat(s: ps, &&pat: @ast::pat) {
|
||||
print_path(s, path, true);
|
||||
alt sub {
|
||||
some(p) { word(s.s, "@"); print_pat(s, p); }
|
||||
_ {}
|
||||
none {}
|
||||
}
|
||||
}
|
||||
ast::pat_enum(path, args) {
|
||||
ast::pat_enum(path, args_) {
|
||||
print_path(s, path, true);
|
||||
if vec::len(args) > 0u {
|
||||
popen(s);
|
||||
commasep(s, inconsistent, args, print_pat);
|
||||
pclose(s);
|
||||
} else { }
|
||||
alt args_ {
|
||||
none { word(s.s, "(*)"); }
|
||||
some(args) {
|
||||
if vec::len(args) > 0u {
|
||||
popen(s);
|
||||
commasep(s, inconsistent, args, print_pat);
|
||||
pclose(s);
|
||||
} else { }
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::pat_rec(fields, etc) {
|
||||
word(s.s, "{");
|
||||
|
@ -220,7 +220,8 @@ fn visit_pat<E>(p: @pat, e: E, v: vt<E>) {
|
||||
alt p.node {
|
||||
pat_enum(path, children) {
|
||||
visit_path(path, e, v);
|
||||
for children.each {|child| v.visit_pat(child, e, v); }
|
||||
option::iter(children) {|children|
|
||||
for children.each {|child| v.visit_pat(child, e, v); }}
|
||||
}
|
||||
pat_rec(fields, _) {
|
||||
for fields.each {|f| v.visit_pat(f.pat, e, v); }
|
||||
@ -231,7 +232,7 @@ fn visit_pat<E>(p: @pat, e: E, v: vt<E>) {
|
||||
}
|
||||
pat_ident(path, inner) {
|
||||
visit_path(path, e, v);
|
||||
option::iter(inner, {|subpat| v.visit_pat(subpat, e, v)});
|
||||
option::iter(inner) {|subpat| v.visit_pat(subpat, e, v)};
|
||||
}
|
||||
pat_lit(ex) { v.visit_expr(ex, e, v); }
|
||||
pat_range(e1, e2) { v.visit_expr(e1, e, v); v.visit_expr(e2, e, v); }
|
||||
|
@ -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, _) {
|
||||
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(_, _) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
21
src/test/run-pass/issue-1701.rs
Normal file
21
src/test/run-pass/issue-1701.rs
Normal file
@ -0,0 +1,21 @@
|
||||
enum pattern { tabby, tortoiseshell, calico }
|
||||
enum breed { beagle, rottweiler, pug }
|
||||
type name = str;
|
||||
enum ear_kind { lop, upright }
|
||||
enum animal { cat(pattern), dog(breed), rabbit(name, ear_kind), tiger }
|
||||
|
||||
fn noise(a: animal) -> option<str> {
|
||||
alt a {
|
||||
cat(*) { some("meow") }
|
||||
dog(*) { some("woof") }
|
||||
rabbit(*) { none }
|
||||
tiger(*) { some("roar") }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert noise(cat(tabby)) == some("meow");
|
||||
assert noise(dog(pug)) == some("woof");
|
||||
assert noise(rabbit("Hilbert", upright)) == none;
|
||||
assert noise(tiger) == some("roar");
|
||||
}
|
Loading…
Reference in New Issue
Block a user