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:
parent
9f95ccb426
commit
6627890f6b
14 changed files with 29 additions and 29 deletions
|
@ -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);
|
||||||
|
|
|
@ -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); }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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); }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue