Support 'alt check' syntax

It is only a way to flag an alt as intentionally non-exhaustive right now.

Issue #1679
This commit is contained in:
Marijn Haverbeke 2012-02-15 09:35:11 +01:00
parent 9f95ccb426
commit 6627890f6b
14 changed files with 29 additions and 29 deletions

View file

@ -293,7 +293,7 @@ impl ast_output for ast_ctxt {
} }
} }
ast::expr_alt(cond, arms) { ast::expr_alt(cond, arms, _) {
self.tag(at_expr_node_alt) {|| self.tag(at_expr_node_alt) {||
self.blk(blk); self.blk(blk);
self.expr(cond); self.expr(cond);

View file

@ -110,7 +110,7 @@ fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) {
check_call(*cx, sc, f, args); check_call(*cx, sc, f, args);
handled = false; handled = false;
} }
ast::expr_alt(input, arms) { check_alt(*cx, input, arms, sc, v); } ast::expr_alt(input, arms, _) { check_alt(*cx, input, arms, sc, v); }
ast::expr_for(decl, seq, blk) { ast::expr_for(decl, seq, blk) {
v.visit_expr(seq, sc, v); v.visit_expr(seq, sc, v);
check_loop(*cx, sc) {|| check_for(*cx, decl, seq, blk, sc, v); } check_loop(*cx, sc) {|| check_for(*cx, decl, seq, blk, sc, v); }

View file

@ -21,19 +21,21 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) { fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
visit::visit_expr(ex, s, v); visit::visit_expr(ex, s, v);
alt ex.node { alt ex.node {
expr_alt(scrut, arms) { expr_alt(scrut, arms, mode) {
check_arms(tcx, ex.span, scrut, let arms = pat_util::normalize_arms(tcx, arms);
pat_util::normalize_arms(tcx, arms)); check_arms(tcx, arms);
/* Check for exhaustiveness */
if mode == alt_exhaustive {
let arms = vec::concat(vec::filter_map(arms, unguarded_pat));
check_exhaustive(tcx, ex.span, expr_ty(tcx, scrut), arms);
} }
_ { } }
_ { }
} }
} }
fn check_arms(tcx: ty::ctxt, sp:span, scrut: @expr, arms: [arm]) { fn check_arms(tcx: ty::ctxt, arms: [arm]) {
let i = 0; let i = 0;
let scrut_ty = expr_ty(tcx, scrut);
/* (Could both checks be done in a single pass?) */
/* Check for unreachable patterns */ /* Check for unreachable patterns */
for arm: arm in arms { for arm: arm in arms {
for arm_pat: @pat in arm.pats { for arm_pat: @pat in arm.pats {
@ -55,11 +57,6 @@ fn check_arms(tcx: ty::ctxt, sp:span, scrut: @expr, arms: [arm]) {
} }
i += 1; i += 1;
} }
/* Check for exhaustiveness */
check_exhaustive(tcx, sp, scrut_ty,
vec::concat(vec::filter_map(arms, unguarded_pat)));
} }
// Precondition: patterns have been normalized // Precondition: patterns have been normalized

View file

@ -88,7 +88,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
v.visit_expr(coll, cx, v); v.visit_expr(coll, cx, v);
visit_block(loop, cx) {|| visit::visit_block(blk, cx, v);} visit_block(loop, cx) {|| visit::visit_block(blk, cx, v);}
} }
expr_alt(input, arms) { expr_alt(input, arms, _) {
v.visit_expr(input, cx, v); v.visit_expr(input, cx, v);
let before = cx.current, sets = []; let before = cx.current, sets = [];
for arm in arms { for arm in arms {

View file

@ -3257,7 +3257,7 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
ast::expr_if(cond, thn, els) | ast::expr_if_check(cond, thn, els) { ast::expr_if(cond, thn, els) | ast::expr_if_check(cond, thn, els) {
ret trans_if(bcx, cond, thn, els, dest); ret trans_if(bcx, cond, thn, els, dest);
} }
ast::expr_alt(expr, arms) { ast::expr_alt(expr, arms, _) {
ret alt::trans_alt(bcx, expr, arms, dest); ret alt::trans_alt(bcx, expr, arms, dest);
} }
ast::expr_block(blk) { ast::expr_block(blk) {

View file

@ -447,7 +447,7 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
find_pre_post_loop(fcx, d, index, body, e.id); find_pre_post_loop(fcx, d, index, body, e.id);
} }
expr_index(val, sub) { find_pre_post_exprs(fcx, [val, sub], e.id); } expr_index(val, sub) { find_pre_post_exprs(fcx, [val, sub], e.id); }
expr_alt(ex, alts) { expr_alt(ex, alts, _) {
find_pre_post_expr(fcx, ex); find_pre_post_expr(fcx, ex);
fn do_an_alt(fcx: fn_ctxt, an_alt: arm) -> pre_and_post { fn do_an_alt(fcx: fn_ctxt, an_alt: arm) -> pre_and_post {
alt an_alt.guard { alt an_alt.guard {

View file

@ -552,7 +552,7 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
expr_index(val, sub) { expr_index(val, sub) {
ret find_pre_post_state_two(fcx, pres, val, sub, e.id, oper_pure); ret find_pre_post_state_two(fcx, pres, val, sub, e.id, oper_pure);
} }
expr_alt(val, alts) { expr_alt(val, alts, _) {
let changed = let changed =
set_prestate_ann(fcx.ccx, e.id, pres) | set_prestate_ann(fcx.ccx, e.id, pres) |
find_pre_post_state_expr(fcx, pres, val); find_pre_post_state_expr(fcx, pres, val);

View file

@ -2231,7 +2231,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
check_block_no_value(fcx, body); check_block_no_value(fcx, body);
write_ty(tcx, id, block_ty(tcx, body)); write_ty(tcx, id, block_ty(tcx, body));
} }
ast::expr_alt(expr, arms) { ast::expr_alt(expr, arms, _) {
bot = check_expr(fcx, expr); bot = check_expr(fcx, expr);
// Typecheck the patterns first, so that we get types for all the // Typecheck the patterns first, so that we get types for all the

View file

@ -215,6 +215,8 @@ enum expr_check_mode { claimed_expr, checked_expr, }
type expr = {id: node_id, node: expr_, span: span}; type expr = {id: node_id, node: expr_, span: span};
enum alt_mode { alt_check, alt_exhaustive, }
enum expr_ { enum expr_ {
expr_vec([@expr], mutability), expr_vec([@expr], mutability),
expr_rec([field], option<@expr>), expr_rec([field], option<@expr>),
@ -229,7 +231,7 @@ enum expr_ {
expr_while(@expr, blk), expr_while(@expr, blk),
expr_for(@local, @expr, blk), expr_for(@local, @expr, blk),
expr_do_while(blk, @expr), expr_do_while(blk, @expr),
expr_alt(@expr, [arm]), expr_alt(@expr, [arm], alt_mode),
expr_fn(proto, fn_decl, blk, @capture_clause), expr_fn(proto, fn_decl, blk, @capture_clause),
expr_fn_block(fn_decl, blk), expr_fn_block(fn_decl, blk),
expr_block(blk), expr_block(blk),

View file

@ -383,8 +383,8 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
expr_do_while(blk, expr) { expr_do_while(blk, expr) {
expr_do_while(fld.fold_block(blk), fld.fold_expr(expr)) expr_do_while(fld.fold_block(blk), fld.fold_expr(expr))
} }
expr_alt(expr, arms) { expr_alt(expr, arms, mode) {
expr_alt(fld.fold_expr(expr), vec::map(arms, fld.fold_arm)) expr_alt(fld.fold_expr(expr), vec::map(arms, fld.fold_arm), mode)
} }
expr_fn(proto, decl, body, captures) { expr_fn(proto, decl, body, captures) {
expr_fn(proto, fold_fn_decl(decl, fld), expr_fn(proto, fold_fn_decl(decl, fld),

View file

@ -1372,6 +1372,8 @@ fn parse_do_while_expr(p: parser) -> @ast::expr {
fn parse_alt_expr(p: parser) -> @ast::expr { fn parse_alt_expr(p: parser) -> @ast::expr {
let lo = p.last_span.lo; let lo = p.last_span.lo;
let mode = if eat_word(p, "check") { ast::alt_check }
else { ast::alt_exhaustive };
let discriminant = parse_expr(p); let discriminant = parse_expr(p);
expect(p, token::LBRACE); expect(p, token::LBRACE);
let arms: [ast::arm] = []; let arms: [ast::arm] = [];
@ -1384,7 +1386,7 @@ fn parse_alt_expr(p: parser) -> @ast::expr {
} }
let hi = p.span.hi; let hi = p.span.hi;
p.bump(); p.bump();
ret mk_expr(p, lo, hi, ast::expr_alt(discriminant, arms)); ret mk_expr(p, lo, hi, ast::expr_alt(discriminant, arms, mode));
} }
fn parse_expr(p: parser) -> @ast::expr { fn parse_expr(p: parser) -> @ast::expr {
@ -1653,7 +1655,7 @@ fn expr_is_complete(p: parser, e: pexpr) -> bool {
fn expr_requires_semi_to_be_stmt(e: @ast::expr) -> bool { fn expr_requires_semi_to_be_stmt(e: @ast::expr) -> bool {
alt e.node { alt e.node {
ast::expr_if(_, _, _) | ast::expr_if_check(_, _, _) ast::expr_if(_, _, _) | ast::expr_if_check(_, _, _)
| ast::expr_alt(_, _) | ast::expr_block(_) | ast::expr_alt(_, _, _) | ast::expr_block(_)
| ast::expr_do_while(_, _) | ast::expr_while(_, _) | ast::expr_do_while(_, _) | ast::expr_while(_, _)
| ast::expr_for(_, _, _) | ast::expr_for(_, _, _)
| ast::expr_call(_, _, true) { | ast::expr_call(_, _, true) {

View file

@ -901,10 +901,11 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
word_space(s, "while"); word_space(s, "while");
print_expr(s, expr); print_expr(s, expr);
} }
ast::expr_alt(expr, arms) { ast::expr_alt(expr, arms, mode) {
cbox(s, alt_indent_unit); cbox(s, alt_indent_unit);
ibox(s, 4u); ibox(s, 4u);
word_nbsp(s, "alt"); word_nbsp(s, "alt");
if mode == ast::alt_check { word_nbsp(s, "check"); }
print_maybe_parens_discrim(s, expr); print_maybe_parens_discrim(s, expr);
space(s.s); space(s.s);
bopen(s); bopen(s);

View file

@ -339,7 +339,7 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
v.visit_block(b, e, v); v.visit_block(b, e, v);
} }
expr_do_while(b, x) { v.visit_block(b, e, v); v.visit_expr(x, e, v); } expr_do_while(b, x) { v.visit_block(b, e, v); v.visit_expr(x, e, v); }
expr_alt(x, arms) { expr_alt(x, arms, _) {
v.visit_expr(x, e, v); v.visit_expr(x, e, v);
for a: arm in arms { v.visit_arm(a, e, v); } for a: arm in arms { v.visit_arm(a, e, v); }
} }

View file

@ -1,5 +1,3 @@
// xfail-test
iface foo { iface foo {
fn foo() -> int; fn foo() -> int;
fn bar(p: int) -> int; fn bar(p: int) -> int;