diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 0b0fcff4615e..4398d3a60633 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -186,7 +186,6 @@ fn instantiate_path(fcx: &@fn_ctxt, pth: &ast::path, fcx.ccx.tcx.sess.span_fatal(sp, "this item does not take type \ parameters"); - fail; } } else { // We will acquire the type parameters through unification. @@ -1516,7 +1515,7 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: &ast::purity, } } -fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { +fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool { // fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " + // syntax::print::pprust::expr_to_str(expr)); @@ -1524,9 +1523,9 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { // expressions. fn check_call_or_bind(fcx: &@fn_ctxt, sp: &span, f: &@ast::expr, args: &(option::t[@ast::expr])[], - call_kind: call_kind) { + call_kind: call_kind) -> bool { // Check the function. - check_expr(fcx, f); + let bot = check_expr(fcx, f); // Get the function type. let fty = expr_ty(fcx.ccx.tcx, f); @@ -1541,7 +1540,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { // Grab the argument types and the return type. let arg_tys; alt structure_of(fcx, sp, fty_stripped) { - ty::ty_fn(_, arg_tys_0, _, _, _) { arg_tys = arg_tys_0; } + ty::ty_fn(_, arg_tys_0, _, _, _) | ty::ty_native_fn(_, arg_tys_0, _) { arg_tys = arg_tys_0; } _ { fcx.ccx.tcx.sess.span_fatal(f.span, @@ -1576,7 +1575,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { for a_opt: option::t[@ast::expr] in args { alt a_opt { some(a) { - check_expr(fcx, a); + bot |= check_expr(fcx, a); demand::full(fcx, a.span, arg_tys.(i).ty, expr_ty(fcx.ccx.tcx, a), ~[], AUTODEREF_BLOCK_COERCE); @@ -1585,47 +1584,49 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } i += 1u; } + ret bot; } // A generic function for checking assignment expressions fn check_assignment(fcx: &@fn_ctxt, sp: &span, lhs: &@ast::expr, - rhs: &@ast::expr, id: &ast::node_id) { - check_expr(fcx, lhs); - check_expr(fcx, rhs); + rhs: &@ast::expr, id: &ast::node_id) -> bool { + let bot = check_expr(fcx, lhs) | check_expr(fcx, rhs); demand::simple(fcx, sp, expr_ty(fcx.ccx.tcx, lhs), expr_ty(fcx.ccx.tcx, rhs)); write::ty_only_fixup(fcx, id, ty::mk_nil(fcx.ccx.tcx)); + ret bot; } // A generic function for checking call expressions fn check_call(fcx: &@fn_ctxt, sp: &span, f: &@ast::expr, - args: &(@ast::expr)[], call_kind: call_kind) { + args: &(@ast::expr)[], call_kind: call_kind) -> bool { let args_opt_0: (option::t[@ast::expr])[] = ~[]; for arg: @ast::expr in args { args_opt_0 += ~[some[@ast::expr](arg)]; } // Call the generic checker. - check_call_or_bind(fcx, sp, f, args_opt_0, call_kind); + ret check_call_or_bind(fcx, sp, f, args_opt_0, call_kind); } // A generic function for checking for or for-each loops fn check_for_or_for_each(fcx: &@fn_ctxt, local: &@ast::local, - element_ty: &ty::t, body: &ast::blk, - node_id: ast::node_id) { - check_decl_local(fcx, local); + element_ty: &ty::t, body: &ast::blk, + node_id: ast::node_id) -> bool { + let bot = check_decl_local(fcx, local); check_block(fcx, body); // Unify type of decl with element type of the seq demand::simple(fcx, local.span, ty::decl_local_ty(fcx.ccx.tcx, local), element_ty); let typ = ty::mk_nil(fcx.ccx.tcx); write::ty_only_fixup(fcx, node_id, typ); + ret bot; } // A generic function for checking the pred in a check // or if-check - fn check_pred_expr(fcx: &@fn_ctxt, e: &@ast::expr) { - check_expr(fcx, e); + fn check_pred_expr(fcx: &@fn_ctxt, e: &@ast::expr) -> bool { + let bot = check_expr(fcx, e); demand::simple(fcx, e.span, ty::mk_bool(fcx.ccx.tcx), expr_ty(fcx.ccx.tcx, e)); @@ -1665,18 +1666,20 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } _ { fcx.ccx.tcx.sess.span_fatal(e.span, "check on non-predicate"); } } + ret bot; } // A generic function for checking the then and else in an if // or if-check fn check_then_else(fcx: &@fn_ctxt, thn: &ast::blk, elsopt: &option::t[@ast::expr], id: ast::node_id, - sp: &span) { - check_block(fcx, thn); + sp: &span) -> bool { + let then_bot = check_block(fcx, thn); + let els_bot = false; let if_t = alt elsopt { some(els) { - check_expr(fcx, els); + els_bot = check_expr(fcx, els); let thn_t = block_ty(fcx.ccx.tcx, thn); let elsopt_t = expr_ty(fcx.ccx.tcx, els); demand::simple(fcx, sp, thn_t, elsopt_t); @@ -1687,6 +1690,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { none. { ty::mk_nil(fcx.ccx.tcx) } }; write::ty_only_fixup(fcx, id, if_t); + ret then_bot & els_bot; } // Checks the compatibility @@ -1704,14 +1708,19 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } let id = expr.id; + let bot = false; alt expr.node { ast::expr_lit(lit) { let typ = check_lit(fcx.ccx, lit); write::ty_only_fixup(fcx, id, typ); } ast::expr_binary(binop, lhs, rhs) { - check_expr(fcx, lhs); - check_expr(fcx, rhs); + bot = check_expr(fcx, lhs); + if ast::lazy_binop(binop) { + check_expr(fcx, rhs); + } else { + bot |= check_expr(fcx, rhs); + } let lhs_t = expr_ty(fcx.ccx.tcx, lhs); let rhs_t = expr_ty(fcx.ccx.tcx, rhs); @@ -1733,7 +1742,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { write::ty_only_fixup(fcx, id, t); } ast::expr_unary(unop, oper) { - check_expr(fcx, oper); + bot = check_expr(fcx, oper); let oper_t = expr_ty(fcx.ccx.tcx, oper); alt unop { ast::box(mut) { @@ -1787,7 +1796,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { if ty::def_has_ty_params(defn) { let path_tpot = instantiate_path(fcx, pth, tpt, expr.span); write::ty_fixup(fcx, id, path_tpot); - ret; + ret false; } // The definition doesn't take type parameters. If the programmer // supplied some, that's an error. @@ -1801,6 +1810,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } ast::expr_mac(_) { fcx.ccx.tcx.sess.bug("unexpanded macro"); } ast::expr_fail(expr_opt) { + bot = true; alt expr_opt { none. {/* do nothing */ } some(e) { @@ -1812,9 +1822,10 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } write::bot_ty(fcx.ccx.tcx, id); } - ast::expr_break. { write::bot_ty(fcx.ccx.tcx, id); } - ast::expr_cont. { write::bot_ty(fcx.ccx.tcx, id); } + ast::expr_break. { write::bot_ty(fcx.ccx.tcx, id); bot = true; } + ast::expr_cont. { write::bot_ty(fcx.ccx.tcx, id); bot = true; } ast::expr_ret(expr_opt) { + bot = true; alt expr_opt { none. { let nil = ty::mk_nil(fcx.ccx.tcx); @@ -1846,7 +1857,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { write::nil_ty(fcx.ccx.tcx, id); } some(e) { - check_expr(fcx, e); + bot = check_expr(fcx, e); demand::simple(fcx, expr.span, fcx.ret_ty, expr_ty(fcx.ccx.tcx, e)); write::nil_ty(fcx.ccx.tcx, id); @@ -1855,55 +1866,54 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } ast::expr_be(e) { // FIXME: prove instead of assert - assert (ast::is_call_expr(e)); check_expr(fcx, e); + bot = true; demand::simple(fcx, e.span, fcx.ret_ty, expr_ty(fcx.ccx.tcx, e)); write::nil_ty(fcx.ccx.tcx, id); } ast::expr_log(l, e) { - check_expr(fcx, e); + bot = check_expr(fcx, e); write::nil_ty(fcx.ccx.tcx, id); } ast::expr_check(_, e) { - check_pred_expr(fcx, e); + bot = check_pred_expr(fcx, e); write::nil_ty(fcx.ccx.tcx, id); } ast::expr_if_check(cond, thn, elsopt) { - check_pred_expr(fcx, cond); - check_then_else(fcx, thn, elsopt, id, expr.span); + bot = check_pred_expr(fcx, cond) | + check_then_else(fcx, thn, elsopt, id, expr.span); } ast::expr_ternary(_, _, _) { - check_expr(fcx, ast::ternary_to_if(expr)); + bot = check_expr(fcx, ast::ternary_to_if(expr)); } ast::expr_assert(e) { - check_expr(fcx, e); + bot = check_expr(fcx, e); let ety = expr_ty(fcx.ccx.tcx, e); demand::simple(fcx, expr.span, ty::mk_bool(fcx.ccx.tcx), ety); write::nil_ty(fcx.ccx.tcx, id); } ast::expr_move(lhs, rhs) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); - check_assignment(fcx, expr.span, lhs, rhs, id); + bot = check_assignment(fcx, expr.span, lhs, rhs, id); } ast::expr_assign(lhs, rhs) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); - check_assignment(fcx, expr.span, lhs, rhs, id); + bot = check_assignment(fcx, expr.span, lhs, rhs, id); } ast::expr_swap(lhs, rhs) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); - check_assignment(fcx, expr.span, lhs, rhs, id); + bot = check_assignment(fcx, expr.span, lhs, rhs, id); } ast::expr_assign_op(op, lhs, rhs) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); - check_assignment(fcx, expr.span, lhs, rhs, id); + bot = check_assignment(fcx, expr.span, lhs, rhs, id); check_binop_type_compat(fcx, expr.span, expr_ty(fcx.ccx.tcx, lhs), op); } ast::expr_send(lhs, rhs) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); - check_expr(fcx, lhs); - check_expr(fcx, rhs); + bot = check_expr(fcx, lhs) | check_expr(fcx, rhs); let rhs_t = expr_ty(fcx.ccx.tcx, rhs); let chan_t = ty::mk_chan(fcx.ccx.tcx, rhs_t); let lhs_t = expr_ty(fcx.ccx.tcx, lhs); @@ -1922,21 +1932,20 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } ast::expr_recv(lhs, rhs) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); - check_expr(fcx, lhs); - check_expr(fcx, rhs); + bot = check_expr(fcx, lhs) | check_expr(fcx, rhs); let item_t = expr_ty(fcx.ccx.tcx, rhs); let port_t = ty::mk_port(fcx.ccx.tcx, item_t); demand::simple(fcx, expr.span, port_t, expr_ty(fcx.ccx.tcx, lhs)); write::ty_only_fixup(fcx, id, item_t); } ast::expr_if(cond, thn, elsopt) { - check_expr(fcx, cond); + bot = check_expr(fcx, cond) | + check_then_else(fcx, thn, elsopt, id, expr.span); demand::simple(fcx, cond.span, ty::mk_bool(fcx.ccx.tcx), expr_ty(fcx.ccx.tcx, cond)); - check_then_else(fcx, thn, elsopt, id, expr.span); } ast::expr_for(decl, seq, body) { - check_expr(fcx, seq); + bot = check_expr(fcx, seq); let elt_ty; let ety = expr_ty(fcx.ccx.tcx, seq); alt structure_of(fcx, expr.span, ety) { @@ -1950,14 +1959,15 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { + "found " + ty_to_str(fcx.ccx.tcx, ety)); } } - check_for_or_for_each(fcx, decl, elt_ty, body, id); + bot |= check_for_or_for_each(fcx, decl, elt_ty, body, id); } ast::expr_for_each(decl, seq, body) { - check_expr(fcx, seq); - check_for_or_for_each(fcx, decl, expr_ty(fcx.ccx.tcx, seq), body, id); + bot = check_expr(fcx, seq) | + check_for_or_for_each(fcx, decl, expr_ty(fcx.ccx.tcx, seq), + body, id); } ast::expr_while(cond, body) { - check_expr(fcx, cond); + bot = check_expr(fcx, cond); check_block(fcx, body); demand::simple(fcx, cond.span, ty::mk_bool(fcx.ccx.tcx), expr_ty(fcx.ccx.tcx, cond)); @@ -1965,13 +1975,13 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { write::ty_only_fixup(fcx, id, typ); } ast::expr_do_while(body, cond) { - check_expr(fcx, cond); + bot = check_expr(fcx, cond); check_block(fcx, body); let typ = block_ty(fcx.ccx.tcx, body); write::ty_only_fixup(fcx, id, typ); } ast::expr_alt(expr, arms) { - check_expr(fcx, expr); + bot = check_expr(fcx, expr); // Typecheck the patterns first, so that we get types for all the // bindings. @@ -1983,19 +1993,19 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } } // Now typecheck the blocks. - let result_ty = next_ty_var(fcx); + let arm_non_bot = false; for arm: ast::arm in arms { - check_block(fcx, arm.block); + if !check_block(fcx, arm.block) { arm_non_bot = true; } let bty = block_ty(fcx.ccx.tcx, arm.block); - // Failing alt arms don't need to have a matching type if !ty::type_is_bot(fcx.ccx.tcx, bty) { result_ty = demand::simple(fcx, arm.block.span, result_ty, bty); } } + bot |= !arm_non_bot; write::ty_only_fixup(fcx, id, result_ty); } ast::expr_fn(f) { @@ -2010,7 +2020,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { check_fn(fcx.ccx, f, id, some(fcx)); } ast::expr_block(b) { - check_block(fcx, b); + bot = check_block(fcx, b); alt b.node.expr { some(expr) { let typ = expr_ty(fcx.ccx.tcx, expr); @@ -2024,7 +2034,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } ast::expr_bind(f, args) { // Call the generic checker. - check_call_or_bind(fcx, expr.span, f, args, kind_bind); + bot = check_call_or_bind(fcx, expr.span, f, args, kind_bind); // Pull the argument and return types out. let proto_1; @@ -2067,13 +2077,16 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { function name onto purity-designation */ require_pure_call(fcx.ccx, fcx.purity, f, expr.span); - check_call(fcx, expr.span, f, args, kind_call); + bot = check_call(fcx, expr.span, f, args, kind_call); // Pull the return type out of the type of the function. let rt_1; let fty = do_autoderef(fcx, expr.span, ty::expr_ty(fcx.ccx.tcx, f)); alt structure_of(fcx, expr.span, fty) { - ty::ty_fn(_, _, rt, _, _) { rt_1 = rt; } + ty::ty_fn(_, _, rt, cf, _) { + bot |= cf == ast::noreturn; + rt_1 = rt; + } ty::ty_native_fn(_, _, rt) { rt_1 = rt; } _ { log_err "LHS of call expr didn't have a function type?!"; @@ -2092,7 +2105,6 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { alt oinfo { regular_obj(_, obj_id) { let did = local_def(obj_id); - // Try looking up the current object in the type // cache. alt fcx.ccx.tcx.tcache.find(did) { @@ -2139,7 +2151,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); } ast::expr_spawn(_, _, f, args) { - check_call(fcx, expr.span, f, args, kind_spawn); + bot = check_call(fcx, expr.span, f, args, kind_spawn); let fty = expr_ty(fcx.ccx.tcx, f); let ret_ty = ty::ret_ty_of_fn_ty(fcx.ccx.tcx, fty); demand::simple(fcx, f.span, ty::mk_nil(fcx.ccx.tcx), ret_ty); @@ -2156,7 +2168,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { write::ty_only_fixup(fcx, id, typ); } ast::expr_cast(e, t) { - check_expr(fcx, e); + bot = check_expr(fcx, e); let t_1 = ast_ty_to_ty_crate(fcx.ccx, t); // FIXME: there are more forms of cast to support, eventually. @@ -2176,11 +2188,11 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { if ivec::len[@ast::expr](args) == 0u { t = next_ty_var(fcx); } else { - check_expr(fcx, args.(0)); + bot |= check_expr(fcx, args.(0)); t = expr_ty(fcx.ccx.tcx, args.(0)); } - for e: @ast::expr in args { - check_expr(fcx, e); + for e: @ast::expr in args { + bot |= check_expr(fcx, e); let expr_t = expr_ty(fcx.ccx.tcx, e); demand::simple(fcx, expr.span, t, expr_t); } @@ -2197,7 +2209,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { alt base { none. {/* no-op */ } some(b_0) { check_expr(fcx, b_0); } } let fields_t: (spanned[field])[] = ~[]; for f: ast::field in fields { - check_expr(fcx, f.node.expr); + bot |= check_expr(fcx, f.node.expr); let expr_t = expr_ty(fcx.ccx.tcx, f.node.expr); let expr_mt = {ty: expr_t, mut: f.node.mut}; // for the most precise error message, @@ -2213,7 +2225,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { write::ty_only_fixup(fcx, id, typ); } some(bexpr) { - check_expr(fcx, bexpr); + bot |= check_expr(fcx, bexpr); let bexpr_t = expr_ty(fcx.ccx.tcx, bexpr); let base_fields: field[] = ~[]; alt structure_of(fcx, expr.span, bexpr_t) { @@ -2244,7 +2256,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } } ast::expr_field(base, field) { - check_expr(fcx, base); + bot |= check_expr(fcx, base); let base_t = expr_ty(fcx.ccx.tcx, base); base_t = do_autoderef(fcx, expr.span, base_t); alt structure_of(fcx, expr.span, base_t) { @@ -2278,10 +2290,10 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } } ast::expr_index(base, idx) { - check_expr(fcx, base); + bot |= check_expr(fcx, base); let base_t = expr_ty(fcx.ccx.tcx, base); base_t = do_autoderef(fcx, expr.span, base_t); - check_expr(fcx, idx); + bot |= check_expr(fcx, idx); let idx_t = expr_ty(fcx.ccx.tcx, idx); if !type_is_integral(fcx, idx.span, idx_t) { fcx.ccx.tcx.sess.span_fatal(idx.span, @@ -2335,7 +2347,6 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } } ast::expr_anon_obj(ao) { - let fields: ast::anon_obj_field[] = ~[]; alt ao.fields { none. { } some(v) { fields = v; } } @@ -2369,15 +2380,11 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { constrs: out_constrs}; } - fn get_anon_obj_method_types(fcx: @fn_ctxt, ao: &ast::anon_obj, - fields: &ast::anon_obj_field[]) -> - ty::method[] { - - let methods: ty::method[] = ~[]; - + let method_types: ty::method[] = ~[]; + { // Outer methods. for m: @ast::method in ao.methods { - methods += ~[ty_of_method(fcx.ccx, m)]; + method_types += ~[ty_of_method(fcx.ccx, m)]; } // Inner methods. @@ -2392,7 +2399,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { some(e) { // If there's a inner_obj, we push it onto the obj_infos stack // so that self-calls can be checked within its context later. - check_expr(fcx, e); + bot |= check_expr(fcx, e); inner_obj_ty = expr_ty(fcx.ccx.tcx, e); inner_obj_sty = some(structure_of(fcx, e.span, inner_obj_ty)); @@ -2437,11 +2444,9 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { std::ivec::filter_map[ty::method, ty::method](f, inner_obj_methods); - methods += inner_obj_methods; - ret methods; + method_types += inner_obj_methods; } - let method_types = get_anon_obj_method_types(fcx, ao, fields); let ot = ty::mk_obj(fcx.ccx.tcx, ty::sort_methods(method_types)); write::ty_only_fixup(fcx, id, ot); @@ -2467,6 +2472,10 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) { } _ { fcx.ccx.tcx.sess.unimpl("expr type in typeck::check_expr"); } } + if bot { + write::ty_only_fixup(fcx, expr.id, ty::mk_bot(fcx.ccx.tcx)); + } + ret bot; } fn next_ty_var_id(fcx: @fn_ctxt) -> int { @@ -2484,8 +2493,8 @@ fn get_obj_info(ccx: &@crate_ctxt) -> option::t[obj_info] { } fn check_decl_initializer(fcx: &@fn_ctxt, nid: ast::node_id, - init: &ast::initializer) { - check_expr(fcx, init.expr); + init: &ast::initializer) -> bool { + let bot = check_expr(fcx, init.expr); let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.expr.span, nid)); alt init.op { ast::init_assign. { @@ -2502,10 +2511,12 @@ fn check_decl_initializer(fcx: &@fn_ctxt, nid: ast::node_id, expr_ty(fcx.ccx.tcx, init.expr)); } } + ret bot; } -fn check_decl_local(fcx: &@fn_ctxt, local: &@ast::local) { +fn check_decl_local(fcx: &@fn_ctxt, local: &@ast::local) -> bool { let a_id = local.node.id; + let bot = false; alt fcx.locals.find(a_id) { none. { fcx.ccx.tcx.sess.bug("check_decl_local: local id not found " + @@ -2515,40 +2526,65 @@ fn check_decl_local(fcx: &@fn_ctxt, local: &@ast::local) { let t = ty::mk_var(fcx.ccx.tcx, i); write::ty_only_fixup(fcx, a_id, t); alt local.node.init { - some(init) { check_decl_initializer(fcx, local.node.id, init); } + some(init) { + bot = check_decl_initializer(fcx, local.node.id, init); + } _ {/* fall through */ } } } } + ret bot; } -fn check_stmt(fcx: &@fn_ctxt, stmt: &@ast::stmt) { +fn check_stmt(fcx: &@fn_ctxt, stmt: &@ast::stmt) -> bool { let node_id; + let bot = false; alt stmt.node { ast::stmt_decl(decl, id) { node_id = id; alt decl.node { ast::decl_local(ls) { - for l: @ast::local in ls { check_decl_local(fcx, l); } + for l: @ast::local in ls { bot |= check_decl_local(fcx, l); } } ast::decl_item(_) {/* ignore for now */ } } } - ast::stmt_expr(expr, id) { node_id = id; check_expr(fcx, expr); } + ast::stmt_expr(expr, id) { node_id = id; bot = check_expr(fcx, expr); } } write::nil_ty(fcx.ccx.tcx, node_id); + ret bot; } -fn check_block(fcx: &@fn_ctxt, blk: &ast::blk) { - for s: @ast::stmt in blk.node.stmts { check_stmt(fcx, s); } +fn check_block(fcx: &@fn_ctxt, blk: &ast::blk) -> bool { + let bot = false; + let warned = false; + for s: @ast::stmt in blk.node.stmts { + if bot && !warned && + alt s.node { + ast::stmt_decl(@{node: ast::decl_local(_), _}, _) | + ast::stmt_expr(_, _) { true } + _ { false } + } { + fcx.ccx.tcx.sess.span_warn(s.span, "unreachable statement"); + warned = true; + } + bot |= check_stmt(fcx, s); + } alt blk.node.expr { none. { write::nil_ty(fcx.ccx.tcx, blk.node.id); } some(e) { - check_expr(fcx, e); + if bot && !warned { + fcx.ccx.tcx.sess.span_warn(e.span, "unreachable expression"); + } + bot |= check_expr(fcx, e); let ety = expr_ty(fcx.ccx.tcx, e); write::ty_only_fixup(fcx, blk.node.id, ety); } } + if bot { + write::ty_only_fixup(fcx, blk.node.id, ty::mk_bot(fcx.ccx.tcx)); + } + ret bot; } fn check_const(ccx: &@crate_ctxt, sp: &span, e: &@ast::expr, diff --git a/src/lib/ivec.rs b/src/lib/ivec.rs index c710d220a6bb..dd13fcef7d28 100644 --- a/src/lib/ivec.rs +++ b/src/lib/ivec.rs @@ -81,7 +81,7 @@ fn from_mut[T](v: &T[mutable ]) -> T[] { // Predicates pred is_empty[T](v: &T[mutable? ]) -> bool { // FIXME: This would be easier if we could just call len - for t: T in v { ret false; } + for t: T in v { ret false; } ret true; }