Skip to content

Commit 64ce092

Browse files
committed
Allow literal patterns to contain arbitrary literal expressions
This removes the need for the unary minus hacks, and allows some other neat things like matching on 1 >> 4. Issue #954
1 parent 691b517 commit 64ce092

File tree

10 files changed

+175
-128
lines changed

10 files changed

+175
-128
lines changed

src/comp/driver/rustc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
137137
let freevars =
138138
time(time_passes, "freevar finding",
139139
bind freevars::annotate_freevars(def_map, crate));
140+
time(time_passes, "const checking",
141+
bind middle::check_const::check_crate(sess, crate));
140142
let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, ast_map, freevars);
141143
time(time_passes, "typechecking", bind typeck::check_crate(ty_cx, crate));
142144
time(time_passes, "block-use checking",
@@ -157,8 +159,6 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
157159
bind last_use::find_last_uses(crate, def_map, ref_map, ty_cx));
158160
time(time_passes, "kind checking",
159161
bind kind::check_crate(ty_cx, last_uses, crate));
160-
time(time_passes, "const checking",
161-
bind middle::check_const::check_crate(ty_cx, crate));
162162
if sess.get_opts().no_trans { ret; }
163163
let llmod =
164164
time(time_passes, "translation",

src/comp/middle/check_alt.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import syntax::ast::*;
2-
import syntax::ast_util::{variant_def_ids, dummy_sp, compare_lit, lit_eq};
2+
import syntax::ast_util::{variant_def_ids, dummy_sp, compare_lit_exprs,
3+
lit_expr_eq};
34
import syntax::visit;
45

56
fn check_crate(tcx: ty::ctxt, crate: @crate) {
@@ -66,7 +67,7 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
6667
pat_wild. | pat_bind(_) { ret true; }
6768
pat_lit(la) {
6869
alt b.node {
69-
pat_lit(lb) { ret lit_eq(la, lb); }
70+
pat_lit(lb) { ret lit_expr_eq(la, lb); }
7071
_ { ret false; }
7172
}
7273
}
@@ -106,11 +107,12 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
106107
pat_range(begina, enda) {
107108
alt b.node {
108109
pat_lit(lb) {
109-
ret compare_lit(begina, lb) <= 0 && compare_lit(enda, lb) >= 0;
110+
ret compare_lit_exprs(begina, lb) <= 0 &&
111+
compare_lit_exprs(enda, lb) >= 0;
110112
}
111113
pat_range(beginb, endb) {
112-
ret compare_lit(begina, beginb) <= 0 &&
113-
compare_lit(enda, endb) >= 0;
114+
ret compare_lit_exprs(begina, beginb) <= 0 &&
115+
compare_lit_exprs(enda, endb) >= 0;
114116
}
115117
_ { ret false; }
116118
}

src/comp/middle/check_const.rs

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,61 @@
11
import syntax::ast::*;
22
import syntax::visit;
3+
import driver::session::session;
34

4-
fn check_crate(tcx: ty::ctxt, crate: @crate) {
5-
let v =
6-
@{visit_item: bind check_item(tcx, _, _, _)
7-
with *visit::default_visitor::<()>()};
8-
visit::visit_crate(*crate, (), visit::mk_vt(v));
9-
tcx.sess.abort_if_errors();
5+
fn check_crate(sess: session, crate: @crate) {
6+
visit::visit_crate(*crate, false, visit::mk_vt(@{
7+
visit_item: check_item,
8+
visit_pat: check_pat,
9+
visit_expr: bind check_expr(sess, _, _, _)
10+
with *visit::default_visitor()
11+
}));
12+
sess.abort_if_errors();
1013
}
1114

12-
fn check_item(tcx: ty::ctxt, it: @item, &&s: (), v: visit::vt<()>) {
13-
visit::visit_item(it, s, v);
15+
fn check_item(it: @item, &&_is_const: bool, v: visit::vt<bool>) {
1416
alt it.node {
15-
item_const(_ /* ty */, ex) {
16-
let v =
17-
@{visit_expr: bind check_const_expr(tcx, _, _, _)
18-
with *visit::default_visitor::<()>()};
19-
check_const_expr(tcx, ex, (), visit::mk_vt(v));
20-
}
21-
_ { }
17+
item_const(_, ex) { v.visit_expr(ex, true, v); }
18+
_ { visit::visit_item(it, false, v); }
2219
}
2320
}
2421

25-
fn check_const_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
26-
visit::visit_expr(ex, s, v);
27-
alt ex.node {
28-
expr_lit(_) { }
29-
expr_binary(_, _, _) { /* subexps covered by visit */ }
30-
expr_unary(u, _) {
31-
alt u {
32-
box(_) |
33-
uniq(_) |
34-
deref. {
35-
tcx.sess.span_err(ex.span,
36-
"disallowed operator in constant expression");
22+
fn check_pat(p: @pat, &&_is_const: bool, v: visit::vt<bool>) {
23+
fn is_str(e: @expr) -> bool {
24+
alt e.node { expr_lit(@{node: lit_str(_), _}) { true } _ { false } }
25+
}
26+
alt p.node {
27+
// Let through plain string literals here
28+
pat_lit(a) { if !is_str(a) { v.visit_expr(a, true, v); } }
29+
pat_range(a, b) {
30+
if !is_str(a) { v.visit_expr(a, true, v); }
31+
if !is_str(b) { v.visit_expr(b, true, v); }
32+
}
33+
_ { visit::visit_pat(p, false, v); }
34+
}
35+
}
36+
37+
fn check_expr(sess: session, e: @expr, &&is_const: bool, v: visit::vt<bool>) {
38+
if is_const {
39+
alt e.node {
40+
expr_unary(box(_), _) | expr_unary(uniq(_), _) |
41+
expr_unary(deref., _){
42+
sess.span_err(e.span,
43+
"disallowed operator in constant expression");
44+
ret;
45+
}
46+
expr_lit(@{node: lit_str(_), _}) {
47+
sess.span_err(e.span,
48+
"string constants are not supported");
49+
}
50+
expr_lit(_) | expr_binary(_, _, _) | expr_unary(_, _) {}
51+
_ {
52+
sess.span_err(e.span,
53+
"constant contains unimplemented expression type");
54+
ret;
3755
}
38-
_ { }
3956
}
40-
}
41-
_ { tcx.sess.span_err(ex.span,
42-
"constant contains unimplemented expression type"); }
4357
}
58+
visit::visit_expr(e, is_const, v);
4459
}
4560

4661
// Local Variables:

src/comp/middle/trans_alt.rs

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,27 @@ import trans_build::*;
77
import trans::{new_sub_block_ctxt, new_scope_block_ctxt, load_if_immediate};
88
import syntax::ast;
99
import syntax::ast_util;
10-
import syntax::ast_util::{dummy_sp, lit_eq};
10+
import syntax::ast_util::{dummy_sp};
1111
import syntax::ast::def_id;
1212
import syntax::codemap::span;
1313

1414
import trans_common::*;
1515

1616
// An option identifying a branch (either a literal, a tag variant or a range)
1717
tag opt {
18-
lit(@ast::lit);
18+
lit(@ast::expr);
1919
var(/* variant id */uint, /* variant dids */{tg: def_id, var: def_id});
20-
range(@ast::lit, @ast::lit);
20+
range(@ast::expr, @ast::expr);
2121
}
2222
fn opt_eq(a: opt, b: opt) -> bool {
23-
alt a {
24-
lit(la) {
25-
ret alt b { lit(lb) { lit_eq(la, lb) } _ { false } };
26-
}
27-
var(ida, _) {
28-
ret alt b { var(idb, _) { ida == idb } _ { false } };
29-
}
30-
range(la1, la2) {
31-
ret alt b {
32-
range(lb1, lb2) { lit_eq(la1, lb1) && lit_eq(la2, lb2) }
33-
_ { false }
34-
};
23+
alt (a, b) {
24+
(lit(a), lit(b)) { ast_util::compare_lit_exprs(a, b) == 0 }
25+
(range(a1, a2), range(b1, b2)) {
26+
ast_util::compare_lit_exprs(a1, b1) == 0 &&
27+
ast_util::compare_lit_exprs(a2, b2) == 0
3528
}
29+
(var(a, _), var(b, _)) { a == b }
30+
_ { false }
3631
}
3732
}
3833

@@ -45,7 +40,7 @@ fn trans_opt(bcx: @block_ctxt, o: opt) -> opt_result {
4540
alt o {
4641
lit(l) {
4742
alt l.node {
48-
ast::lit_str(s) {
43+
ast::expr_lit(@{node: ast::lit_str(s), _}) {
4944
let strty = ty::mk_str(bcx_tcx(bcx));
5045
let cell = trans::empty_dest_cell();
5146
bcx = trans_vec::trans_str(bcx, s, trans::by_val(cell));
@@ -54,17 +49,14 @@ fn trans_opt(bcx: @block_ctxt, o: opt) -> opt_result {
5449
}
5550
_ {
5651
ret single_result(
57-
rslt(bcx, trans::trans_crate_lit(ccx, *l)));
52+
rslt(bcx, trans::trans_const_expr(ccx, l)));
5853
}
5954
}
6055
}
6156
var(id, _) { ret single_result(rslt(bcx, C_int(ccx, id as int))); }
6257
range(l1, l2) {
63-
let cell1 = trans::empty_dest_cell();
64-
let cell2 = trans::empty_dest_cell();
65-
let bcx = trans::trans_lit(bcx, *l1, trans::by_val(cell1));
66-
let bcx = trans::trans_lit(bcx, *l2, trans::by_val(cell2));
67-
ret range_result(rslt(bcx, *cell1), rslt(bcx, *cell2));
58+
ret range_result(rslt(bcx, trans::trans_const_expr(ccx, l1)),
59+
rslt(bcx, trans::trans_const_expr(ccx, l2)));
6860
}
6961
}
7062
}
@@ -464,13 +456,9 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail,
464456
}
465457
}
466458
lit(l) {
467-
kind = alt l.node {
468-
ast::lit_str(_) | ast::lit_nil. | ast::lit_float(_) |
469-
ast::lit_mach_float(_, _) {
470-
test_val = Load(bcx, val); compare
471-
}
472-
_ { test_val = Load(bcx, val); switch }
473-
};
459+
test_val = Load(bcx, val);
460+
let pty = ty::node_id_to_monotype(ccx.tcx, pat_id);
461+
kind = ty::type_is_integral(ccx.tcx, pty) ? switch : compare;
474462
}
475463
range(_, _) {
476464
test_val = Load(bcx, val);

src/comp/middle/ty.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ export type_is_vec;
155155
export type_is_fp;
156156
export type_allows_implicit_copy;
157157
export type_is_integral;
158+
export type_is_numeric;
158159
export type_is_native;
159160
export type_is_nil;
160161
export type_is_pod;
@@ -1173,6 +1174,10 @@ fn type_is_fp(cx: ctxt, ty: t) -> bool {
11731174
}
11741175
}
11751176

1177+
fn type_is_numeric(cx: ctxt, ty: t) -> bool {
1178+
ret type_is_integral(cx, ty) || type_is_fp(cx, ty);
1179+
}
1180+
11761181
fn type_is_signed(cx: ctxt, ty: t) -> bool {
11771182
alt struct(cx, ty) {
11781183
ty_int. { ret true; }

src/comp/middle/typeck.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import syntax::{ast, ast_util};
22
import ast::spanned;
3-
import syntax::ast_util::{local_def, respan, ty_param_kind, lit_is_numeric,
4-
lit_types_match};
3+
import syntax::ast_util::{local_def, respan, ty_param_kind};
54
import syntax::visit;
65
import metadata::csearch;
76
import driver::session;
@@ -1253,8 +1252,8 @@ fn lit_as_float(l: @ast::lit) -> str {
12531252
}
12541253
}
12551254

1256-
fn valid_range_bounds(l1: @ast::lit, l2: @ast::lit) -> bool {
1257-
ast_util::compare_lit(l1, l2) <= 0
1255+
fn valid_range_bounds(from: @ast::expr, to: @ast::expr) -> bool {
1256+
ast_util::compare_lit_exprs(from, to) <= 0
12581257
}
12591258

12601259
// Pattern checking is top-down rather than bottom-up so that bindings get
@@ -1264,27 +1263,26 @@ fn check_pat(fcx: @fn_ctxt, map: ast_util::pat_id_map, pat: @ast::pat,
12641263
alt pat.node {
12651264
ast::pat_wild. { write::ty_only_fixup(fcx, pat.id, expected); }
12661265
ast::pat_lit(lt) {
1267-
let typ = check_lit(fcx.ccx, lt);
1268-
typ = demand::simple(fcx, pat.span, expected, typ);
1269-
write::ty_only_fixup(fcx, pat.id, typ);
1266+
check_expr_with(fcx, lt, expected);
1267+
write::ty_only_fixup(fcx, pat.id, expr_ty(fcx.ccx.tcx, lt));
12701268
}
12711269
ast::pat_range(begin, end) {
1272-
if !lit_types_match(begin, end) {
1270+
check_expr_with(fcx, begin, expected);
1271+
check_expr_with(fcx, end, expected);
1272+
let b_ty = resolve_type_vars_if_possible(fcx, expr_ty(fcx.ccx.tcx,
1273+
begin));
1274+
if b_ty != resolve_type_vars_if_possible(fcx, expr_ty(fcx.ccx.tcx,
1275+
end)) {
12731276
fcx.ccx.tcx.sess.span_err(pat.span, "mismatched types in range");
1274-
} else if !lit_is_numeric(begin) || !lit_is_numeric(end) {
1277+
} else if !ty::type_is_numeric(fcx.ccx.tcx, b_ty) {
12751278
fcx.ccx.tcx.sess.span_err(pat.span,
12761279
"non-numeric type used in range");
12771280
} else if !valid_range_bounds(begin, end) {
12781281
fcx.ccx.tcx.sess.span_err(begin.span,
12791282
"lower range bound must be less \
12801283
than upper");
12811284
}
1282-
let typ1 = check_lit(fcx.ccx, begin);
1283-
typ1 = demand::simple(fcx, pat.span, expected, typ1);
1284-
write::ty_only_fixup(fcx, pat.id, typ1);
1285-
let typ2 = check_lit(fcx.ccx, end);
1286-
typ2 = demand::simple(fcx, pat.span, typ1, typ2);
1287-
write::ty_only_fixup(fcx, pat.id, typ2);
1285+
write::ty_only_fixup(fcx, pat.id, b_ty);
12881286
}
12891287
ast::pat_bind(name) {
12901288
let vid = lookup_local(fcx, pat.span, pat.id);

src/comp/syntax/ast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,13 @@ type field_pat = {ident: ident, pat: @pat};
8686
tag pat_ {
8787
pat_wild;
8888
pat_bind(ident);
89-
pat_lit(@lit);
9089
pat_tag(@path, [@pat]);
9190
pat_rec([field_pat], bool);
9291
pat_tup([@pat]);
9392
pat_box(@pat);
9493
pat_uniq(@pat);
95-
pat_range(@lit, @lit);
94+
pat_lit(@expr);
95+
pat_range(@expr, @expr);
9696
}
9797

9898
tag mutability { mut; imm; maybe_mut; }

0 commit comments

Comments
 (0)