diff options
| author | Marijn Haverbeke <marijnh@gmail.com> | 2011-12-08 11:56:16 +0100 |
|---|---|---|
| committer | Marijn Haverbeke <marijnh@gmail.com> | 2011-12-08 12:03:48 +0100 |
| commit | 9a269a3aa8fe8140ad3f2fc2cfdfd68d6b40ec86 (patch) | |
| tree | efb59785d520476c50204eadce27bfb9128ca512 /src | |
| parent | 8c966b7b18a5529c33dd9766460880bd681ab102 (diff) | |
| download | rust-9a269a3aa8fe8140ad3f2fc2cfdfd68d6b40ec86.tar.gz rust-9a269a3aa8fe8140ad3f2fc2cfdfd68d6b40ec86.zip | |
Allow binding of nested patterns
See src/test/run-pass/nested-patterns.rs for some examples. The syntax is
boundvar@subpattern
Which will match the subpattern as usual, but also bind boundvar to the
whole matched value.
Closes #838
Diffstat (limited to 'src')
| -rw-r--r-- | src/comp/middle/alias.rs | 3 | ||||
| -rw-r--r-- | src/comp/middle/check_alt.rs | 55 | ||||
| -rw-r--r-- | src/comp/middle/resolve.rs | 6 | ||||
| -rw-r--r-- | src/comp/middle/trans.rs | 4 | ||||
| -rw-r--r-- | src/comp/middle/trans_alt.rs | 68 | ||||
| -rw-r--r-- | src/comp/middle/tstate/auxiliary.rs | 2 | ||||
| -rw-r--r-- | src/comp/middle/tstate/collect_locals.rs | 2 | ||||
| -rw-r--r-- | src/comp/middle/tstate/pre_post_conditions.rs | 14 | ||||
| -rw-r--r-- | src/comp/middle/tstate/states.rs | 2 | ||||
| -rw-r--r-- | src/comp/middle/typeck.rs | 8 | ||||
| -rw-r--r-- | src/comp/syntax/ast.rs | 2 | ||||
| -rw-r--r-- | src/comp/syntax/ast_util.rs | 5 | ||||
| -rw-r--r-- | src/comp/syntax/fold.rs | 4 | ||||
| -rw-r--r-- | src/comp/syntax/parse/parser.rs | 11 | ||||
| -rw-r--r-- | src/comp/syntax/print/pprust.rs | 8 | ||||
| -rw-r--r-- | src/comp/syntax/visit.rs | 5 | ||||
| -rw-r--r-- | src/test/run-pass/nested-patterns.rs | 12 |
17 files changed, 132 insertions, 79 deletions
diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index 909e90fd0c6..3d081c143f3 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -585,8 +585,9 @@ fn pattern_roots(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat) &set: [pattern_root]) { alt pat.node { ast::pat_wild. | ast::pat_lit(_) | ast::pat_range(_, _) {} - ast::pat_bind(nm) { + ast::pat_bind(nm, sub) { set += [{id: pat.id, name: nm, mut: mut, span: pat.span}]; + alt sub { some(p) { walk(tcx, mut, p, set); } _ {} } } ast::pat_tag(_, ps) | ast::pat_tup(ps) { for p in ps { walk(tcx, mut, p, set); } diff --git a/src/comp/middle/check_alt.rs b/src/comp/middle/check_alt.rs index 59410cd3ecb..8e83105199a 100644 --- a/src/comp/middle/check_alt.rs +++ b/src/comp/middle/check_alt.rs @@ -2,6 +2,7 @@ import syntax::ast::*; import syntax::ast_util::{variant_def_ids, dummy_sp, compare_lit_exprs, lit_expr_eq}; import syntax::visit; +import std::option::{some, none}; fn check_crate(tcx: ty::ctxt, crate: @crate) { let v = @@ -64,57 +65,58 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool { } alt a.node { - pat_wild. | pat_bind(_) { ret true; } + pat_bind(_, some(p)) { pattern_supersedes(tcx, p, b) } + pat_wild. | pat_bind(_, none.) { true } pat_lit(la) { alt b.node { - pat_lit(lb) { ret lit_expr_eq(la, lb); } - _ { ret false; } + pat_lit(lb) { lit_expr_eq(la, lb) } + _ { false } } } pat_tag(va, suba) { alt b.node { pat_tag(vb, subb) { - ret tcx.def_map.get(a.id) == tcx.def_map.get(b.id) && - patterns_supersede(tcx, suba, subb); + tcx.def_map.get(a.id) == tcx.def_map.get(b.id) && + patterns_supersede(tcx, suba, subb) } - _ { ret false; } + _ { false } } } pat_rec(suba, _) { alt b.node { - pat_rec(subb, _) { ret field_patterns_supersede(tcx, suba, subb); } - _ { ret false; } + pat_rec(subb, _) { field_patterns_supersede(tcx, suba, subb) } + _ { false } } } pat_tup(suba) { alt b.node { - pat_tup(subb) { ret patterns_supersede(tcx, suba, subb); } - _ { ret false; } + pat_tup(subb) { patterns_supersede(tcx, suba, subb) } + _ { false } } } pat_box(suba) { alt b.node { - pat_box(subb) { ret pattern_supersedes(tcx, suba, subb); } - _ { ret pattern_supersedes(tcx, suba, b); } + pat_box(subb) { pattern_supersedes(tcx, suba, subb) } + _ { pattern_supersedes(tcx, suba, b) } } } pat_uniq(suba) { alt b.node { - pat_uniq(subb) { ret pattern_supersedes(tcx, suba, subb); } - _ { ret pattern_supersedes(tcx, suba, b); } + pat_uniq(subb) { pattern_supersedes(tcx, suba, subb) } + _ { pattern_supersedes(tcx, suba, b) } } } pat_range(begina, enda) { alt b.node { pat_lit(lb) { - ret compare_lit_exprs(begina, lb) <= 0 && - compare_lit_exprs(enda, lb) >= 0; + compare_lit_exprs(begina, lb) <= 0 && + compare_lit_exprs(enda, lb) >= 0 } pat_range(beginb, endb) { - ret compare_lit_exprs(begina, beginb) <= 0 && - compare_lit_exprs(enda, endb) >= 0; + compare_lit_exprs(begina, beginb) <= 0 && + compare_lit_exprs(enda, endb) >= 0 } - _ { ret false; } + _ { false } } } } @@ -130,25 +132,26 @@ fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) { fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool { alt pat.node { - pat_wild. | pat_bind(_) { ret false; } - pat_lit(_) { ret true; } - pat_box(sub) { ret is_refutable(tcx, sub); } - pat_uniq(sub) { ret is_refutable(tcx, sub); } + pat_box(sub) | pat_uniq(sub) | pat_bind(_, some(sub)) { + is_refutable(tcx, sub) + } + pat_wild. | pat_bind(_, none.) { false } + pat_lit(_) { true } pat_rec(fields, _) { for field: field_pat in fields { if is_refutable(tcx, field.pat) { ret true; } } - ret false; + false } pat_tup(elts) { for elt in elts { if is_refutable(tcx, elt) { ret true; } } - ret false; + false } pat_tag(_, args) { let vdef = variant_def_ids(tcx.def_map.get(pat.id)); if std::vec::len(ty::tag_variants(tcx, vdef.tg)) != 1u { ret true; } for p: @pat in args { if is_refutable(tcx, p) { ret true; } } - ret false; + false } } } diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 9fdbaaaba79..7ed27f2502d 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -819,7 +819,7 @@ fn lookup_in_ty_params(name: ident, ty_params: [ast::ty_param]) -> fn lookup_in_pat(name: ident, pat: @ast::pat) -> option::t<def_id> { let found = none; ast_util::pat_bindings(pat) {|bound| - let p_name = alt bound.node { ast::pat_bind(n) { n } }; + let p_name = alt bound.node { ast::pat_bind(n, _) { n } }; if str::eq(p_name, name) { found = some(local_def(bound.id)); } }; ret found; @@ -1376,7 +1376,7 @@ fn check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) { fn check_pat(ch: checker, p: @ast::pat) { ast_util::pat_bindings(p) {|p| - let ident = alt p.node { pat_bind(n) { n } }; + let ident = alt p.node { pat_bind(n, _) { n } }; add_name(ch, p.span, ident); }; } @@ -1424,7 +1424,7 @@ fn check_block(e: @env, b: ast::blk, &&x: (), v: vt<()>) { let local_values = checker(*e, "value"); for (_, loc) in locs { ast_util::pat_bindings(loc.node.pat) {|p| - let ident = alt p.node { pat_bind(n) { n } }; + let ident = alt p.node { pat_bind(n, _) { n } }; add_name(local_values, p.span, ident); check_name(values, p.span, ident); }; diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 458266298d4..104085579b5 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -4702,7 +4702,7 @@ fn alloc_ty(cx: @block_ctxt, t: ty::t) -> result { fn alloc_local(cx: @block_ctxt, local: @ast::local) -> @block_ctxt { let t = node_id_type(bcx_ccx(cx), local.node.id); let is_simple = alt local.node.pat.node { - ast::pat_bind(_) { true } _ { false } + ast::pat_bind(_, none.) { true } _ { false } }; // Do not allocate space for locals that can be kept immediate. let ccx = bcx_ccx(cx); @@ -4716,7 +4716,7 @@ fn alloc_local(cx: @block_ctxt, local: @ast::local) -> @block_ctxt { } let r = alloc_ty(cx, t); alt local.node.pat.node { - ast::pat_bind(ident) { + ast::pat_bind(ident, none.) { if bcx_ccx(cx).sess.get_opts().debuginfo { let _: () = str::as_buf(ident, {|buf| llvm::LLVMSetValueName(r.val, buf) diff --git a/src/comp/middle/trans_alt.rs b/src/comp/middle/trans_alt.rs index efbad8d212a..3b729a819e3 100644 --- a/src/comp/middle/trans_alt.rs +++ b/src/comp/middle/trans_alt.rs @@ -88,14 +88,31 @@ type match_branch = id_map: ast_util::pat_id_map}}; type match = [match_branch]; -fn matches_always(p: @ast::pat) -> bool { - ret alt p.node { - ast::pat_wild. { true } - ast::pat_bind(_) { true } - ast::pat_rec(_, _) { true } - ast::pat_tup(_) { true } - _ { false } - }; +fn has_nested_bindings(m: match, col: uint) -> bool { + for br in m { + alt br.pats[col].node { + ast::pat_bind(_, some(_)) { ret true; } + _ {} + } + } + ret false; +} + +fn expand_nested_bindings(m: match, col: uint, val: ValueRef) -> match { + let result = []; + for br in m { + alt br.pats[col].node { + ast::pat_bind(name, some(inner)) { + let pats = vec::slice(br.pats, 0u, col) + [inner] + + vec::slice(br.pats, col + 1u, vec::len(br.pats)); + result += [@{pats: pats, + bound: br.bound + [{ident: name, val: val}] + with *br}]; + } + _ { result += [br]; } + } + } + result } type enter_pat = fn@(@ast::pat) -> option::t<[@ast::pat]>; @@ -109,7 +126,7 @@ fn enter_match(m: match, col: uint, val: ValueRef, e: enter_pat) -> match { vec::slice(br.pats, col + 1u, vec::len(br.pats)); let new_br = @{pats: pats, bound: alt br.pats[col].node { - ast::pat_bind(name) { + ast::pat_bind(name, none.) { br.bound + [{ident: name, val: val}] } _ { br.bound } @@ -123,6 +140,13 @@ fn enter_match(m: match, col: uint, val: ValueRef, e: enter_pat) -> match { } fn enter_default(m: match, col: uint, val: ValueRef) -> match { + fn matches_always(p: @ast::pat) -> bool { + ret alt p.node { + ast::pat_wild. | ast::pat_bind(_, none.) | ast::pat_rec(_, _) | + ast::pat_tup(_) { true } + _ { false } + }; + } fn e(p: @ast::pat) -> option::t<[@ast::pat]> { ret if matches_always(p) { some([]) } else { none }; } @@ -303,18 +327,17 @@ type exit_node = {bound: bind_map, from: BasicBlockRef, to: BasicBlockRef}; type mk_fail = fn@() -> BasicBlockRef; fn pick_col(m: match) -> uint { + fn score(p: @ast::pat) -> uint { + alt p.node { + ast::pat_lit(_) | ast::pat_tag(_, _) | ast::pat_range(_, _) { 1u } + ast::pat_bind(_, some(p)) { score(p) } + _ { 0u } + } + } let scores = vec::init_elt_mut(0u, vec::len(m[0].pats)); for br: match_branch in m { let i = 0u; - for p: @ast::pat in br.pats { - alt p.node { - ast::pat_lit(_) | ast::pat_tag(_, _) | ast::pat_range(_, _) { - scores[i] += 1u; - } - _ { } - } - i += 1u; - } + for p: @ast::pat in br.pats { scores[i] += score(p); i += 1u; } } let max_score = 0u; let best_col = 0u; @@ -368,6 +391,9 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail, let col = pick_col(m); let val = vals[col]; + let m = has_nested_bindings(m, col) ? + expand_nested_bindings(m, col, val) : m; + let vals_left = vec::slice(vals, 0u, col) + vec::slice(vals, col + 1u, vec::len(vals)); @@ -662,7 +688,7 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: @ast::pat, val: ValueRef, make_copy: bool) -> @block_ctxt { let ccx = bcx.fcx.lcx.ccx, bcx = bcx; alt pat.node { - ast::pat_bind(_) { + ast::pat_bind(_, inner) { if make_copy || ccx.copy_map.contains_key(pat.id) { let ty = ty::node_id_to_monotype(ccx.tcx, pat.id); // FIXME: Could constrain pat_bind to make this @@ -676,6 +702,10 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: @ast::pat, val: ValueRef, bcx.fcx.lllocals.insert(pat.id, local_mem(alloc)); trans_common::add_clean(bcx, alloc, ty); } else { bcx.fcx.lllocals.insert(pat.id, local_mem(val)); } + alt inner { + some(pat) { bcx = bind_irrefutable_pat(bcx, pat, val, true); } + _ {} + } } ast::pat_tag(_, sub) { if vec::len(sub) == 0u { ret bcx; } diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 315eac89147..c156bb739ff 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -1048,7 +1048,7 @@ type binding = {lhs: [inst], rhs: option::t<initializer>}; fn local_to_bindings(loc: @local) -> binding { let lhs = []; pat_bindings(loc.node.pat) {|p| - let ident = alt p.node { pat_bind(name) { name } }; + let ident = alt p.node { pat_bind(name, _) { name } }; lhs += [{ident: ident, node: p.id}]; }; {lhs: lhs, rhs: loc.node.init} diff --git a/src/comp/middle/tstate/collect_locals.rs b/src/comp/middle/tstate/collect_locals.rs index f94ef6d220a..e5166a5e6ba 100644 --- a/src/comp/middle/tstate/collect_locals.rs +++ b/src/comp/middle/tstate/collect_locals.rs @@ -12,7 +12,7 @@ type ctxt = {cs: @mutable [sp_constr], tcx: ty::ctxt}; fn collect_local(loc: @local, cx: ctxt, v: visit::vt<ctxt>) { pat_bindings(loc.node.pat) {|p| - let ident = alt p.node { pat_bind(id) { id } }; + let ident = alt p.node { pat_bind(id, _) { id } }; log "collect_local: pushing " + ident;; *cx.cs += [respan(loc.span, ninit(p.id, ident))]; }; diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index d8e57c90986..4e54b405542 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -108,7 +108,7 @@ fn find_pre_post_loop(fcx: fn_ctxt, l: @local, index: @expr, body: blk, find_pre_post_expr(fcx, index); find_pre_post_block(fcx, body); pat_bindings(l.node.pat) {|p| - let ident = alt p.node { pat_bind(id) { id } }; + let ident = alt p.node { pat_bind(id, _) { id } }; let v_init = ninit(p.id, ident); relax_precond_block(fcx, bit_num(fcx, v_init) as node_id, body); // Hack: for-loop index variables are frequently ignored, @@ -579,11 +579,7 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) { /* FIXME: This won't be necessary when typestate works well enough for pat_bindings to return a refinement-typed thing. */ - let ident = alt pat.node { - pat_bind(n) { n } - _ { fcx.ccx.tcx.sess.span_bug(pat.span, - "Impossible LHS"); } - }; + let ident = alt pat.node { pat_bind(n, _) { n } }; alt p { some(p) { copy_in_postcond(fcx, id, @@ -612,14 +608,10 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) { postconds of the RHSs themselves */ pat_bindings(alocal.node.pat) {|pat| alt pat.node { - pat_bind(n) { + pat_bind(n, _) { set_in_postcond(bit_num(fcx, ninit(pat.id, n)), prev_pp); } - _ { - fcx.ccx.tcx.sess.span_bug(pat.span, - "Impossible LHS"); - } } }; copy_pre_post_(fcx.ccx, id, prev_pp.precondition, diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index aa7977d142d..2b47baed9ee 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -206,7 +206,7 @@ fn find_pre_post_state_loop(fcx: fn_ctxt, pres: prestate, l: @local, // in the body let index_post = tritv_clone(expr_poststate(fcx.ccx, index)); pat_bindings(l.node.pat) {|p| - let ident = alt p.node { pat_bind(name) { name } }; + let ident = alt p.node { pat_bind(name, _) { name } }; set_in_poststate_ident(fcx, p.id, ident, index_post); }; diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 3a37072e509..34fc1816c3f 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1178,7 +1178,7 @@ fn gather_locals(ccx: @crate_ctxt, f: ast::_fn, id: ast::node_id, let visit_pat = lambda (p: @ast::pat, &&e: (), v: visit::vt<()>) { alt p.node { - ast::pat_bind(_) { assign(p.id, none); } + ast::pat_bind(_, _) { assign(p.id, none); } _ {/* no-op */ } } visit::visit_pat(p, e, v); @@ -1248,7 +1248,7 @@ fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat, } write::ty_only_fixup(fcx, pat.id, b_ty); } - ast::pat_bind(name) { + ast::pat_bind(name, sub) { let vid = lookup_local(fcx, pat.span, pat.id); let typ = ty::mk_var(fcx.ccx.tcx, vid); typ = demand::simple(fcx, pat.span, expected, typ); @@ -1260,6 +1260,10 @@ fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat, typ = demand::simple(fcx, pat.span, ct, typ); } write::ty_only_fixup(fcx, pat.id, typ); + alt sub { + some(p) { check_pat(fcx, map, p, expected); } + _ {} + } } ast::pat_tag(path, subpats) { // Typecheck the path. diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index be3bf5b5ee0..30acee6dc68 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -92,7 +92,7 @@ type field_pat = {ident: ident, pat: @pat}; tag pat_ { pat_wild; - pat_bind(ident); + pat_bind(ident, option::t<@pat>); pat_tag(@path, [@pat]); pat_rec([field_pat], bool); pat_tup([@pat]); diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index dc1d0e0bbbb..794d4bf5339 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -58,7 +58,7 @@ type pat_id_map = std::map::hashmap<str, node_id>; fn pat_id_map(pat: @pat) -> pat_id_map { let map = std::map::new_str_hash::<node_id>(); pat_bindings(pat) {|bound| - let name = alt bound.node { pat_bind(n) { n } }; + let name = alt bound.node { pat_bind(n, _) { n } }; map.insert(name, bound.id); }; ret map; @@ -67,7 +67,8 @@ fn pat_id_map(pat: @pat) -> pat_id_map { // FIXME: could return a constrained type fn pat_bindings(pat: @pat, it: block(@pat)) { alt pat.node { - pat_bind(_) { it(pat); } + pat_bind(_, option::none.) { it(pat); } + pat_bind(_, option::some(sub)) { it(pat); pat_bindings(sub, it); } pat_tag(_, sub) { for p in sub { pat_bindings(p, it); } } pat_rec(fields, _) { for f in fields { pat_bindings(f.pat, it); } } pat_tup(elts) { for elt in elts { pat_bindings(elt, it); } } diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs index 0e76e9a15d1..ce82c4d7c3b 100644 --- a/src/comp/syntax/fold.rs +++ b/src/comp/syntax/fold.rs @@ -270,7 +270,9 @@ fn noop_fold_arm(a: arm, fld: ast_fold) -> arm { fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ { ret alt p { pat_wild. { p } - pat_bind(ident) { pat_bind(fld.fold_ident(ident)) } + pat_bind(ident, sub) { + pat_bind(fld.fold_ident(ident), option::map(fld.fold_pat, sub)) + } pat_lit(_) { p } pat_tag(pth, pats) { pat_tag(fld.fold_path(pth), vec::map(fld.fold_pat, pats)) diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 2bf7865bf81..5748637fde4 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -1429,10 +1429,9 @@ fn parse_pat(p: parser) -> @ast::pat { if p.get_bad_expr_words().contains_key(fieldname) { p.fatal("found " + fieldname + " in binding position"); } - subpat = - @{id: p.get_id(), - node: ast::pat_bind(fieldname), - span: ast_util::mk_sp(lo, hi)}; + subpat = @{id: p.get_id(), + node: ast::pat_bind(fieldname, none), + span: ast_util::mk_sp(lo, hi)}; } fields += [{ident: fieldname, pat: subpat}]; } @@ -1479,7 +1478,9 @@ fn parse_pat(p: parser) -> @ast::pat { _ { true } } { hi = p.get_hi_pos(); - pat = ast::pat_bind(parse_value_ident(p)); + let name = parse_value_ident(p); + let sub = eat(p, token::AT) ? some(parse_pat(p)) : none; + pat = ast::pat_bind(name, sub); } else { let tag_path = parse_path_and_ty_param_substs(p); hi = tag_path.span.hi; diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index 2bb8463e2b9..ff28edd057a 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -1062,7 +1062,13 @@ fn print_pat(s: ps, &&pat: @ast::pat) { s.ann.pre(ann_node); alt pat.node { ast::pat_wild. { word(s.s, "_"); } - ast::pat_bind(id) { word(s.s, id); } + ast::pat_bind(id, sub) { + word(s.s, id); + alt sub { + some(p) { word(s.s, "@"); print_pat(s, p); } + _ {} + } + } ast::pat_tag(path, args) { print_path(s, path, true); if vec::len(args) > 0u { diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs index be4dbef294b..9e61d82287c 100644 --- a/src/comp/syntax/visit.rs +++ b/src/comp/syntax/visit.rs @@ -159,8 +159,9 @@ fn visit_pat<E>(p: @pat, e: E, v: vt<E>) { 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); } - pat_uniq(inner) { v.visit_pat(inner, e, v); } + pat_box(inner) | pat_uniq(inner) | pat_bind(_, some(inner)) { + v.visit_pat(inner, e, v); + } _ { } } } diff --git a/src/test/run-pass/nested-patterns.rs b/src/test/run-pass/nested-patterns.rs new file mode 100644 index 00000000000..79eb1d40e4d --- /dev/null +++ b/src/test/run-pass/nested-patterns.rs @@ -0,0 +1,12 @@ +fn main() { + alt {a: 10, b: @20} { + x@{a, b: @20} { assert x.a == 10; assert a == 10; } + {b, _} { fail; } + } + let x@{b, _} = {a: 10, b: {mutable c: 20}}; + x.b.c = 30; + assert b.c == 20; + let y@{d, _} = {a: 10, d: {mutable c: 20}}; + y.d.c = 30; + assert d.c == 20; +} |
