From b62bf8cede38cf8a3baac83885436e13944b4950 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 21 May 2011 14:07:44 -0400 Subject: [PATCH] rustc: Allow if expressions to fail --- src/comp/middle/trans.rs | 13 +++++------ src/comp/middle/typeck.rs | 32 ++++++++++++++++++++------- src/test/run-fail/expr-if-fail.rs | 12 +++++++++++ src/test/run-pass/expr-if-fail.rs | 36 +++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 14 deletions(-) create mode 100644 src/test/run-fail/expr-if-fail.rs create mode 100644 src/test/run-pass/expr-if-fail.rs diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 9223eaaa121..b562805e8d9 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3660,7 +3660,8 @@ fn join_results(&@block_ctxt parent_cx, } fn trans_if(&@block_ctxt cx, &@ast::expr cond, - &ast::block thn, &option::t[@ast::expr] els) -> result { + &ast::block thn, &option::t[@ast::expr] els, + &ast::ann ann) -> result { auto cond_res = trans_expr(cx, cond); @@ -3699,12 +3700,12 @@ fn trans_if(&@block_ctxt cx, &@ast::expr cond, // If we have an else expression, then the entire // if expression can have a non-nil type. // FIXME: This isn't quite right, particularly re: dynamic types - auto expr_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, elexpr); + auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx.node_types, + ann); if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) { expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn); } else { - expr_llty = type_of(else_res.bcx.fcx.lcx.ccx, elexpr.span, - expr_ty); + expr_llty = type_of(cx.fcx.lcx.ccx, elexpr.span, expr_ty); if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, expr_ty)) { expr_llty = T_ptr(expr_llty); } @@ -5392,8 +5393,8 @@ fn trans_expr(&@block_ctxt cx, &@ast::expr e) -> result { ret trans_binary(cx, op, x, y); } - case (ast::expr_if(?cond, ?thn, ?els, _)) { - ret trans_if(cx, cond, thn, els); + case (ast::expr_if(?cond, ?thn, ?els, ?ann)) { + ret trans_if(cx, cond, thn, els, ann); } case (ast::expr_for(?decl, ?seq, ?body, _)) { diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index aedbb89f2a8..a679804e0b6 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1331,12 +1331,19 @@ mod Pushdown { case (ast::expr_if(?cond, ?then_0, ?else_0, ?ann)) { auto t = Demand::autoderef(scx, e.span, expected, ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); - pushdown_block(scx, expected, then_0); + + auto then_t = ty::block_ty(scx.fcx.ccx.tcx, then_0); + if (!ty::type_is_bot(scx.fcx.ccx.tcx, then_t)) { + pushdown_block(scx, expected, then_0); + } alt (else_0) { case (none[@ast::expr]) { /* no-op */ } case (some[@ast::expr](?e_0)) { - pushdown_expr(scx, expected, e_0); + auto else_t = ty::expr_ty(scx.fcx.ccx.tcx, e_0); + if (!ty::type_is_bot(scx.fcx.ccx.tcx, else_t)) { + pushdown_expr(scx, expected, e_0); + } } } write::ty_only_fixup(scx, ann.id, t); @@ -2129,21 +2136,30 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { check_block(scx, thn); auto thn_t = block_ty(scx.fcx.ccx.tcx, thn); - auto elsopt_t; + auto if_t; alt (elsopt) { case (some[@ast::expr](?els)) { check_expr(scx, els); - Pushdown::pushdown_expr(scx, thn_t, els); - elsopt_t = expr_ty(scx.fcx.ccx.tcx, els); + auto elsopt_t = expr_ty(scx.fcx.ccx.tcx, els); + if (!ty::type_is_bot(scx.fcx.ccx.tcx, elsopt_t)) { + Pushdown::pushdown_expr(scx, thn_t, els); + if_t = elsopt_t; + } else if (!ty::type_is_bot(scx.fcx.ccx.tcx, thn_t)) { + if_t = thn_t; + } else { + if_t = ty::mk_nil(scx.fcx.ccx.tcx); + } } case (none[@ast::expr]) { - elsopt_t = ty::mk_nil(scx.fcx.ccx.tcx); + if_t = ty::mk_nil(scx.fcx.ccx.tcx); } } - Pushdown::pushdown_block(scx, elsopt_t, thn); + if (!ty::type_is_bot(scx.fcx.ccx.tcx, thn_t)) { + Pushdown::pushdown_block(scx, if_t, thn); + } - write::ty_only_fixup(scx, a.id, elsopt_t); + write::ty_only_fixup(scx, a.id, if_t); } case (ast::expr_for(?decl, ?seq, ?body, ?a)) { diff --git a/src/test/run-fail/expr-if-fail.rs b/src/test/run-fail/expr-if-fail.rs new file mode 100644 index 00000000000..2a4f6d27a4c --- /dev/null +++ b/src/test/run-fail/expr-if-fail.rs @@ -0,0 +1,12 @@ +// xfail-stage0 +// error-pattern:explicit failure + +fn main() { + auto x = if (false) { + 0 + } else if (true) { + fail + } else { + 10 + }; +} diff --git a/src/test/run-pass/expr-if-fail.rs b/src/test/run-pass/expr-if-fail.rs new file mode 100644 index 00000000000..189f8a72469 --- /dev/null +++ b/src/test/run-pass/expr-if-fail.rs @@ -0,0 +1,36 @@ +// xfail-stage0 + +fn test_if_fail() { + auto x = if (false) { + fail + } else { + 10 + }; + assert (x == 10); +} + +fn test_else_fail() { + auto x = if (true) { + 10 + } else { + fail + }; + assert (x == 10); +} + +fn test_elseif_fail() { + auto x = if (false) { + 0 + } else if (false) { + fail + } else { + 10 + }; + assert (x == 10); +} + +fn main() { + test_if_fail(); + test_else_fail(); + test_elseif_fail(); +}