diff --git a/src/comp/middle/check_alt.rs b/src/comp/middle/check_alt.rs index b3feeeb3fec..be8a9aba102 100644 --- a/src/comp/middle/check_alt.rs +++ b/src/comp/middle/check_alt.rs @@ -84,6 +84,12 @@ fn pattern_supersedes(tcx: &ty::ctxt, a: &@pat, b: &@pat) -> bool { _ { ret false; } } } + pat_tup(suba) { + alt b.node { + pat_tup(subb) { ret patterns_supersede(tcx, suba, subb); } + _ { ret false; } + } + } pat_box(suba) { alt b.node { pat_box(subb) { ret pattern_supersedes(tcx, suba, subb); } @@ -112,6 +118,12 @@ fn is_refutable(tcx: &ty::ctxt, pat: &@pat) -> bool { } ret false; } + pat_tup(elts) { + for elt in elts { + if is_refutable(tcx, elt) { ret true; } + } + ret false; + } pat_tag(_, args) { let vdef = variant_def_ids(tcx.def_map.get(pat.id)); if std::ivec::len(ty::tag_variants(tcx, vdef.tg)) != 1u { diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index c97c2f9eb0f..9a6a6cb088f 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -644,7 +644,7 @@ fn lookup_in_scope(e: &env, sc: scopes, sp: &span, name: &ident, } scope_loop(local) { if ns == ns_value { - alt lookup_in_pat(name, *local.node.pat) { + alt lookup_in_pat(name, local.node.pat) { some(did) { ret some(ast::def_local(did)); } _ {} } @@ -654,7 +654,7 @@ fn lookup_in_scope(e: &env, sc: scopes, sp: &span, name: &ident, scope_arm(a) { if ns == ns_value { ret option::map(ast::def_binding, - lookup_in_pat(name, *a.pats.(0))); + lookup_in_pat(name, a.pats.(0))); } } } @@ -711,30 +711,15 @@ fn lookup_in_ty_params(name: &ident, ty_params: &[ast::ty_param]) -> ret none[def]; } -fn lookup_in_pat(name: &ident, pat: &ast::pat) -> option::t[def_id] { - alt pat.node { - ast::pat_bind(p_name) { +fn lookup_in_pat(name: &ident, pat: &@ast::pat) -> option::t[def_id] { + let found = none; + for each bound in ast::pat_bindings(pat) { + let p_name = alt bound.node { ast::pat_bind(n) { n } }; if str::eq(p_name, name) { - ret some(local_def(pat.id)); + found = some(local_def(bound.id)); } - } - ast::pat_wild. { } - ast::pat_lit(_) { } - ast::pat_tag(_, pats) { - for p: @ast::pat in pats { - let found = lookup_in_pat(name, *p); - if !is_none(found) { ret found; } - } - } - ast::pat_rec(fields, _) { - for f: ast::field_pat in fields { - let found = lookup_in_pat(name, *f.pat); - if !is_none(found) { ret found; } - } - } - ast::pat_box(inner) { ret lookup_in_pat(name, *inner); } } - ret none; + ret found; } fn lookup_in_fn(name: &ident, decl: &ast::fn_decl, @@ -779,7 +764,7 @@ fn lookup_in_block(name: &ident, b: &ast::blk_, ns: namespace) -> ast::decl_local(locs) { for loc: @ast::local in locs { if ns == ns_value { - alt lookup_in_pat(name, *loc.node.pat) { + alt lookup_in_pat(name, loc.node.pat) { some(did) { ret some(ast::def_local(did)); } _ {} } diff --git a/src/comp/middle/trans_alt.rs b/src/comp/middle/trans_alt.rs index f15922a20fe..b694bbbf614 100644 --- a/src/comp/middle/trans_alt.rs +++ b/src/comp/middle/trans_alt.rs @@ -63,6 +63,7 @@ fn matches_always(p: &@ast::pat) -> bool { ast::pat_wild. { true } ast::pat_bind(_) { true } ast::pat_rec(_, _) { true } + ast::pat_tup(_) { true } _ { false } }; } @@ -145,6 +146,18 @@ fn enter_rec(m: &match, col: uint, fields: &[ast::ident], val: ValueRef) -> ret enter_match(m, col, val, bind e(dummy, fields, _)); } +fn enter_tup(m: &match, col: uint, val: ValueRef, n_elts: uint) -> match { + let dummy = @{id: 0, node: ast::pat_wild, span: {lo: 0u, hi: 0u}}; + fn e(dummy: &@ast::pat, n_elts: uint, p: &@ast::pat) + -> option::t[[@ast::pat]] { + alt p.node { + ast::pat_tup(elts) { ret some(elts); } + _ { ret some(ivec::init_elt(dummy, n_elts)); } + } + } + ret enter_match(m, col, val, bind e(dummy, n_elts, _)); +} + fn enter_box(m: &match, col: uint, val: ValueRef) -> match { let dummy = @{id: 0, node: ast::pat_wild, span: {lo: 0u, hi: 0u}}; fn e(dummy: &@ast::pat, p: &@ast::pat) -> option::t[[@ast::pat]] { @@ -227,6 +240,13 @@ fn any_box_pat(m: &match, col: uint) -> bool { ret false; } +fn any_tup_pat(m: &match, col: uint) -> bool { + for br: match_branch in m { + alt br.pats.(col).node { ast::pat_tup(_) { ret true; } _ { } } + } + ret false; +} + type exit_node = {bound: bind_map, from: BasicBlockRef, to: BasicBlockRef}; type mk_fail = fn() -> BasicBlockRef; @@ -300,6 +320,23 @@ fn compile_submatch(bcx: @block_ctxt, m: &match, vals: [ValueRef], ret; } + if any_tup_pat(m, col) { + let tup_ty = ty::node_id_to_monotype(ccx.tcx, pat_id); + let n_tup_elts = alt ty::struct(ccx.tcx, tup_ty) { + ty::ty_tup(elts) { ivec::len(elts) } + }; + let tup_vals = ~[], i = 0u; + while i < n_tup_elts { + let r = trans::GEP_tup_like(bcx, tup_ty, val, ~[0, i as int]); + tup_vals += ~[r.val]; + bcx = r.bcx; + i += 1u; + } + compile_submatch(bcx, enter_tup(m, col, val, n_tup_elts), + tup_vals + vals_left, f, exits); + ret; + } + // Unbox in case of a box field if any_box_pat(m, col) { let box = bcx.build.Load(val); @@ -518,6 +555,15 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: &@ast::pat, val: ValueRef, bcx = bind_irrefutable_pat(r.bcx, f.pat, r.val, table, copy); } } + ast::pat_tup(elems) { + let tup_ty = ty::node_id_to_monotype(ccx.tcx, pat.id); + let i = 0u; + for elem in elems { + let r = trans::GEP_tup_like(bcx, tup_ty, val, ~[0, i as int]); + bcx = bind_irrefutable_pat(r.bcx, elem, r.val, table, copy); + i += 1u; + } + } ast::pat_box(inner) { let box = bcx.build.Load(val); let unboxed = bcx.build.InBoundsGEP diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 6d10a6adaee..fbb69c226ed 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1454,6 +1454,31 @@ fn check_pat(fcx: &@fn_ctxt, map: &ast::pat_id_map, pat: &@ast::pat, } write::ty_only_fixup(fcx, pat.id, expected); } + ast::pat_tup(elts) { + let ex_elts; + alt structure_of(fcx, pat.span, expected) { + ty::ty_tup(elts) { ex_elts = elts; } + _ { + fcx.ccx.tcx.sess.span_fatal(pat.span, + #fmt("mismatched types: expected %s, \ + found tuple", ty_to_str(fcx.ccx.tcx, + expected))); + } + } + let e_count = ivec::len(elts); + if e_count != ivec::len(ex_elts) { + fcx.ccx.tcx.sess.span_fatal + (pat.span, #fmt("mismatched types: expected a tuple \ + with %u fields, found one with %u \ + fields", ivec::len(ex_elts), e_count)); + } + let i = 0u; + for elt in elts { + check_pat(fcx, map, elt, ex_elts.(i)); + i += 1u; + } + write::ty_only_fixup(fcx, pat.id, expected); + } ast::pat_box(inner) { alt structure_of(fcx, pat.span, expected) { ty::ty_box(e_inner) { diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index bedb2cad64d..d2ad2cd0f08 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -126,6 +126,7 @@ tag pat_ { pat_lit(@lit); pat_tag(path, [@pat]); pat_rec([field_pat], bool); + pat_tup([@pat]); pat_box(@pat); } @@ -135,18 +136,10 @@ type pat_id_map = std::map::hashmap[str, ast::node_id]; // use the node_id of their namesake in the first pattern. fn pat_id_map(pat: &@pat) -> pat_id_map { let map = std::map::new_str_hash[node_id](); - fn walk(map: &pat_id_map, pat: &@pat) { - alt pat.node { - pat_bind(name) { map.insert(name, pat.id); } - pat_tag(_, sub) { for p: @pat in sub { walk(map, p); } } - pat_rec(fields, _) { - for f: field_pat in fields { walk(map, f.pat); } - } - pat_box(inner) { walk(map, inner); } - _ { } - } + for each bound in pat_bindings(pat) { + let name = alt bound.node { pat_bind(n) { n } }; + map.insert(name, bound.id); } - walk(map, pat); ret map; } @@ -163,6 +156,11 @@ iter pat_bindings(pat: &@pat) -> @pat { for each b in pat_bindings(f.pat) { put b; } } } + pat_tup(elts) { + for elt in elts { + for each b in pat_bindings(elt) { put b; } + } + } pat_box(sub) { for each b in pat_bindings(sub) { put b; } } diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs index 177e05fa091..77ec93c809b 100644 --- a/src/comp/syntax/fold.rs +++ b/src/comp/syntax/fold.rs @@ -283,6 +283,9 @@ fn noop_fold_pat(p: &pat_, fld: ast_fold) -> pat_ { } pat_rec(fs, etc) } + pat_tup(elts) { + pat_tup(ivec::map(fld.fold_pat, elts)) + } pat_box(inner) { pat_box(fld.fold_pat(inner)) } }; } diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 8f7dbd184c3..f28ea683cf9 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -1454,6 +1454,24 @@ fn parse_pat(p: &parser) -> @ast::pat { p.bump(); pat = ast::pat_rec(fields, etc); } + token::LPAREN. { + p.bump(); + if p.peek() == token::RPAREN { + hi = p.get_hi_pos(); + p.bump(); + pat = ast::pat_lit(@{node: ast::lit_nil, span: {lo: lo, hi: hi}}); + } else { + let fields = ~[parse_pat(p)]; + while p.peek() == token::COMMA { + p.bump(); + fields += ~[parse_pat(p)]; + } + if ivec::len(fields) == 1u { expect(p, token::COMMA); } + hi = p.get_hi_pos(); + expect(p, token::RPAREN); + pat = ast::pat_tup(fields); + } + } tok { if !is_ident(tok) || is_word(p, "true") || is_word(p, "false") { let lit = parse_lit(p); diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index 569a5ad136a..fa2df63e280 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -1146,6 +1146,11 @@ fn print_pat(s: &ps, pat: &@ast::pat) { } word(s.s, "}"); } + ast::pat_tup(elts) { + popen(s); + commasep(s, inconsistent, elts, print_pat); + pclose(s); + } ast::pat_box(inner) { word(s.s, "@"); print_pat(s, inner); } } s.ann.post(ann_node); diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs index 3fbca6238ee..5f160d88e6f 100644 --- a/src/comp/syntax/visit.rs +++ b/src/comp/syntax/visit.rs @@ -175,6 +175,9 @@ fn visit_pat[E](p: &@pat, e: &E, v: &vt[E]) { pat_rec(fields, _) { for f: field_pat in fields { v.visit_pat(f.pat, e, v); } } + pat_tup(elts) { + for elt in elts { v.visit_pat(elt, e, v); } + } pat_box(inner) { v.visit_pat(inner, e, v); } _ { } }