Skip to content

Commit c487f0e

Browse files
committed
---
yaml --- r: 3793 b: refs/heads/master c: 86ee345 h: refs/heads/master i: 3791: 3ac8aa5 v: v3
1 parent f6601f0 commit c487f0e

File tree

14 files changed

+169
-41
lines changed

14 files changed

+169
-41
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: 4d325b1a15126c6aa9f97d510a11d93d4ac2ad53
2+
refs/heads/master: 86ee3454a1e49b0b913f37c2c52e79d68cae5410

trunk/src/comp/middle/alias.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ fn arm_defnums(&ast::arm arm) -> vec[node_id] {
300300
case (_) { }
301301
}
302302
}
303-
walk_pat(dnums, arm.pat);
303+
walk_pat(dnums, arm.pats.(0));
304304
ret dnums;
305305
}
306306

trunk/src/comp/middle/resolve.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ fn resolve_names(&@env e, &@ast::crate c) {
288288
c.node.path.node.idents, ns_value));
289289
}
290290
fn walk_arm(@env e, &ast::arm a, &scopes sc, &vt[scopes] v) {
291-
walk_pat(*e, sc, a.pat);
291+
for (@ast::pat p in a.pats) { walk_pat(*e, sc, p); }
292292
visit_arm_with_scope(a, sc, v);
293293
}
294294
fn walk_pat(&env e, &scopes sc, &@ast::pat pat) {
@@ -648,7 +648,7 @@ fn lookup_in_scope(&env e, scopes sc, &span sp, &ident name, namespace ns) ->
648648
}
649649
case (scope_block(?b)) { ret lookup_in_block(name, b.node, ns); }
650650
case (scope_arm(?a)) {
651-
if (ns == ns_value) { ret lookup_in_pat(name, *a.pat); }
651+
if (ns == ns_value) { ret lookup_in_pat(name, *a.pats.(0)); }
652652
}
653653
}
654654
ret none[def];
@@ -1264,7 +1264,32 @@ fn check_arm(@env e, &ast::arm a, &() x, &vt[()] v) {
12641264
case (_) { }
12651265
}
12661266
}
1267-
walk_pat(checker(*e, "binding"), a.pat);
1267+
auto ch0 = checker(*e, "binding");
1268+
walk_pat(ch0, a.pats.(0));
1269+
auto seen0 = ch0.seen;
1270+
auto i = ivec::len(a.pats);
1271+
while (i > 1u) {
1272+
i -= 1u;
1273+
auto ch = checker(*e, "binding");
1274+
walk_pat(ch, a.pats.(i));
1275+
// Ensure the bindings introduced in this pattern are the same as in
1276+
// the first pattern.
1277+
if (vec::len(ch.seen) != vec::len(seen0)) {
1278+
e.sess.span_err(a.pats.(i).span,
1279+
"inconsistent number of bindings");
1280+
} else {
1281+
for (ident name in ch.seen) {
1282+
if (option::is_none(vec::find(bind str::eq(name, _),
1283+
seen0))) {
1284+
// Fight the alias checker
1285+
auto name_ = name;
1286+
e.sess.span_err
1287+
(a.pats.(i).span, "binding " + name_ +
1288+
" does not occur in first pattern");
1289+
}
1290+
}
1291+
}
1292+
}
12681293
}
12691294

12701295
fn check_block(@env e, &ast::block b, &() x, &vt[()] v) {

trunk/src/comp/middle/trans.rs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4842,8 +4842,10 @@ fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
48424842
}
48434843
}
48444844

