Make alts on uninhabited enum types typecheck and translate properly
Possibly one of the silliest Rust commits ever. Closes #3037
This commit is contained in:
parent
8fdf77a20d
commit
300f54ebc0
@ -26,6 +26,23 @@ fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
|
||||
expr_alt(scrut, arms, mode) {
|
||||
check_arms(tcx, arms);
|
||||
/* Check for exhaustiveness */
|
||||
// Check for empty enum, because is_useful only works on inhabited
|
||||
// types.
|
||||
let pat_ty = node_id_to_type(tcx, scrut.id);
|
||||
if type_is_empty(tcx, pat_ty) && arms.is_empty() {
|
||||
// Vacuously exhaustive
|
||||
ret;
|
||||
}
|
||||
alt ty::get(pat_ty).struct {
|
||||
ty_enum(did, _) {
|
||||
if (*enum_variants(tcx, did)).is_empty() && arms.is_empty() {
|
||||
|
||||
ret;
|
||||
}
|
||||
}
|
||||
_ { /* We assume only enum types can be uninhabited */ }
|
||||
}
|
||||
|
||||
if mode == alt_exhaustive {
|
||||
let arms = vec::concat(vec::filter_map(arms, unguarded_pat));
|
||||
check_exhaustive(tcx, ex.span, arms);
|
||||
@ -60,6 +77,7 @@ fn raw_pat(p: @pat) -> @pat {
|
||||
}
|
||||
|
||||
fn check_exhaustive(tcx: ty::ctxt, sp: span, pats: ~[@pat]) {
|
||||
assert(pats.is_not_empty());
|
||||
let ext = alt is_useful(tcx, vec::map(pats, |p| ~[p]), ~[wild()]) {
|
||||
not_useful { ret; } // This is good, wildcard pattern isn't reachable
|
||||
useful_ { none }
|
||||
@ -111,6 +129,8 @@ enum ctor {
|
||||
// checking (if a wildcard pattern is useful in relation to a matrix, the
|
||||
// matrix isn't exhaustive).
|
||||
|
||||
// Note: is_useful doesn't work on empty types, as the paper notes.
|
||||
// So it assumes that v is non-empty.
|
||||
fn is_useful(tcx: ty::ctxt, m: matrix, v: ~[@pat]) -> useful {
|
||||
if m.len() == 0u { ret useful_; }
|
||||
if m[0].len() == 0u { ret not_useful; }
|
||||
|
@ -385,6 +385,10 @@ fn score(p: @ast::pat) -> uint {
|
||||
|
||||
fn compile_submatch(bcx: block, m: match, vals: ~[ValueRef],
|
||||
chk: option<mk_fail>, &exits: ~[exit_node]) {
|
||||
/*
|
||||
For an empty match, a fall-through case must exist
|
||||
*/
|
||||
assert(m.len() > 0u || is_some(chk));
|
||||
let _icx = bcx.insn_ctxt(~"alt::compile_submatch");
|
||||
let mut bcx = bcx;
|
||||
let tcx = bcx.tcx(), dm = tcx.def_map;
|
||||
@ -664,24 +668,35 @@ fn trans_alt_inner(scope_cx: block, expr: @ast::expr, arms: ~[ast::arm],
|
||||
}
|
||||
}
|
||||
|
||||
let mk_fail = alt mode {
|
||||
ast::alt_check {
|
||||
// Cached fail-on-fallthrough block
|
||||
let fail_cx = @mut none;
|
||||
fn mk_fail(bcx: block, sp: span,
|
||||
fn mk_fail(bcx: block, sp: span, msg: ~str,
|
||||
done: @mut option<BasicBlockRef>) -> BasicBlockRef {
|
||||
alt *done { some(bb) { ret bb; } _ { } }
|
||||
let fail_cx = sub_block(bcx, ~"case_fallthrough");
|
||||
trans_fail(fail_cx, some(sp), ~"non-exhaustive match failure");;
|
||||
trans_fail(fail_cx, some(sp), msg);
|
||||
*done = some(fail_cx.llbb);
|
||||
ret fail_cx.llbb;
|
||||
}
|
||||
some(|| mk_fail(scope_cx, expr.span, fail_cx))
|
||||
}
|
||||
let t = node_id_type(bcx, expr.id);
|
||||
let mk_fail = alt mode {
|
||||
ast::alt_check {
|
||||
let fail_cx = @mut none;
|
||||
// Cached fail-on-fallthrough block
|
||||
some(|| mk_fail(scope_cx, expr.span, ~"non-exhaustive match failure",
|
||||
fail_cx))
|
||||
}
|
||||
ast::alt_exhaustive {
|
||||
let fail_cx = @mut none;
|
||||
// special case for uninhabited type
|
||||
if ty::type_is_empty(tcx, t) {
|
||||
some(|| mk_fail(scope_cx, expr.span,
|
||||
~"scrutinizing value that can't exist", fail_cx))
|
||||
}
|
||||
else {
|
||||
none
|
||||
}
|
||||
}
|
||||
ast::alt_exhaustive { none }
|
||||
};
|
||||
let mut exit_map = ~[];
|
||||
let t = node_id_type(bcx, expr.id);
|
||||
let spilled = spill_if_immediate(bcx, val, t);
|
||||
compile_submatch(bcx, match, ~[spilled], mk_fail, exit_map);
|
||||
|
||||
|
@ -117,6 +117,7 @@
|
||||
export type_err, terr_vstore_kind;
|
||||
export type_err_to_str;
|
||||
export type_needs_drop;
|
||||
export type_is_empty;
|
||||
export type_is_integral;
|
||||
export type_is_numeric;
|
||||
export type_is_pod;
|
||||
@ -2748,6 +2749,15 @@ fn enum_is_univariant(cx: ctxt, id: ast::def_id) -> bool {
|
||||
vec::len(*enum_variants(cx, id)) == 1u
|
||||
}
|
||||
|
||||
fn type_is_empty(cx: ctxt, t: t) -> bool {
|
||||
alt ty::get(t).struct {
|
||||
ty_enum(did, _) {
|
||||
(*enum_variants(cx, did)).is_empty()
|
||||
}
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
|
||||
fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[variant_info] {
|
||||
alt cx.enum_var_cache.find(id) {
|
||||
some(variants) { ret variants; }
|
||||
|
11
src/test/run-pass/issue-3037.rs
Normal file
11
src/test/run-pass/issue-3037.rs
Normal file
@ -0,0 +1,11 @@
|
||||
enum what { }
|
||||
|
||||
fn what_to_str(x: what) -> ~str
|
||||
{
|
||||
alt x {
|
||||
}
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
}
|
Loading…
Reference in New Issue
Block a user