Skip to content

Commit 7595fe5

Browse files
committed
Implement record patterns
Closes #469.
1 parent 12cb128 commit 7595fe5

File tree

13 files changed

+193
-2
lines changed

13 files changed

+193
-2
lines changed

src/comp/middle/alias.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,9 @@ fn arm_defnums(&ast::arm arm) -> vec[node_id] {
297297
case (ast::pat_tag(_, ?children)) {
298298
for (@ast::pat child in children) { walk_pat(found, child); }
299299
}
300+
case (ast::pat_rec(?fields, _)) {
301+
for (ast::field_pat f in fields) { walk_pat(found, f.pat); }
302+
}
300303
case (_) { }
301304
}
302305
}

src/comp/middle/resolve.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,9 @@ fn resolve_names(&@env e, &@ast::crate c) {
313313
}
314314
}
315315
}
316+
case (ast::pat_rec(?fields, _)) {
317+
for (ast::field_pat f in fields) { walk_pat(e, sc, f.pat); }
318+
}
316319
case (_) { }
317320
}
318321
}
@@ -707,6 +710,12 @@ fn lookup_in_pat(&ident name, &ast::pat pat) -> option::t[def] {
707710
if (!option::is_none(found)) { ret found; }
708711
}
709712
}
713+
case (ast::pat_rec(?fields, _)) {
714+
for (ast::field_pat f in fields) {
715+
auto found = lookup_in_pat(name, *f.pat);
716+
if (!option::is_none(found)) { ret found; }
717+
}
718+
}
710719
}
711720
ret none[def];
712721
}
@@ -1261,6 +1270,9 @@ fn check_arm(@env e, &ast::arm a, &() x, &vt[()] v) {
12611270
case (ast::pat_tag(_, ?children)) {
12621271
for (@ast::pat child in children) { walk_pat(ch, child); }
12631272
}
1273+
case (ast::pat_rec(?fields, _)) {
1274+
for (ast::field_pat f in fields) { walk_pat(ch, f.pat); }
1275+
}
12641276
case (_) { }
12651277
}
12661278
}

src/comp/middle/trans.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4839,6 +4839,23 @@ fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
48394839
}
48404840
ret rslt(matched_cx, llval);
48414841
}
4842+
case (ast::pat_rec(?field_pats, _)) {
4843+
auto bcx = cx;
4844+
auto ccx = cx.fcx.lcx.ccx;
4845+
auto rec_ty = pat_ty(ccx.tcx, pat);
4846+
auto fields = alt (ty::struct(ccx.tcx, rec_ty)) {
4847+
ty::ty_rec(?fields) { fields }
4848+
};
4849+
for (ast::field_pat f in field_pats) {
4850+
let uint ix = ty::field_idx(ccx.sess, f.pat.span,
4851+
f.ident, fields);
4852+
auto r = GEP_tup_like(bcx, rec_ty, llval, ~[0, ix as int]);
4853+
auto v = load_if_immediate(r.bcx, r.val,
4854+
pat_ty(ccx.tcx, f.pat));
4855+
bcx = trans_pat_match(r.bcx, f.pat, v, next_cx).bcx;
4856+
}
4857+
ret rslt(bcx, llval);
4858+
}
48424859
}
48434860
}
48444861

@@ -4896,6 +4913,21 @@ fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, ValueRef llval,
48964913
}
48974914
ret rslt(this_cx, llval);
48984915
}
4916+
case (ast::pat_rec(?field_pats, _)) {
4917+
auto bcx = cx;
4918+
auto ccx = cx.fcx.lcx.ccx;
4919+
auto rec_ty = pat_ty(ccx.tcx, pat);
4920+
auto fields = alt (ty::struct(ccx.tcx, rec_ty)) {
4921+
ty::ty_rec(?fields) { fields }
4922+
};
4923+
for (ast::field_pat f in field_pats) {
4924+
let uint ix = ty::field_idx(ccx.sess, f.pat.span,
4925+
f.ident, fields);
4926+
auto r = GEP_tup_like(bcx, rec_ty, llval, ~[0, ix as int]);
4927+
bcx = trans_pat_binding(bcx, f.pat, r.val, true, bound).bcx;
4928+
}
4929+
ret rslt(bcx, llval);
4930+
}
48994931
}
49004932
}
49014933

src/comp/middle/typeck.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,11 @@ fn replace_expr_type(&@fn_ctxt fcx, &@ast::expr expr,
12781278
write::ty_fixup(fcx, expr.id, tup(new_tps, new_tyt._1));
12791279
}
12801280

1281+
// FIXME remove once std::ivec::find makes it into a snapshot
1282+
fn ivec_find[T](fn(&T) -> bool f, &T[] v) -> option::t[T] {
1283+
for (T elt in v) { if (f(elt)) { ret some[T](elt); } }
1284+
ret none[T];
1285+
}
12811286

12821287
// AST fragment checking
12831288
fn check_lit(@crate_ctxt ccx, &@ast::lit lit) -> ty::t {
@@ -1395,16 +1400,52 @@ fn check_pat(&@fn_ctxt fcx, &ast::pat_id_map map, &@ast::pat pat,
13951400
case (_) {
13961401
// FIXME: Switch expected and actual in this message? I
13971402
// can never tell.
1398-
13991403
fcx.ccx.tcx.sess.span_fatal(pat.span,
14001404
#fmt("mismatched types: \
1401-
expected tag, found %s",
1405+
expected %s, found tag",
14021406
ty_to_str(fcx.ccx.tcx,
14031407
expected)));
14041408
}
14051409
}
14061410
write::ty_fixup(fcx, pat.id, path_tpot);
14071411
}
1412+
case (ast::pat_rec(?fields, ?etc)) {
1413+
auto ex_fields;
1414+
alt (structure_of(fcx, pat.span, expected)) {
1415+
case (ty::ty_rec(?fields)) { ex_fields = fields; }
1416+
case (_) {
1417+
fcx.ccx.tcx.sess.span_fatal
1418+
(pat.span, #fmt("mismatched types: expected %s, \
1419+
found record",
1420+
ty_to_str(fcx.ccx.tcx, expected)));
1421+
}
1422+
};
1423+
auto f_count = ivec::len(fields);
1424+
auto ex_f_count = ivec::len(ex_fields);
1425+
if (ex_f_count < f_count || (!etc && ex_f_count > f_count)) {
1426+
fcx.ccx.tcx.sess.span_fatal
1427+
(pat.span, #fmt("mismatched types: expected a record \
1428+
with %u fields, found one with %u \
1429+
fields", ex_f_count, f_count));
1430+
}
1431+
fn matches(&str name, &ty::field f) -> bool {
1432+
ret str::eq(name, f.ident);
1433+
}
1434+
for (ast::field_pat f in fields) {
1435+
alt (ivec_find(bind matches(f.ident, _), ex_fields)) {
1436+
some(?field) {
1437+
check_pat(fcx, map, f.pat, field.mt.ty);
1438+
}
1439+
none {
1440+
fcx.ccx.tcx.sess.span_fatal
1441+
(pat.span, #fmt("mismatched types: did not \
1442+
expect a record with a field %s",
1443+
f.ident));
1444+
}
1445+
}
1446+
}
1447+
write::ty_only_fixup(fcx, pat.id, expected);
1448+
}
14081449
}
14091450
}
14101451

src/comp/syntax/ast.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,14 @@ type pat = rec(node_id id,
118118
pat_ node,
119119
span span);
120120

121+
type field_pat = rec(ident ident, @pat pat);
122+
121123
tag pat_ {
122124
pat_wild;
123125
pat_bind(ident);
124126
pat_lit(@lit);
125127
pat_tag(path, (@pat)[]);
128+
pat_rec(field_pat[], bool);
126129
}
127130

128131
type pat_id_map = std::map::hashmap[str, ast::node_id];
@@ -137,6 +140,9 @@ fn pat_id_map(&@pat pat) -> pat_id_map {
137140
pat_tag(_, ?sub) {
138141
for (@pat p in sub) { walk(map, p); }
139142
}
143+
pat_rec(?fields, _) {
144+
for (field_pat f in fields) { walk(map, f.pat); }
145+
}
140146
_ {}
141147
}
142148
}

src/comp/syntax/fold.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,13 @@ fn noop_fold_pat(&pat_ p, ast_fold fld) -> pat_ {
267267
case (pat_tag(?pth, ?pats)) {
268268
pat_tag(fld.fold_path(pth), ivec::map(fld.fold_pat, pats))
269269
}
270+
case (pat_rec(?fields, ?etc)) {
271+
auto fs = ~[];
272+
for (ast::field_pat f in fields) {
273+
fs += ~[rec(ident=f.ident, pat=fld.fold_pat(f.pat))];
274+
}
275+
pat_rec(fs, etc)
276+
}
270277
};
271278
}
272279

