Skip to content

Commit c3bc8fa

Browse files
committed
Allow omission of the '.' after nullary tag patterns
This commit allows patterns like: alt x { some(_) { ... } none { } } without the '.' after none. The parser suspends judgment about whether a bare ident is a tag or a new bound variable; instead, the resolver disambiguates. This means that any code after resolution that pattern-matches on patterns needs to call pat_util::normalize_pat, which consults an environment to do this disambiguation. In addition, local variables are no longer allowed to shadow tag names, so this required changing some code (e.g. renaming variables named "mut", and renaming ast::sub to subtract). The parser currently accepts patterns with and without the '.'. Once the compiler and libraries are changed, it will no longer accept the '.'.
1 parent a7bd817 commit c3bc8fa

25 files changed

+405
-190
lines changed

src/comp/middle/alias.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import std::list;
99
import option::{some, none, is_none};
1010
import list::list;
1111
import driver::session::session;
12+
import pat_util::*;
1213

1314
// This is not an alias-analyser (though it would merit from becoming one, or
1415
// getting input from one, to be more precise). It is a pass that checks
@@ -323,7 +324,7 @@ fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
323324
for a: ast::arm in arms {
324325
let new_bs = sc.bs;
325326
let root_var = path_def_id(cx, root.ex);
326-
let pat_id_map = ast_util::pat_id_map(a.pats[0]);
327+
let pat_id_map = pat_util::pat_id_map(cx.tcx, a.pats[0]);
327328
type info = {
328329
id: node_id,
329330
mutable unsafe_tys: [unsafe_ty],
@@ -588,10 +589,11 @@ fn pattern_roots(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat)
588589
-> [pattern_root] {
589590
fn walk(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat,
590591
&set: [pattern_root]) {
591-
alt pat.node {
592+
alt normalize_pat(tcx, pat).node {
592593
ast::pat_wild. | ast::pat_lit(_) | ast::pat_range(_, _) {}
593-
ast::pat_bind(nm, sub) {
594-
set += [{id: pat.id, name: nm, mut: mut, span: pat.span}];
594+
ast::pat_ident(nm, sub) {
595+
set += [{id: pat.id, name: path_to_ident(nm), mut: mut,
596+
span: pat.span}];
595597
alt sub { some(p) { walk(tcx, mut, p, set); } _ {} }
596598
}
597599
ast::pat_tag(_, ps) | ast::pat_tup(ps) {

src/comp/middle/ast_map.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ fn map_fn(cx: ctx, _fk: visit::fn_kind, decl: fn_decl, _body: blk,
4444
}
4545

4646
fn map_local(cx: ctx, loc: @local) {
47-
ast_util::pat_bindings(loc.node.pat) {|p|
47+
pat_util::pat_bindings(loc.node.pat) {|p|
4848
cx.map.insert(p.id, node_local(cx.local_id));
4949
cx.local_id += 1u;
5050
};
5151
}
5252

5353
fn map_arm(cx: ctx, arm: arm) {
54-
ast_util::pat_bindings(arm.pats[0]) {|p|
54+
pat_util::pat_bindings(arm.pats[0]) {|p|
5555
cx.map.insert(p.id, node_local(cx.local_id));
5656
cx.local_id += 1u;
5757
};

src/comp/middle/check_alt.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import syntax::ast::*;
22
import syntax::ast_util::{variant_def_ids, dummy_sp, compare_lit_exprs,
33
lit_expr_eq};
4+
import pat_util::*;
45
import syntax::visit;
56
import option::{some, none};
67
import driver::session::session;
@@ -16,7 +17,12 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
1617

1718
fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
1819
visit::visit_expr(ex, s, v);
19-
alt ex.node { expr_alt(_, arms) { check_arms(tcx, arms); } _ { } }
20+
alt ex.node {
21+
expr_alt(_, arms) {
22+
check_arms(tcx, pat_util::normalize_arms(tcx, arms));
23+
}
24+
_ { }
25+
}
2026
}
2127

2228
fn check_arms(tcx: ty::ctxt, arms: [arm]) {
@@ -66,8 +72,8 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
6672
}
6773

6874
alt a.node {
69-
pat_bind(_, some(p)) { pattern_supersedes(tcx, p, b) }
70-
pat_wild. | pat_bind(_, none.) { true }
75+
pat_ident(_, some(p)) { pattern_supersedes(tcx, p, b) }
76+
pat_wild. | pat_ident(_, none.) { true }
7177
pat_lit(la) {
7278
alt b.node {
7379
pat_lit(lb) { lit_expr_eq(la, lb) }
@@ -132,11 +138,11 @@ fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) {
132138
}
133139

134140
fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool {
135-
alt pat.node {
136-
pat_box(sub) | pat_uniq(sub) | pat_bind(_, some(sub)) {
141+
alt normalize_pat(tcx, pat).node {
142+
pat_box(sub) | pat_uniq(sub) | pat_ident(_, some(sub)) {
137143
is_refutable(tcx, sub)
138144
}
139-
pat_wild. | pat_bind(_, none.) { false }
145+
pat_wild. | pat_ident(_, none.) { false }
140146
pat_lit(_) { true }
141147
pat_rec(fields, _) {
142148
for field: field_pat in fields {

src/comp/middle/debuginfo.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import middle::trans_build::B;
88
import middle::ty;
99
import syntax::{ast, codemap};
1010
import ast::ty;
11+
import pat_util::*;
1112
import util::ppaux::ty_to_str;
1213

1314
export create_local_var;
@@ -629,9 +630,10 @@ fn create_local_var(bcx: @block_ctxt, local: @ast::local)
629630
option::none. {}
630631
}
631632

632-
let name = alt local.node.pat.node {
633-
ast::pat_bind(ident, _) { ident /*XXX deal w/ optional node binding*/ }
634-
};
633+
let name = path_to_ident(alt pat_util::normalize_pat(bcx_tcx(bcx),
634+
local.node.pat).node {
635+
ast::pat_ident(ident, _) { ident /*XXX deal w/ optional node binding*/ }
636+
});
635637
let loc = codemap::lookup_char_pos(cx.sess.codemap,
636638
local.span.lo);
637639
let ty = trans::node_id_type(cx, local.node.id);

src/comp/middle/pat_util.rs

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import syntax::ast::*;
2+
import syntax::ast_util;
3+
import syntax::ast_util::respan;
4+
import syntax::fold;
5+
import syntax::fold::*;
6+
7+
export normalize_arms;
8+
export normalize_pat;
9+
export normalize_pat_def_map;
10+
export pat_binding_ids;
11+
export pat_bindings;
12+
export pat_id_map;
13+
export path_to_ident;
14+
15+
fn normalize_pat_def_map(dm: resolve::def_map, p: @pat) -> @pat {
16+
// have to do it the hard way b/c ast fold doesn't pass around
17+
// node IDs. bother.
18+
alt p.node {
19+
pat_wild. { p }
20+
pat_ident(_, none.) { normalize_one(dm, p) }
21+
pat_ident(q, some(r)) {
22+
@{node: pat_ident(q, some(normalize_pat_def_map(dm, r)))
23+
with *p}
24+
}
25+
pat_tag(a_path, subs) {
26+
@{node: pat_tag(a_path,
27+
vec::map(subs, {|p| normalize_pat_def_map(dm, p)})) with *p}
28+
}
29+
pat_rec(field_pats, b) {
30+
@{node: pat_rec(vec::map(field_pats,
31+
{|fp| {pat: normalize_pat_def_map(dm, fp.pat) with fp}}), b)
32+
with *p}
33+
}
34+
pat_tup(subs) {
35+
@{node: pat_tup(vec::map(subs, {|p| normalize_pat_def_map(dm, p)}))
36+
with *p}
37+
}
38+
pat_box(q) {
39+
@{node: pat_box(normalize_pat_def_map(dm, q))
40+
with *p}
41+
}
42+
pat_uniq(q) {
43+
@{node: pat_uniq(normalize_pat_def_map(dm, q))
44+
with *p}
45+
}
46+
pat_lit(_) { p }
47+
pat_range(_,_) { p }
48+
}
49+
}
50+
51+
fn normalize_one(dm: resolve::def_map, p: @pat) -> @pat {
52+
alt dm.find(p.id) {
53+
some(d) {
54+
alt p.node {
55+
pat_ident(tag_path, _) { @{id: p.id,
56+
node: pat_tag(tag_path, []),
57+
span: p.span} }
58+
_ { p }
59+
}
60+
}
61+
none. { p }
62+
}
63+
}
64+
65+
fn normalize_pat(tcx: ty::ctxt, p: @pat) -> @pat {
66+
normalize_pat_def_map(tcx.def_map, p)
67+
}
68+
69+
fn normalize_arms(tcx: ty::ctxt, arms:[arm]) -> [arm] {
70+
vec::map(arms, {|a|
71+
{pats:
72+
vec::map(a.pats, {|p|
73+
pat_util::normalize_pat(tcx, p)})
74+
with a}})
75+
}
76+
77+
type pat_id_map = std::map::hashmap<str, node_id>;
78+
79+
// This is used because same-named variables in alternative patterns need to
80+
// use the node_id of their namesake in the first pattern.
81+
fn pat_id_map(tcx: ty::ctxt, pat: @pat) -> pat_id_map {
82+
let map = std::map::new_str_hash::<node_id>();
83+
pat_bindings(normalize_pat(tcx, pat)) {|bound|
84+
let name = path_to_ident(alt bound.node
85+
{ pat_ident(n, _) { n } });
86+
map.insert(name, bound.id);
87+
};
88+
ret map;
89+
}
90+
91+
// This does *not* normalize. The pattern should be already normalized
92+
// if you want to get a normalized pattern out of it.
93+
// Could return a constrained type in order to express that (future work)
94+
fn pat_bindings(pat: @pat, it: block(@pat)) {
95+
alt pat.node {
96+
pat_ident(_, option::none.) { it(pat); }
97+
pat_ident(_, option::some(sub)) { it(pat); pat_bindings(sub, it); }
98+
pat_tag(_, 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(_, _) { }
104+
}
105+
}
106+
107+
fn pat_binding_ids(pat: @pat) -> [node_id] {
108+
let found = [];
109+
pat_bindings(pat) {|b| found += [b.id]; };
110+
ret found;
111+
}
112+
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+
}

0 commit comments

Comments
 (0)