4845+
type bind_map = hashmap[ast::ident, result];
4846+
48454847
fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
4846-
bool is_mem) -> result {
4848+
bool is_mem, &bind_map bound) -> result {
48474849
alt (pat.node) {
48484850
case (ast::pat_wild) { ret rslt(cx, llval); }
48494851
case (ast::pat_lit(_)) { ret rslt(cx, llval); }
@@ -4853,8 +4855,9 @@ fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
48534855
val = spill_if_immediate
48544856
(cx, llval, node_id_type(cx.fcx.lcx.ccx, pat.id));
48554857
}
4856-
cx.fcx.lllocals.insert(pat.id, val);
4857-
ret rslt(cx, val);
4858+
auto r = rslt(cx, val);
4859+
bound.insert(name, r);
4860+
ret r;
48584861
}
48594862
case (ast::pat_tag(_, ?subpats)) {
48604863
if (std::ivec::len[@ast::pat](subpats) == 0u) {
@@ -4887,7 +4890,7 @@ fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
48874890
ty_param_substs, i);
48884891
this_cx = rslt.bcx;
48894892
auto subpat_res =
4890-
trans_pat_binding(this_cx, subpat, rslt.val, true);
4893+
trans_pat_binding(this_cx, subpat, rslt.val, true, bound);
48914894
this_cx = subpat_res.bcx;
48924895
i += 1;
48934896
}
@@ -4902,16 +4905,34 @@ fn trans_alt(&@block_ctxt cx, &@ast::expr expr, &ast::arm[] arms,
49024905
auto this_cx = expr_res.bcx;
49034906
let result[] arm_results = ~[];
49044907
for (ast::arm arm in arms) {
4905-
auto next_cx = new_sub_block_ctxt(expr_res.bcx, "next");
4906-
auto match_res =
4907-
trans_pat_match(this_cx, arm.pat, expr_res.val, next_cx);
4908-
auto binding_res =
4909-
trans_pat_binding(match_res.bcx, arm.pat, expr_res.val, false);
4910-
auto block_cx = new_scope_block_ctxt(match_res.bcx, "case block");
4911-
binding_res.bcx.build.Br(block_cx.llbb);
4908+
auto bind_maps = ~[];
4909+
auto block_cx = new_scope_block_ctxt(expr_res.bcx, "case block");
4910+
for (@ast::pat pat in arm.pats) {
4911+
auto next_cx = new_sub_block_ctxt(expr_res.bcx, "next");
4912+
auto match_res =
4913+
trans_pat_match(this_cx, pat, expr_res.val, next_cx);
4914+
auto bind_map = new_str_hash[result]();
4915+
auto binding_res = trans_pat_binding
4916+
(match_res.bcx, pat, expr_res.val, false, bind_map);
4917+
bind_maps += ~[bind_map];
4918+
binding_res.bcx.build.Br(block_cx.llbb);
4919+
this_cx = next_cx;
4920+
}
4921+
// Go over the names and node_ids of the bound variables, add a Phi
4922+
// node for each and register the bindings.
4923+
for each (@tup(ast::ident, ast::node_id) item in
4924+
ast::pat_id_map(arm.pats.(0)).items()) {
4925+
auto vals = ~[]; auto llbbs = ~[];
4926+
for (bind_map map in bind_maps) {
4927+
auto rslt = map.get(item._0);
4928+
vals += ~[rslt.val];
4929+
llbbs += ~[rslt.bcx.llbb];
4930+
}
4931+
auto phi = block_cx.build.Phi(val_ty(vals.(0)), vals, llbbs);
4932+
block_cx.fcx.lllocals.insert(item._1, phi);
4933+
}
49124934
auto block_res = trans_block(block_cx, arm.block, output);
49134935
arm_results += ~[block_res];
4914-
this_cx = next_cx;
49154936
}
49164937
auto default_cx = this_cx;
49174938
trans_fail(default_cx, some[span](expr.span),

trunk/src/comp/middle/typeck.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import driver::session;
1010
import util::common;
1111
import syntax::codemap::span;
1212
import std::map::new_int_hash;
13+
import std::map::new_str_hash;
1314
import util::common::new_def_hash;
1415
import util::common::log_expr_err;
1516
import middle::ty;
@@ -1286,10 +1287,10 @@ fn check_lit(@crate_ctxt ccx, &@ast::lit lit) -> ty::t {
12861287
}
12871288
}
12881289

1289-
12901290
// Pattern checking is top-down rather than bottom-up so that bindings get
12911291
// their types immediately.
1292-
fn check_pat(&@fn_ctxt fcx, &@ast::pat pat, ty::t expected) {
1292+
fn check_pat(&@fn_ctxt fcx, &ast::pat_id_map map, &@ast::pat pat,
1293+
ty::t expected) {
12931294
alt (pat.node) {
12941295
case (ast::pat_wild) {
12951296
write::ty_only_fixup(fcx, pat.id, expected);
@@ -1303,6 +1304,12 @@ fn check_pat(&@fn_ctxt fcx, &@ast::pat pat, ty::t expected) {
13031304
auto vid = lookup_local(fcx, pat.span, pat.id);
13041305
auto typ = ty::mk_var(fcx.ccx.tcx, vid);
13051306
typ = demand::simple(fcx, pat.span, expected, typ);
1307+
auto canon_id = map.get(name);
1308+
if (canon_id != pat.id) {
1309+
auto ct = ty::mk_var(fcx.ccx.tcx,
1310+
lookup_local(fcx, pat.span, canon_id));
1311+
typ = demand::simple(fcx, pat.span, ct, typ);
1312+
}
13061313
write::ty_only_fixup(fcx, pat.id, typ);
13071314
}
13081315
case (ast::pat_tag(?path, ?subpats)) {
@@ -1358,7 +1365,7 @@ fn check_pat(&@fn_ctxt fcx, &@ast::pat pat, ty::t expected) {
13581365

13591366
auto i = 0u;
13601367
for (@ast::pat subpat in subpats) {
1361-
check_pat(fcx, subpat, arg_types.(i));
1368+
check_pat(fcx, map, subpat, arg_types.(i));
13621369
i += 1u;
13631370
}
13641371
} else if (subpats_len > 0u) {
@@ -1884,10 +1891,11 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
18841891
// bindings.
18851892

18861893
auto pattern_ty = ty::expr_ty(fcx.ccx.tcx, expr);
1887-
let vec[@ast::pat] pats = [];
18881894
for (ast::arm arm in arms) {
1889-
check_pat(fcx, arm.pat, pattern_ty);
1890-
pats += [arm.pat];
1895+
auto id_map = ast::pat_id_map(arm.pats.(0));
1896+
for (@ast::pat p in arm.pats) {
1897+
check_pat(fcx, id_map, p, pattern_ty);
1898+
}
18911899
}
18921900
// Now typecheck the blocks.
18931901

trunk/src/comp/syntax/ast.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,25 @@ tag pat_ {
125125
pat_tag(path, (@pat)[]);
126126
}
127127

128+
type pat_id_map = std::map::hashmap[str, ast::node_id];
129+
130+
// This is used because same-named variables in alternative patterns need to
131+
// use the node_id of their namesake in the first pattern.
132+
fn pat_id_map(&@pat pat) -> pat_id_map {
133+
auto map = std::map::new_str_hash[node_id]();
134+
fn walk(&pat_id_map map, &@pat pat) {
135+
alt (pat.node) {
136+
pat_bind(?name) { map.insert(name, pat.id); }
137+
pat_tag(_, ?sub) {
138+
for (@pat p in sub) { walk(map, p); }
139+
}
140+
_ {}
141+
}
142+
}
143+
walk(map, pat);
144+
ret map;
145+
}
146+
128147
tag mutability { mut; imm; maybe_mut; }
129148

130149
tag layer { layer_value; layer_state; layer_gc; }
@@ -227,7 +246,7 @@ type decl = spanned[decl_];
227246
228247
tag decl_ { decl_local(@local); decl_item(@item); }
229248
230-
type arm = rec(@pat pat, block block);
249+
type arm = rec((@pat)[] pats, block block);
231250
232251
type elt = rec(mutability mut, @expr expr);
233252

trunk/src/comp/syntax/fold.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,8 @@ fn noop_fold_stmt(&stmt_ s, ast_fold fld) -> stmt_ {
255255
}
256256

257257
fn noop_fold_arm(&arm a, ast_fold fld) -> arm {
258-
ret rec(pat=fld.fold_pat(a.pat), block=fld.fold_block(a.block));
258+
ret rec(pats=ivec::map(fld.fold_pat, a.pats),
259+
block=fld.fold_block(a.block));
259260
}
260261

261262
fn noop_fold_pat(&pat_ p, ast_fold fld) -> pat_ {

trunk/src/comp/syntax/parse/parser.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,10 +1359,10 @@ fn parse_alt_expr(&parser p) -> @ast::expr {
13591359
eat_word(p, "case");
13601360
auto parens = false;
13611361
if (p.peek() == token::LPAREN) { parens = true; p.bump(); }
1362-
auto pat = parse_pat(p);
1362+
auto pats = parse_pats(p);
13631363
if (parens) { expect(p, token::RPAREN); }
13641364
auto block = parse_block(p);
1365-
arms += ~[rec(pat=pat, block=block)];
1365+
arms += ~[rec(pats=pats, block=block)];
13661366
}
13671367
auto hi = p.get_hi_pos();
13681368
p.bump();
@@ -1405,20 +1405,32 @@ fn parse_initializer(&parser p) -> option::t[ast::initializer] {
14051405
p.bump();
14061406
ret some(rec(op=ast::init_move, expr=parse_expr(p)));
14071407
}
1408-
case (
1409-
// Now that the the channel is the first argument to receive,
1410-
// combining it with an initializer doesn't really make sense.
1411-
// case (token::RECV) {
1412-
// p.bump();
1413-
// ret some(rec(op = ast::init_recv,
1414-
// expr = parse_expr(p)));
1415-
// }
1416-
_) {
1408+
// Now that the the channel is the first argument to receive,
1409+
// combining it with an initializer doesn't really make sense.
1410+
// case (token::RECV) {
1411+
// p.bump();
1412+
// ret some(rec(op = ast::init_recv,
1413+
// expr = parse_expr(p)));
1414+
// }
1415+
case (_) {
14171416
ret none;
14181417
}
14191418
}
14201419
}
14211420

1421+
fn parse_pats(&parser p) -> (@ast::pat)[] {
1422+
auto pats = ~[];
1423+
while (true) {
1424+
pats += ~[parse_pat(p)];
1425+
if (p.peek() == token::BINOP(token::OR)) {
1426+
p.bump();
1427+
} else {
1428+
break;
1429+
}
1430+
}
1431+
ret pats;
1432+
}
1433+
14221434
fn parse_pat(&parser p) -> @ast::pat {
14231435
auto lo = p.get_lo_pos();
14241436
auto hi = p.get_hi_pos();

trunk/src/comp/syntax/print/pprust.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -832,9 +832,12 @@ fn print_expr(&ps s, &@ast::expr expr) {
832832
for (ast::arm arm in arms) {
833833
space(s.s);
834834
head(s, "case");
835-
popen(s);
836-
print_pat(s, arm.pat);
837-
pclose(s);
835+
auto first = true;
836+
for (@ast::pat p in arm.pats) {
837+
if (first) { first = false; }
838+
else { space(s.s); word_space(s, "|"); }
839+
print_pat(s, p);
840+
}
838841
space(s.s);
839842
print_block(s, arm.block);
840843
}

trunk/src/comp/syntax/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ fn visit_expr[E](&@expr ex, &E e, &vt[E] v) {
394394
}
395395

396396
fn visit_arm[E](&arm a, &E e, &vt[E] v) {
397-
vt(v).visit_pat(a.pat, e, v);
397+
for (@pat p in a.pats) { vt(v).visit_pat(p, e, v); }
398398
vt(v).visit_block(a.block, e, v);
399399
}
400400
// Local Variables:

trunk/src/comp/syntax/walk.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ fn walk_expr(&ast_visitor v, @ast::expr e) {
334334
case (ast::expr_alt(?x, ?arms)) {
335335
walk_expr(v, x);
336336
for (ast::arm a in arms) {
337-
walk_pat(v, a.pat);
337+
for (@ast::pat p in a.pats) { walk_pat(v, p); }
338338
v.visit_arm_pre(a);
339339
walk_block(v, a.block);
340340
v.visit_arm_post(a);

trunk/src/lib/ivec.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,15 @@ fn all[T](fn(&T)->bool f, &T[] v) -> bool {
206206
ret true;
207207
}
208208

209+
fn member[T](&T x, &T[] v) -> bool {
210+
for (T elt in v) { if (x == elt) { ret true; } }
211+
ret false;
212+
}
213+
214+
fn find[T](fn(&T) -> bool f, &T[] v) -> option::t[T] {
215+
for (T elt in v) { if (f(elt)) { ret some[T](elt); } }
216+
ret none[T];
217+
}
209218

210219
mod unsafe {
211220
fn copy_from_buf[T](&mutable T[] v, *T ptr, uint count) {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// error-pattern: mismatched types
2+
3+
tag blah {
4+
a(int, int, uint);
5+
b(int, int);
6+
}
7+
8+
fn main() {
9+
alt a(1, 1, 2u) {
10+
a(_, ?x, ?y) | b(?x, ?y) { }
11+
}
12+
}

trunk/src/test/run-pass/or-pattern.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
tag blah {
2+
a(int, int, uint);
3+
b(int, int);
4+
c;
5+
}
6+
7+
fn or_alt(&blah q) -> int {
8+
alt q {
9+
a(?x, ?y, _) | b(?x, ?y) { ret x + y;}
10+
c { ret 0; }
11+
}
12+
}
13+
14+
fn main() {
15+
assert or_alt(c) == 0;
16+
assert or_alt(a(10, 100, 0u)) == 110;
17+
assert or_alt(b(20, 200)) == 220;
18+
}

0 commit comments

Comments
 (0)