Skip to content

Commit beab6ba

Browse files
committed
Add a pass that checks for unreachable alt arms
1 parent bd81ada commit beab6ba

File tree

5 files changed

+115
-2
lines changed

5 files changed

+115
-2
lines changed

src/comp/driver/rustc.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ fn compile_input(session::session sess, ast::crate_cfg cfg, str input,
138138
auto ty_cx = ty::mk_ctxt(sess, d, ast_map, freevars);
139139
time[()](time_passes, "typechecking",
140140
bind typeck::check_crate(ty_cx, crate));
141+
time[()](time_passes, "alt checking",
142+
bind middle::check_alt::check_crate(ty_cx, crate));
141143
if (sess.get_opts().run_typestate) {
142144
time(time_passes, "typestate checking",
143145
bind middle::tstate::ck::check_crate(ty_cx, crate));

src/comp/middle/check_alt.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import syntax::ast::*;
2+
import syntax::visit;
3+
4+
fn check_crate(&ty::ctxt tcx, &@crate crate) {
5+
auto v = @rec(visit_expr=bind check_expr(tcx, _, _, _)
6+
with *visit::default_visitor[()]());
7+
visit::visit_crate(*crate, (), visit::mk_vt(v));
8+
tcx.sess.abort_if_errors();
9+
}
10+
11+
fn check_expr(&ty::ctxt tcx, &@expr ex, &() s, &visit::vt[()] v) {
12+
visit::visit_expr(ex, s, v);
13+
alt ex.node {
14+
expr_alt(_, ?arms) { check_arms(tcx, arms); }
15+
_ {}
16+
}
17+
}
18+
19+
fn check_arms(&ty::ctxt tcx, &arm[] arms) {
20+
auto i = 0;
21+
for (arm arm in arms) {
22+
for (@pat arm_pat in arm.pats) {
23+
auto reachable = true;
24+
auto j = 0;
25+
while j < i {
26+
for (@pat prev_pat in arms.(j).pats) {
27+
if pattern_supersedes(tcx, prev_pat, arm_pat) {
28+
reachable = false;
29+
}
30+
}
31+
j += 1;
32+
}
33+
if !reachable {
34+
tcx.sess.span_err(arm_pat.span, "unreachable pattern");
35+
}
36+
}
37+
i += 1;
38+
}
39+
}
40+
41+
fn pattern_supersedes(&ty::ctxt tcx, &@pat a, &@pat b) -> bool {
42+
fn patterns_supersede(&ty::ctxt tcx, &(@pat)[] as, &(@pat)[] bs) -> bool {
43+
auto i = 0;
44+
for (@pat a in as) {
45+
if !pattern_supersedes(tcx, a, bs.(i)) { ret false; }
46+
i += 1;
47+
}
48+
ret true;
49+
}
50+
fn field_patterns_supersede(&ty::ctxt tcx, &field_pat[] fas,
51+
&field_pat[] fbs) -> bool {
52+
auto wild = @rec(id=0, node=pat_wild, span=rec(lo=0u, hi=0u));
53+
for (field_pat fa in fas) {
54+
auto pb = wild;
55+
for (field_pat fb in fbs) {
56+
if fa.ident == fb.ident { pb = fb.pat; }
57+
}
58+
if !pattern_supersedes(tcx, fa.pat, pb) { ret false; }
59+
}
60+
ret true;
61+
}
62+
63+
alt a.node {
64+
pat_wild | pat_bind(_) { ret true; }
65+
pat_lit(?la) {
66+
alt b.node {
67+
pat_lit(?lb) { ret util::common::lit_eq(la, lb); }
68+
_ { ret false; }
69+
}
70+
}
71+
pat_tag(?va, ?suba) {
72+
alt b.node {
73+
pat_tag(?vb, ?subb) {
74+
ret tcx.def_map.get(a.id) == tcx.def_map.get(b.id) &&
75+
patterns_supersede(tcx, suba, subb);
76+
}
77+
_ { ret false; }
78+
}
79+
}
80+
pat_rec(?suba, _) {
81+
alt b.node {
82+
pat_rec(?subb, _) { ret field_patterns_supersede(tcx, suba, subb); }
83+
_ { ret false; }
84+
}
85+
}
86+
pat_box(?suba) {
87+
alt b.node {
88+
pat_box(?subb) { ret pattern_supersedes(tcx, suba, subb); }
89+
_ { ret pattern_supersedes(tcx, suba, b); }
90+
}
91+
}
92+
}
93+
}
94+
95+
// Local Variables:
96+
// mode: rust
97+
// fill-column: 78;
98+
// indent-tabs-mode: nil
99+
// c-basic-offset: 4
100+
// buffer-file-coding-system: utf-8-unix
101+
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
102+
// End:

src/comp/middle/ty.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,8 +1254,6 @@ fn type_owns_heap_mem(&ctxt cx, &t ty) -> bool {
12541254
case (ty_port(_)) { result = false; }
12551255
case (ty_chan(_)) { result = false; }
12561256
case (ty_task) { result = false; }
1257-
case (ty_tup(_)) { result = false; }
1258-
case (ty_rec(_)) { result = false; }
12591257
case (ty_var(_)) { fail "ty_var in type_owns_heap_mem"; }
12601258
case (ty_param(_)) { result = false; }
12611259
}

src/comp/rustc.rc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ mod middle {
2525
mod ast_map;
2626
mod resolve;
2727
mod typeck;
28+
mod check_alt;
2829
mod alias;
2930
mod freevars;
3031

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// error-pattern:unreachable pattern
2+
3+
tag foo { a(@foo, int); b(uint); }
4+
5+
fn main() {
6+
alt b(1u) {
7+
b(_) | a(@_, 1) {}
8+
a(_, 1) {}
9+
}
10+
}

0 commit comments

Comments
 (0)