diff --git a/src/librustsyntax/ast.rs b/src/librustsyntax/ast.rs index ff581b6dbf54..c44de4ed1467 100644 --- a/src/librustsyntax/ast.rs +++ b/src/librustsyntax/ast.rs @@ -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), diff --git a/src/librustsyntax/ext/auto_serialize.rs b/src/librustsyntax/ext/auto_serialize.rs index a6700b566a30..6a361e73b93b 100644 --- a/src/librustsyntax/ext/auto_serialize.rs +++ b/src/librustsyntax/ext/auto_serialize.rs @@ -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)) } }, diff --git a/src/librustsyntax/fold.rs b/src/librustsyntax/fold.rs index 6e4d89eb5c0f..237b45408d99 100644 --- a/src/librustsyntax/fold.rs +++ b/src/librustsyntax/fold.rs @@ -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 = []; diff --git a/src/librustsyntax/parse/parser.rs b/src/librustsyntax/parse/parser.rs index 8340fa2f6e7c..4131d3eca96a 100644 --- a/src/librustsyntax/parse/parser.rs +++ b/src/librustsyntax/parse/parser.rs @@ -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)); } } } diff --git a/src/librustsyntax/print/pprust.rs b/src/librustsyntax/print/pprust.rs index 52673a548ec7..2eec0ac87978 100644 --- a/src/librustsyntax/print/pprust.rs +++ b/src/librustsyntax/print/pprust.rs @@ -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, "{"); diff --git a/src/librustsyntax/visit.rs b/src/librustsyntax/visit.rs index 8aad37788800..e55d291aa533 100644 --- a/src/librustsyntax/visit.rs +++ b/src/librustsyntax/visit.rs @@ -220,7 +220,8 @@ fn visit_pat(p: @pat, e: E, v: vt) { 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(p: @pat, e: E, v: vt) { } 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); } diff --git a/src/rustc/middle/alias.rs b/src/rustc/middle/alias.rs index de591b9cc4e5..f48a38e6a89e 100644 --- a/src/rustc/middle/alias.rs +++ b/src/rustc/middle/alias.rs @@ -600,11 +600,11 @@ fn pattern_roots(tcx: ty::ctxt, mutbl: option, 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, _) { diff --git a/src/rustc/middle/check_alt.rs b/src/rustc/middle/check_alt.rs index 6d5491a09eeb..62b8350bf301 100644 --- a/src/rustc/middle/check_alt.rs +++ b/src/rustc/middle/check_alt.rs @@ -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 } } } diff --git a/src/rustc/middle/pat_util.rs b/src/rustc/middle/pat_util.rs index ebcbbb2359b6..4ecfd343ce97 100644 --- a/src/rustc/middle/pat_util.rs +++ b/src/rustc/middle/pat_util.rs @@ -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(_, _) {} } } diff --git a/src/rustc/middle/trans/alt.rs b/src/rustc/middle/trans/alt.rs index 71aa0c0e9cc5..fa3ac25c796a 100644 --- a/src/rustc/middle/trans/alt.rs +++ b/src/rustc/middle/trans/alt.rs @@ -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); } diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index d13a23fccb97..18997266d81b 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -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: diff --git a/src/test/run-pass/issue-1701.rs b/src/test/run-pass/issue-1701.rs new file mode 100644 index 000000000000..b3b364c80901 --- /dev/null +++ b/src/test/run-pass/issue-1701.rs @@ -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 { + 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"); +} \ No newline at end of file