src/comp/syntax/parse/parser.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,6 +1455,45 @@ fn parse_pat(&parser p) -> @ast::pat {
14551455
}
14561456
}
14571457
}
1458+
case (token::LBRACE) {
1459+
p.bump();
1460+
auto fields = ~[];
1461+
auto etc = false;
1462+
auto first = true;
1463+
while (p.peek() != token::RBRACE) {
1464+
if (p.peek() == token::DOT) {
1465+
p.bump();
1466+
expect(p, token::DOT);
1467+
expect(p, token::DOT);
1468+
if (p.peek() != token::RBRACE) {
1469+
p.fatal("expecting }, found " +
1470+
token::to_str(p.get_reader(), p.peek()));
1471+
}
1472+
etc = true;
1473+
break;
1474+
}
1475+
if (first) { first = false; }
1476+
else { expect(p, token::COMMA); }
1477+
auto fieldname = parse_ident(p);
1478+
auto subpat;
1479+
if (p.peek() == token::COLON) {
1480+
p.bump();
1481+
subpat = parse_pat(p);
1482+
} else {
1483+
if (p.get_bad_expr_words().contains_key(fieldname)) {
1484+
p.fatal("found " + fieldname +
1485+
" in binding position");
1486+
}
1487+
subpat = @rec(id=p.get_id(),
1488+
node=ast::pat_bind(fieldname),
1489+
span=rec(lo=lo, hi=hi));
1490+
}
1491+
fields += ~[rec(ident=fieldname, pat=subpat)];
1492+
}
1493+
hi = p.get_hi_pos();
1494+
p.bump();
1495+
pat = ast::pat_rec(fields, etc);
1496+
}
14581497
case (?tok) {
14591498
if (!is_ident(tok) || is_word(p, "true") || is_word(p, "false")) {
14601499
auto lit = parse_lit(p);

src/comp/syntax/print/pprust.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,22 @@ fn print_pat(&ps s, &@ast::pat pat) {
11201120
pclose(s);
11211121
}
11221122
}
1123+
case (ast::pat_rec(?fields, ?etc)) {
1124+
bopen(s);
1125+
fn print_field(&ps s, &ast::field_pat f) {
1126+
cbox(s, indent_unit);
1127+
word(s.s, f.ident);
1128+
word(s.s, ":");
1129+
print_pat(s, f.pat);
1130+
end(s);
1131+
}
1132+
fn get_span(&ast::field_pat f) -> codemap::span {
1133+
ret f.pat.span;
1134+
}
1135+
commasep_cmnt_ivec(s, consistent, fields, print_field, get_span);
1136+
if (etc) { space(s.s); word(s.s, "..."); }
1137+
bclose(s, pat.span);
1138+
}
11231139
}
11241140
s.ann.post(ann_node);
11251141
}

src/comp/syntax/visit.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ fn visit_pat[E](&@pat p, &E e, &vt[E] v) {
190190
for (@ty tp in path.node.types) { v.visit_ty(tp, e, v); }
191191
for (@pat child in children) { v.visit_pat(child, e, v); }
192192
}
193+
case (pat_rec(?fields, _)) {
194+
for (field_pat f in fields) { v.visit_pat(f.pat, e, v); }
195+
}
193196
case (_) { }
194197
}
195198
}

src/comp/syntax/walk.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ fn walk_pat(&ast_visitor v, &@ast::pat p) {
189189
for (@ast::ty tp in path.node.types) { walk_ty(v, tp); }
190190
for (@ast::pat child in children) { walk_pat(v, child); }
191191
}
192+
case (ast::pat_rec(?fields, _)) {
193+
for (ast::field_pat f in fields) { walk_pat(v, f.pat); }
194+
}
192195
case (_) { }
193196
}
194197
v.visit_pat_post(p);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// error-pattern:did not expect a record with a field q
2+
3+
fn main() {
4+
alt rec(x=1, y=2) {
5+
{x, q} {}
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// error-pattern:expected a record with 2 fields, found one with 1
2+
3+
fn main() {
4+
alt rec(x=1, y=2) {
5+
{x} {}
6+
}
7+
}

src/test/run-pass/record-pat.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
tag t1 { a(int); b(uint); }
2+
type t2 = rec(t1 x, int y);
3+
tag t3 { c(t2, uint); }
4+
5+
fn m(&t3 in) -> int {
6+
alt in {
7+
c({x: a(?m) ...}, _) { ret m; }
8+
c({x: b(?m), y}, ?z) { ret (m + z) as int + y; }
9+
}
10+
}
11+
12+
fn main() {
13+
assert m(c(rec(x=a(10), y=5), 4u)) == 10;
14+
assert m(c(rec(x=b(10u), y=5), 4u)) == 19;
15+
}

0 commit comments

Comments
 (0)