Skip to content

Commit 82712be

Browse files
committed
---
yaml --- r: 4884 b: refs/heads/master c: 7d08678 h: refs/heads/master v: v3
1 parent 039bd09 commit 82712be

File tree

10 files changed

+97
-30
lines changed

10 files changed

+97
-30
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: a2466233b4217cc8da4d2ebcd5f7c0b11db5b861
2+
refs/heads/master: 7d08678b740d779d9f0e1e6d15d7cf6ad4e1b57a

trunk/src/comp/middle/check_alt.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ fn check_arms(tcx: &ty::ctxt, arms: &[arm]) {
2222
let reachable = true;
2323
let j = 0;
2424
while j < i {
25-
for prev_pat: @pat in arms[j].pats {
26-
if pattern_supersedes(tcx, prev_pat, arm_pat) {
27-
reachable = false;
25+
if std::option::is_none(arms[j].guard) {
26+
for prev_pat: @pat in arms[j].pats {
27+
if pattern_supersedes(tcx, prev_pat, arm_pat) {
28+
reachable = false;
29+
}
2830
}
2931
}
3032
j += 1;

trunk/src/comp/middle/trans_alt.rs

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,19 @@ fn variant_opt(ccx: &@crate_ctxt, pat_id: ast::node_id) -> opt {
5555
}
5656

5757
type bind_map = [{ident: ast::ident, val: ValueRef}];
58+
fn assoc(key: str, list: &bind_map) -> option::t<ValueRef> {
59+
for elt: {ident: ast::ident, val: ValueRef} in list {
60+
if str::eq(elt.ident, key) { ret some(elt.val); }
61+
}
62+
ret none;
63+
}
64+
5865
type match_branch =
59-
@{pats: [@ast::pat], body: BasicBlockRef, mutable bound: bind_map};
66+
@{pats: [@ast::pat],
67+
bound: bind_map,
68+
data: @{body: BasicBlockRef,
69+
guard: option::t<@ast::expr>,
70+
id_map: ast::pat_id_map}};
6071
type match = [match_branch];
6172

6273
fn matches_always(p: &@ast::pat) -> bool {
@@ -69,27 +80,24 @@ fn matches_always(p: &@ast::pat) -> bool {
6980
};
7081
}
7182

72-
73-
fn bind_for_pat(p: &@ast::pat, br: &match_branch, val: ValueRef) {
74-
alt p.node {
75-
ast::pat_bind(name) { br.bound += [{ident: name, val: val}]; }
76-
_ { }
77-
}
78-
}
79-
8083
type enter_pat = fn(&@ast::pat) -> option::t<[@ast::pat]>;
8184

8285
fn enter_match(m: &match, col: uint, val: ValueRef, e: &enter_pat) -> match {
8386
let result = [];
8487
for br: match_branch in m {
8588
alt e(br.pats[col]) {
8689
some(sub) {
87-
let pats =
88-
vec::slice(br.pats, 0u, col) + sub +
90+
let pats = vec::slice(br.pats, 0u, col) + sub +
8991
vec::slice(br.pats, col + 1u, vec::len(br.pats));
90-
let new_br = @{pats: pats with *br};
92+
let new_br = @{pats: pats,
93+
bound: alt br.pats[col].node {
94+
ast::pat_bind(name) {
95+
br.bound + [{ident: name, val: val}]
96+
}
97+
_ { br.bound }
98+
}
99+
with *br};
91100
result += [new_br];
92-
bind_for_pat(br.pats[col], new_br, val);
93101
}
94102
none. { }
95103
}
@@ -282,8 +290,30 @@ fn compile_submatch(bcx: @block_ctxt, m: &match, vals: [ValueRef],
282290
f: &mk_fail, exits: &mutable [exit_node]) {
283291
if vec::len(m) == 0u { bcx.build.Br(f()); ret; }
284292
if vec::len(m[0].pats) == 0u {
285-
exits += [{bound: m[0].bound, from: bcx.llbb, to: m[0].body}];
286-
bcx.build.Br(m[0].body);
293+
let data = m[0].data;
294+
alt data.guard {
295+
some(e) {
296+
let guard_cx = new_scope_block_ctxt(bcx, "guard");
297+
let next_cx = new_sub_block_ctxt(bcx, "next");
298+
let else_cx = new_sub_block_ctxt(bcx, "else");
299+
bcx.build.Br(guard_cx.llbb);
300+
// Temporarily set bindings. They'll be rewritten to PHI nodes for
301+
// the actual arm block.
302+
for each @{key, val} in data.id_map.items() {
303+
bcx.fcx.lllocals.insert
304+
(val, option::get(assoc(key, m[0].bound)));
305+
}
306+
let {bcx: guard_cx, val: guard_val} =
307+
trans::trans_expr(guard_cx, e);
308+
guard_cx.build.CondBr(guard_val, next_cx.llbb, else_cx.llbb);
309+
compile_submatch(else_cx, vec::slice(m, 1u, vec::len(m)),
310+
vals, f, exits);
311+
bcx = next_cx;
312+
}
313+
_ {}
314+
}
315+
exits += [{bound: m[0].bound, from: bcx.llbb, to: data.body}];
316+
bcx.build.Br(data.body);
287317
ret;
288318
}
289319

@@ -433,13 +463,6 @@ fn compile_submatch(bcx: @block_ctxt, m: &match, vals: [ValueRef],
433463
// Returns false for unreachable blocks
434464
fn make_phi_bindings(bcx: &@block_ctxt, map: &[exit_node],
435465
ids: &ast::pat_id_map) -> bool {
436-
fn assoc(key: str, list: &bind_map) -> option::t<ValueRef> {
437-
for elt: {ident: ast::ident, val: ValueRef} in list {
438-
if str::eq(elt.ident, key) { ret some(elt.val); }
439-
}
440-
ret none;
441-
}
442-
443466
let our_block = bcx.llbb as uint;
444467
let success = true;
445468
for each item: @{key: ast::ident, val: ast::node_id} in ids.items() {
@@ -477,9 +500,14 @@ fn trans_alt(cx: &@block_ctxt, expr: &@ast::expr, arms: &[ast::arm],
477500

478501
for a: ast::arm in arms {
479502
let body = new_scope_block_ctxt(cx, "case_body");
503+
let id_map = ast::pat_id_map(a.pats[0]);
480504
bodies += [body];
481505
for p: @ast::pat in a.pats {
482-
match += [@{pats: [p], body: body.llbb, mutable bound: []}];
506+
match += [@{pats: [p],
507+
bound: [],
508+
data: @{body: body.llbb,
509+
guard: a.guard,
510+
id_map: id_map}}];
483511
}
484512
}
485513

trunk/src/comp/middle/typeck.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,6 +2038,12 @@ fn check_expr_with_unifier(fcx: &@fn_ctxt, expr: &@ast::expr, unify: &unifier,
20382038
let result_ty = next_ty_var(fcx);
20392039
let arm_non_bot = false;
20402040
for arm: ast::arm in arms {
2041+
alt arm.guard {
2042+
some(e) {
2043+
check_expr_with(fcx, e, ty::mk_bool(tcx));
2044+
}
2045+
none. {}
2046+
}
20412047
if !check_block(fcx, arm.body) { arm_non_bot = true; }
20422048
let bty = block_ty(tcx, arm.body);
20432049
result_ty = demand::simple(fcx, arm.body.span, result_ty, bty);

trunk/src/comp/syntax/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ type decl = spanned<decl_>;
267267
268268
tag decl_ { decl_local([@local]); decl_item(@item); }
269269
270-
type arm = {pats: [@pat], body: blk};
270+
type arm = {pats: [@pat], guard: option::t<@expr>, body: blk};
271271
272272
type field_ = {mut: mutability, ident: ident, expr: @expr};
273273

trunk/src/comp/syntax/fold.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,9 @@ fn noop_fold_stmt(s: &stmt_, fld: ast_fold) -> stmt_ {
269269
}
270270

271271
fn noop_fold_arm(a: &arm, fld: ast_fold) -> arm {
272-
ret {pats: vec::map(fld.fold_pat, a.pats), body: fld.fold_block(a.body)};
272+
ret {pats: vec::map(fld.fold_pat, a.pats),
273+
guard: option::map(fld.fold_expr, a.guard),
274+
body: fld.fold_block(a.body)};
273275
}
274276

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

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1360,8 +1360,12 @@ fn parse_alt_expr(p: &parser) -> @ast::expr {
13601360
let arms: [ast::arm] = [];
13611361
while p.peek() != token::RBRACE {
13621362
let pats = parse_pats(p);
1363+
let guard = none;
1364+
if eat_word(p, "when") {
1365+
guard = some(parse_expr(p));
1366+
}
13631367
let blk = parse_block(p);
1364-
arms += [{pats: pats, body: blk}];
1368+
arms += [{pats: pats, guard: guard, body: blk}];
13651369
}
13661370
let hi = p.get_hi_pos();
13671371
p.bump();

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,14 @@ fn print_expr(s: &ps, expr: &@ast::expr) {
905905
print_pat(s, p);
906906
}
907907
space(s.s);
908+
alt arm.guard {
909+
some(e) {
910+
word_space(s, "when");
911+
print_expr(s, e);
912+
space(s.s);
913+
}
914+
none. {}
915+
}
908916
print_possibly_embedded_block(s, arm.body, block_normal,
909917
alt_indent_unit);
910918
}

trunk/src/comp/syntax/visit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ fn visit_expr<E>(ex: &@expr, e: &E, v: &vt<E>) {
332332

333333
fn visit_arm<E>(a: &arm, e: &E, v: &vt<E>) {
334334
for p: @pat in a.pats { v.visit_pat(p, e, v); }
335+
visit_expr_opt(a.guard, e, v);
335336
v.visit_block(a.body, e, v);
336337
}
337338

trunk/src/test/run-pass/guards.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
fn main() {
2+
let a = alt 10 {
3+
x when x < 7 { 1 }
4+
x when x < 11 { 2 }
5+
10 { 3 }
6+
_ { 4 }
7+
};
8+
assert a == 2;
9+
10+
let b = alt {x: 10, y: 20} {
11+
x when x.x < 5 && x.y < 5 { 1 }
12+
{x, y} when x == 10 && y == 20 { 2 }
13+
{x, y} { 3 }
14+
};
15+
assert b == 2;
16+
}

0 commit comments

Comments
 (0)