Skip to content

Commit cb2f43c

Browse files
committed
Stop normalizing patterns
The check for whether a pat_ident is a variant or a binding is simple and fast. Normalizing patterns again and again is slow and error-prone (several places were forgetting to do it).
1 parent a3b655f commit cb2f43c

File tree

15 files changed

+285
-320
lines changed

15 files changed

+285
-320
lines changed

src/comp/middle/alias.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
332332
for a: ast::arm in arms {
333333
let new_bs = sc.bs;
334334
let root_var = path_def_id(cx, root.ex);
335-
let pat_id_map = pat_util::pat_id_map(cx.tcx, a.pats[0]);
335+
let pat_id_map = pat_util::pat_id_map(cx.tcx.def_map, a.pats[0]);
336336
type info = {
337337
id: node_id,
338338
mutable unsafe_tys: [unsafe_ty],
@@ -596,13 +596,15 @@ fn pattern_roots(tcx: ty::ctxt, mutbl: option<unsafe_ty>, pat: @ast::pat)
596596
-> [pattern_root] {
597597
fn walk(tcx: ty::ctxt, mutbl: option<unsafe_ty>, pat: @ast::pat,
598598
&set: [pattern_root]) {
599-
alt normalize_pat(tcx, pat).node {
600-
ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) {}
601-
ast::pat_ident(nm, sub) {
599+
alt pat.node {
600+
ast::pat_ident(nm, sub)
601+
if !pat_util::pat_is_variant(tcx.def_map, pat) {
602602
set += [{id: pat.id, name: path_to_ident(nm), mutbl: mutbl,
603603
span: pat.span}];
604604
alt sub { some(p) { walk(tcx, mutbl, p, set); } _ {} }
605605
}
606+
ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) |
607+
ast::pat_ident(_, _) {}
606608
ast::pat_enum(_, ps) | ast::pat_tup(ps) {
607609
for p in ps { walk(tcx, mutbl, p, set); }
608610
}

src/comp/middle/ast_map.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,25 @@ fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
6262
visit::visit_fn(fk, decl, body, sp, id, cx, v);
6363
}
6464

65-
fn map_local(loc: @local, cx: ctx, v: vt) {
66-
pat_util::pat_bindings(loc.node.pat) {|p_id, _s, _p|
67-
cx.map.insert(p_id, node_local(cx.local_id));
68-
cx.local_id += 1u;
65+
fn number_pat(cx: ctx, pat: @pat) {
66+
pat_util::walk_pat(pat) {|p|
67+
alt p.node {
68+
pat_ident(_, _) {
69+
cx.map.insert(p.id, node_local(cx.local_id));
70+
cx.local_id += 1u;
71+
}
72+
_ {}
73+
}
6974
};
75+
}
76+
77+
fn map_local(loc: @local, cx: ctx, v: vt) {
78+
number_pat(cx, loc.node.pat);
7079
visit::visit_local(loc, cx, v);
7180
}
7281

7382
fn map_arm(arm: arm, cx: ctx, v: vt) {
74-
pat_util::pat_bindings(arm.pats[0]) {|p_id, _s, _p|
75-
cx.map.insert(p_id, node_local(cx.local_id));
76-
cx.local_id += 1u;
77-
};
83+
number_pat(cx, arm.pats[0]);
7884
visit::visit_arm(arm, cx, v);
7985
}
8086

src/comp/middle/check_alt.rs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,18 @@ import middle::ty;
1010
import middle::ty::*;
1111

1212
fn check_crate(tcx: ty::ctxt, crate: @crate) {
13-
let v =
14-
@{visit_expr: bind check_expr(tcx, _, _, _),
15-
visit_local: bind check_local(tcx, _, _, _)
16-
with *visit::default_visitor::<()>()};
17-
visit::visit_crate(*crate, (), visit::mk_vt(v));
13+
visit::visit_crate(*crate, (), visit::mk_vt(@{
14+
visit_expr: bind check_expr(tcx, _, _, _),
15+
visit_local: bind check_local(tcx, _, _, _)
16+
with *visit::default_visitor::<()>()
17+
}));
1818
tcx.sess.abort_if_errors();
1919
}
2020

2121
fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
2222
visit::visit_expr(ex, s, v);
2323
alt ex.node {
2424
expr_alt(scrut, arms, mode) {
25-
let arms = pat_util::normalize_arms(tcx, arms);
2625
check_arms(tcx, arms);
2726
/* Check for exhaustiveness */
2827
if mode == alt_exhaustive {
@@ -66,8 +65,6 @@ fn raw_pat(p: @pat) -> @pat {
6665
}
6766
}
6867

69-
// Precondition: patterns have been normalized
70-
// (not checked statically yet)
7168
fn check_exhaustive(tcx: ty::ctxt, sp: span, pats: [@pat]) {
7269
if pats.len() == 0u {
7370
tcx.sess.span_err(sp, "non-exhaustive patterns");
@@ -216,11 +213,13 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
216213

217214
alt a.node {
218215
pat_ident(_, some(p)) { pattern_supersedes(tcx, p, b) }
219-
pat_wild | pat_ident(_, none) { true }
220-
pat_lit(la) {
221-
alt b.node {
222-
pat_lit(lb) { lit_expr_eq(la, lb) }
223-
_ { false }
216+
pat_wild { true }
217+
pat_ident(_, none) {
218+
let opt_def_a = tcx.def_map.find(a.id);
219+
alt opt_def_a {
220+
some(def_variant(_, _)) { opt_def_a == tcx.def_map.find(b.id) }
221+
// This is a binding
222+
_ { true }
224223
}
225224
}
226225
pat_enum(va, suba) {
@@ -256,6 +255,12 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
256255
_ { pattern_supersedes(tcx, suba, b) }
257256
}
258257
}
258+
pat_lit(la) {
259+
alt b.node {
260+
pat_lit(lb) { lit_expr_eq(la, lb) }
261+
_ { false }
262+
}
263+
}
259264
pat_range(begina, enda) {
260265
alt b.node {
261266
pat_lit(lb) {
@@ -281,12 +286,19 @@ fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) {
281286
}
282287

283288
fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool {
284-
alt normalize_pat(tcx, pat).node {
289+
alt tcx.def_map.find(pat.id) {
290+
some(def_variant(enum_id, var_id)) {
291+
if vec::len(*ty::enum_variants(tcx, enum_id)) != 1u { ret true; }
292+
}
293+
_ {}
294+
}
295+
296+
alt pat.node {
285297
pat_box(sub) | pat_uniq(sub) | pat_ident(_, some(sub)) {
286298
is_refutable(tcx, sub)
287299
}
288300
pat_wild | pat_ident(_, none) { false }
289-
pat_lit(_) { true }
301+
pat_lit(_) | pat_range(_, _) { true }
290302
pat_rec(fields, _) {
291303
for it: field_pat in fields {
292304
if is_refutable(tcx, it.pat) { ret true; }
@@ -298,12 +310,9 @@ fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool {
298310
false
299311
}
300312
pat_enum(_, args) {
301-
let vdef = variant_def_ids(tcx.def_map.get(pat.id));
302-
if vec::len(*ty::enum_variants(tcx, vdef.enm)) != 1u { ret true; }
303313
for p: @pat in args { if is_refutable(tcx, p) { ret true; } }
304314
false
305315
}
306-
pat_range(_, _) { true }
307316
}
308317
}
309318

src/comp/middle/pat_util.rs

Lines changed: 42 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -5,115 +5,66 @@ import syntax::fold;
55
import syntax::fold::*;
66
import syntax::codemap::span;
77

8-
export normalize_arms;
9-
export normalize_pat;
10-
export normalize_pat_def_map;
11-
export pat_binding_ids;
12-
export pat_bindings;
13-
export pat_id_map;
8+
export walk_pat;
9+
export pat_binding_ids, pat_bindings, pat_id_map;
10+
export pat_is_variant;
1411
export path_to_ident;
1512

16-
fn normalize_pat_def_map(dm: resolve::def_map, p: @pat) -> @pat {
17-
// have to do it the hard way b/c ast fold doesn't pass around
18-
// node IDs. bother.
19-
alt p.node {
20-
pat_wild { p }
21-
pat_ident(_, none) { normalize_one(dm, p) }
22-
pat_ident(q, some(r)) {
23-
@{node: pat_ident(q, some(normalize_pat_def_map(dm, r)))
24-
with *p}
25-
}
26-
pat_enum(a_path, subs) {
27-
@{node: pat_enum(a_path,
28-
vec::map(subs, {|p| normalize_pat_def_map(dm, p)})) with *p}
29-
}
30-
pat_rec(field_pats, b) {
31-
@{node: pat_rec(vec::map(field_pats,
32-
{|fp| {pat: normalize_pat_def_map(dm, fp.pat) with fp}}), b)
33-
with *p}
34-
}
35-
pat_tup(subs) {
36-
@{node: pat_tup(vec::map(subs, {|p| normalize_pat_def_map(dm, p)}))
37-
with *p}
38-
}
39-
pat_box(q) {
40-
@{node: pat_box(normalize_pat_def_map(dm, q))
41-
with *p}
42-
}
43-
pat_uniq(q) {
44-
@{node: pat_uniq(normalize_pat_def_map(dm, q))
45-
with *p}
46-
}
47-
pat_lit(_) { p }
48-
pat_range(_,_) { p }
49-
}
50-
}
51-
52-
fn normalize_one(dm: resolve::def_map, p: @pat) -> @pat {
53-
alt dm.find(p.id) {
54-
some(d) {
55-
alt p.node {
56-
pat_ident(enum_path, _) { @{id: p.id,
57-
node: pat_enum(enum_path, []),
58-
span: p.span} }
59-
_ { p }
60-
}
61-
}
62-
none { p }
63-
}
64-
}
65-
66-
fn normalize_pat(tcx: ty::ctxt, p: @pat) -> @pat {
67-
normalize_pat_def_map(tcx.def_map, p)
68-
}
69-
70-
fn normalize_arms(tcx: ty::ctxt, arms:[arm]) -> [arm] {
71-
vec::map(arms, {|a|
72-
{pats:
73-
vec::map(a.pats, {|p|
74-
pat_util::normalize_pat(tcx, p)})
75-
with a}})
76-
}
77-
7813
type pat_id_map = std::map::hashmap<str, node_id>;
7914

8015
// This is used because same-named variables in alternative patterns need to
8116
// use the node_id of their namesake in the first pattern.
82-
fn pat_id_map(tcx: ty::ctxt, pat: @pat) -> pat_id_map {
83-
let map = std::map::new_str_hash::<node_id>();
84-
pat_bindings(normalize_pat(tcx, pat)) {|p_id, _s, n|
17+
fn pat_id_map(dm: resolve::def_map, pat: @pat) -> pat_id_map {
18+
let map = std::map::new_str_hash();
19+
pat_bindings(dm, pat) {|p_id, _s, n|
8520
map.insert(path_to_ident(n), p_id);
8621
};
8722
ret map;
8823
}
8924

25+
fn pat_is_variant(dm: resolve::def_map, pat: @pat) -> bool {
26+
alt pat.node {
27+
pat_enum(_, _) { true }
28+
pat_ident(_, none) {
29+
alt dm.find(pat.id) {
30+
some(def_variant(_, _)) { true }
31+
_ { false }
32+
}
33+
}
34+
_ { false }
35+
}
36+
}
37+
9038
// This does *not* normalize. The pattern should be already normalized
9139
// if you want to get a normalized pattern out of it.
9240
// Could return a constrained type in order to express that (future work)
93-
fn pat_bindings(pat: @pat, it: fn(node_id, span, @path)) {
94-
alt pat.node {
95-
pat_ident(pth, option::none) { it(pat.id, pat.span, pth); }
96-
pat_ident(pth, option::some(sub)) { it(pat.id, pat.span, pth);
97-
pat_bindings(sub, it); }
98-
pat_enum(_, sub) { for p in sub { pat_bindings(p, it); } }
99-
pat_rec(fields, _) { for f in fields { pat_bindings(f.pat, it); } }
100-
pat_tup(elts) { for elt in elts { pat_bindings(elt, it); } }
101-
pat_box(sub) { pat_bindings(sub, it); }
102-
pat_uniq(sub) { pat_bindings(sub, it); }
103-
pat_wild | pat_lit(_) | pat_range(_, _) { }
41+
fn pat_bindings(dm: resolve::def_map, pat: @pat,
42+
it: fn(node_id, span, @path)) {
43+
walk_pat(pat) {|p|
44+
alt p.node {
45+
pat_ident(pth, _) if !pat_is_variant(dm, p) {
46+
it(p.id, p.span, pth);
47+
}
48+
_ {}
49+
}
10450
}
10551
}
10652

107-
fn pat_binding_ids(pat: @pat) -> [node_id] {
53+
fn walk_pat(pat: @pat, it: fn(@pat)) {
54+
it(pat);
55+
alt pat.node {
56+
pat_ident(pth, some(p)) { walk_pat(p, it); }
57+
pat_rec(fields, _) { for f in fields { walk_pat(f.pat, it); } }
58+
pat_enum(_, s) | pat_tup(s) { for p in s { walk_pat(p, it); } }
59+
pat_box(s) | pat_uniq(s) { walk_pat(s, it); }
60+
pat_wild | pat_lit(_) | pat_range(_, _) | pat_ident(_, none) {}
61+
}
62+
}
63+
64+
fn pat_binding_ids(dm: resolve::def_map, pat: @pat) -> [node_id] {
10865
let found = [];
109-
pat_bindings(pat) {|b_id, _sp, _pt| found += [b_id]; };
66+
pat_bindings(dm, pat) {|b_id, _sp, _pt| found += [b_id]; };
11067
ret found;
11168
}
11269

113-
fn path_to_ident(p: @path) -> ident {
114-
alt vec::last(p.node.idents) {
115-
none { // sigh
116-
fail "Malformed path"; }
117-
some(i) { ret i; }
118-
}
119-
}
70+
fn path_to_ident(p: @path) -> ident { vec::last_total(p.node.idents) }

src/comp/middle/resolve.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ fn visit_local_with_scope(e: @env, loc: @local, sc:scopes, v:vt<scopes>) {
624624
// a single identifier unambiguous (does the pattern "foo" refer
625625
// to enum foo, or is it binding a new name foo?)
626626
alt loc.node.pat.node {
627-
pat_ident(an_ident,_) {
627+
pat_ident(an_ident, _) {
628628
// Be sure to pass ns_an_enum to lookup_in_scope so that
629629
// if this is a name that's being shadowed, we don't die
630630
alt lookup_in_scope(*e, sc, loc.span,
@@ -1139,8 +1139,7 @@ fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param])
11391139
fn lookup_in_pat(e: env, name: ident, pat: @ast::pat) -> option<def_id> {
11401140
let found = none;
11411141

1142-
pat_util::pat_bindings(normalize_pat_def_map(e.def_map, pat))
1143-
{|p_id, _sp, n|
1142+
pat_util::pat_bindings(e.def_map, pat) {|p_id, _sp, n|
11441143
if str::eq(path_to_ident(n), name)
11451144
{ found = some(local_def(p_id)); }
11461145
};
@@ -1776,7 +1775,7 @@ fn check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) {
17761775
}
17771776

17781777
fn check_pat(e: @env, ch: checker, p: @ast::pat) {
1779-
pat_util::pat_bindings(normalize_pat_def_map(e.def_map, p)) {|_i, p_sp, n|
1778+
pat_util::pat_bindings(e.def_map, p) {|_i, p_sp, n|
17801779
add_name(ch, p_sp, path_to_ident(n));
17811780
};
17821781
}
@@ -1823,13 +1822,12 @@ fn check_block(e: @env, b: ast::blk, &&x: (), v: vt<()>) {
18231822
ast::decl_local(locs) {
18241823
let local_values = checker(*e, "value");
18251824
for loc in locs {
1826-
pat_util::pat_bindings
1827-
(normalize_pat_def_map(e.def_map, loc.node.pat))
1828-
{|_i, p_sp, n|
1829-
let ident = path_to_ident(n);
1830-
add_name(local_values, p_sp, ident);
1831-
check_name(values, p_sp, ident);
1832-
};
1825+
pat_util::pat_bindings(e.def_map, loc.node.pat)
1826+
{|_i, p_sp, n|
1827+
let ident = path_to_ident(n);
1828+
add_name(local_values, p_sp, ident);
1829+
check_name(values, p_sp, ident);
1830+
};
18331831
}
18341832
}
18351833
ast::decl_item(it) {

0 commit comments

Comments
 (0)