Track failures in typeck, assign proper type to failing blocks
(and warn for unreachable statements) Closes #727
This commit is contained in:
parent
9705f97ead
commit
aa3b89610e
2 changed files with 127 additions and 91 deletions
|
@ -186,7 +186,6 @@ fn instantiate_path(fcx: &@fn_ctxt, pth: &ast::path,
|
||||||
fcx.ccx.tcx.sess.span_fatal(sp,
|
fcx.ccx.tcx.sess.span_fatal(sp,
|
||||||
"this item does not take type \
|
"this item does not take type \
|
||||||
parameters");
|
parameters");
|
||||||
fail;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We will acquire the type parameters through unification.
|
// 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 " +
|
// fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " +
|
||||||
// syntax::print::pprust::expr_to_str(expr));
|
// syntax::print::pprust::expr_to_str(expr));
|
||||||
|
|
||||||
|
@ -1524,9 +1523,9 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
|
||||||
// expressions.
|
// expressions.
|
||||||
fn check_call_or_bind(fcx: &@fn_ctxt, sp: &span, f: &@ast::expr,
|
fn check_call_or_bind(fcx: &@fn_ctxt, sp: &span, f: &@ast::expr,
|
||||||
args: &(option::t[@ast::expr])[],
|
args: &(option::t[@ast::expr])[],
|
||||||
call_kind: call_kind) {
|
call_kind: call_kind) -> bool {
|
||||||
// Check the function.
|
// Check the function.
|
||||||
check_expr(fcx, f);
|
let bot = check_expr(fcx, f);
|
||||||
|
|
||||||
// Get the function type.
|
// Get the function type.
|
||||||
let fty = expr_ty(fcx.ccx.tcx, f);
|
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.
|
// Grab the argument types and the return type.
|
||||||
let arg_tys;
|
let arg_tys;
|
||||||
alt structure_of(fcx, sp, fty_stripped) {
|
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; }
|
ty::ty_native_fn(_, arg_tys_0, _) { arg_tys = arg_tys_0; }
|
||||||
_ {
|
_ {
|
||||||
fcx.ccx.tcx.sess.span_fatal(f.span,
|
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 {
|
for a_opt: option::t[@ast::expr] in args {
|
||||||
alt a_opt {
|
alt a_opt {
|
||||||
some(a) {
|
some(a) {
|
||||||
check_expr(fcx, a);
|
bot |= check_expr(fcx, a);
|
||||||
demand::full(fcx, a.span, arg_tys.(i).ty,
|
demand::full(fcx, a.span, arg_tys.(i).ty,
|
||||||
expr_ty(fcx.ccx.tcx, a), ~[],
|
expr_ty(fcx.ccx.tcx, a), ~[],
|
||||||
AUTODEREF_BLOCK_COERCE);
|
AUTODEREF_BLOCK_COERCE);
|
||||||
|
@ -1585,47 +1584,49 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
|
||||||
}
|
}
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
|
ret bot;
|
||||||
}
|
}
|
||||||
// A generic function for checking assignment expressions
|
// A generic function for checking assignment expressions
|
||||||
|
|
||||||
fn check_assignment(fcx: &@fn_ctxt, sp: &span, lhs: &@ast::expr,
|
fn check_assignment(fcx: &@fn_ctxt, sp: &span, lhs: &@ast::expr,
|
||||||
rhs: &@ast::expr, id: &ast::node_id) {
|
rhs: &@ast::expr, id: &ast::node_id) -> bool {
|
||||||
check_expr(fcx, lhs);
|
let bot = check_expr(fcx, lhs) | check_expr(fcx, rhs);
|
||||||
check_expr(fcx, rhs);
|
|
||||||
demand::simple(fcx, sp, expr_ty(fcx.ccx.tcx, lhs),
|
demand::simple(fcx, sp, expr_ty(fcx.ccx.tcx, lhs),
|
||||||
expr_ty(fcx.ccx.tcx, rhs));
|
expr_ty(fcx.ccx.tcx, rhs));
|
||||||
write::ty_only_fixup(fcx, id, ty::mk_nil(fcx.ccx.tcx));
|
write::ty_only_fixup(fcx, id, ty::mk_nil(fcx.ccx.tcx));
|
||||||
|
ret bot;
|
||||||
}
|
}
|
||||||
// A generic function for checking call expressions
|
// A generic function for checking call expressions
|
||||||
|
|
||||||
fn check_call(fcx: &@fn_ctxt, sp: &span, f: &@ast::expr,
|
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])[] = ~[];
|
let args_opt_0: (option::t[@ast::expr])[] = ~[];
|
||||||
for arg: @ast::expr in args {
|
for arg: @ast::expr in args {
|
||||||
args_opt_0 += ~[some[@ast::expr](arg)];
|
args_opt_0 += ~[some[@ast::expr](arg)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the generic checker.
|
// 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
|
// A generic function for checking for or for-each loops
|
||||||
|
|
||||||
fn check_for_or_for_each(fcx: &@fn_ctxt, local: &@ast::local,
|
fn check_for_or_for_each(fcx: &@fn_ctxt, local: &@ast::local,
|
||||||
element_ty: &ty::t, body: &ast::blk,
|
element_ty: &ty::t, body: &ast::blk,
|
||||||
node_id: ast::node_id) {
|
node_id: ast::node_id) -> bool {
|
||||||
check_decl_local(fcx, local);
|
let bot = check_decl_local(fcx, local);
|
||||||
check_block(fcx, body);
|
check_block(fcx, body);
|
||||||
// Unify type of decl with element type of the seq
|
// Unify type of decl with element type of the seq
|
||||||
demand::simple(fcx, local.span, ty::decl_local_ty(fcx.ccx.tcx, local),
|
demand::simple(fcx, local.span, ty::decl_local_ty(fcx.ccx.tcx, local),
|
||||||
element_ty);
|
element_ty);
|
||||||
let typ = ty::mk_nil(fcx.ccx.tcx);
|
let typ = ty::mk_nil(fcx.ccx.tcx);
|
||||||
write::ty_only_fixup(fcx, node_id, typ);
|
write::ty_only_fixup(fcx, node_id, typ);
|
||||||
|
ret bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A generic function for checking the pred in a check
|
// A generic function for checking the pred in a check
|
||||||
// or if-check
|
// or if-check
|
||||||
fn check_pred_expr(fcx: &@fn_ctxt, e: &@ast::expr) {
|
fn check_pred_expr(fcx: &@fn_ctxt, e: &@ast::expr) -> bool {
|
||||||
check_expr(fcx, e);
|
let bot = check_expr(fcx, e);
|
||||||
demand::simple(fcx, e.span, ty::mk_bool(fcx.ccx.tcx),
|
demand::simple(fcx, e.span, ty::mk_bool(fcx.ccx.tcx),
|
||||||
expr_ty(fcx.ccx.tcx, e));
|
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"); }
|
_ { 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
|
// A generic function for checking the then and else in an if
|
||||||
// or if-check
|
// or if-check
|
||||||
fn check_then_else(fcx: &@fn_ctxt, thn: &ast::blk,
|
fn check_then_else(fcx: &@fn_ctxt, thn: &ast::blk,
|
||||||
elsopt: &option::t[@ast::expr], id: ast::node_id,
|
elsopt: &option::t[@ast::expr], id: ast::node_id,
|
||||||
sp: &span) {
|
sp: &span) -> bool {
|
||||||
check_block(fcx, thn);
|
let then_bot = check_block(fcx, thn);
|
||||||
|
let els_bot = false;
|
||||||
let if_t =
|
let if_t =
|
||||||
alt elsopt {
|
alt elsopt {
|
||||||
some(els) {
|
some(els) {
|
||||||
check_expr(fcx, els);
|
els_bot = check_expr(fcx, els);
|
||||||
let thn_t = block_ty(fcx.ccx.tcx, thn);
|
let thn_t = block_ty(fcx.ccx.tcx, thn);
|
||||||
let elsopt_t = expr_ty(fcx.ccx.tcx, els);
|
let elsopt_t = expr_ty(fcx.ccx.tcx, els);
|
||||||
demand::simple(fcx, sp, thn_t, elsopt_t);
|
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) }
|
none. { ty::mk_nil(fcx.ccx.tcx) }
|
||||||
};
|
};
|
||||||
write::ty_only_fixup(fcx, id, if_t);
|
write::ty_only_fixup(fcx, id, if_t);
|
||||||
|
ret then_bot & els_bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks the compatibility
|
// Checks the compatibility
|
||||||
|
@ -1704,14 +1708,19 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = expr.id;
|
let id = expr.id;
|
||||||
|
let bot = false;
|
||||||
alt expr.node {
|
alt expr.node {
|
||||||
ast::expr_lit(lit) {
|
ast::expr_lit(lit) {
|
||||||
let typ = check_lit(fcx.ccx, lit);
|
let typ = check_lit(fcx.ccx, lit);
|
||||||
write::ty_only_fixup(fcx, id, typ);
|
write::ty_only_fixup(fcx, id, typ);
|
||||||
}
|
}
|
||||||
ast::expr_binary(binop, lhs, rhs) {
|
ast::expr_binary(binop, lhs, rhs) {
|
||||||
check_expr(fcx, lhs);
|
bot = check_expr(fcx, lhs);
|
||||||
check_expr(fcx, rhs);
|
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 lhs_t = expr_ty(fcx.ccx.tcx, lhs);
|
||||||
let rhs_t = expr_ty(fcx.ccx.tcx, rhs);
|
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);
|
write::ty_only_fixup(fcx, id, t);
|
||||||
}
|
}
|
||||||
ast::expr_unary(unop, oper) {
|
ast::expr_unary(unop, oper) {
|
||||||
check_expr(fcx, oper);
|
bot = check_expr(fcx, oper);
|
||||||
let oper_t = expr_ty(fcx.ccx.tcx, oper);
|
let oper_t = expr_ty(fcx.ccx.tcx, oper);
|
||||||
alt unop {
|
alt unop {
|
||||||
ast::box(mut) {
|
ast::box(mut) {
|
||||||
|
@ -1787,7 +1796,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
|
||||||
if ty::def_has_ty_params(defn) {
|
if ty::def_has_ty_params(defn) {
|
||||||
let path_tpot = instantiate_path(fcx, pth, tpt, expr.span);
|
let path_tpot = instantiate_path(fcx, pth, tpt, expr.span);
|
||||||
write::ty_fixup(fcx, id, path_tpot);
|
write::ty_fixup(fcx, id, path_tpot);
|
||||||
ret;
|
ret false;
|
||||||
}
|
}
|
||||||
// The definition doesn't take type parameters. If the programmer
|
// The definition doesn't take type parameters. If the programmer
|
||||||
// supplied some, that's an error.
|
// 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_mac(_) { fcx.ccx.tcx.sess.bug("unexpanded macro"); }
|
||||||
ast::expr_fail(expr_opt) {
|
ast::expr_fail(expr_opt) {
|
||||||
|
bot = true;
|
||||||
alt expr_opt {
|
alt expr_opt {
|
||||||
none. {/* do nothing */ }
|
none. {/* do nothing */ }
|
||||||
some(e) {
|
some(e) {
|
||||||
|
@ -1812,9 +1822,10 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
|
||||||
}
|
}
|
||||||
write::bot_ty(fcx.ccx.tcx, id);
|
write::bot_ty(fcx.ccx.tcx, id);
|
||||||
}
|
}
|
||||||
ast::expr_break. { 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); }
|
ast::expr_cont. { write::bot_ty(fcx.ccx.tcx, id); bot = true; }
|
||||||
ast::expr_ret(expr_opt) {
|
ast::expr_ret(expr_opt) {
|
||||||
|
bot = true;
|
||||||
alt expr_opt {
|
alt expr_opt {
|
||||||
none. {
|
none. {
|
||||||
let nil = ty::mk_nil(fcx.ccx.tcx);
|
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);
|
write::nil_ty(fcx.ccx.tcx, id);
|
||||||
}
|
}
|
||||||
some(e) {
|
some(e) {
|
||||||
check_expr(fcx, e);
|
bot = check_expr(fcx, e);
|
||||||
demand::simple(fcx, expr.span, fcx.ret_ty,
|
demand::simple(fcx, expr.span, fcx.ret_ty,
|
||||||
expr_ty(fcx.ccx.tcx, e));
|
expr_ty(fcx.ccx.tcx, e));
|
||||||
write::nil_ty(fcx.ccx.tcx, id);
|
write::nil_ty(fcx.ccx.tcx, id);
|
||||||
|
@ -1855,55 +1866,54 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
|
||||||
}
|
}
|
||||||
ast::expr_be(e) {
|
ast::expr_be(e) {
|
||||||
// FIXME: prove instead of assert
|
// FIXME: prove instead of assert
|
||||||
|
|
||||||
assert (ast::is_call_expr(e));
|
assert (ast::is_call_expr(e));
|
||||||
check_expr(fcx, e);
|
check_expr(fcx, e);
|
||||||
|
bot = true;
|
||||||
demand::simple(fcx, e.span, fcx.ret_ty, expr_ty(fcx.ccx.tcx, e));
|
demand::simple(fcx, e.span, fcx.ret_ty, expr_ty(fcx.ccx.tcx, e));
|
||||||
write::nil_ty(fcx.ccx.tcx, id);
|
write::nil_ty(fcx.ccx.tcx, id);
|
||||||
}
|
}
|
||||||
ast::expr_log(l, e) {
|
ast::expr_log(l, e) {
|
||||||
check_expr(fcx, e);
|
bot = check_expr(fcx, e);
|
||||||
write::nil_ty(fcx.ccx.tcx, id);
|
write::nil_ty(fcx.ccx.tcx, id);
|
||||||
}
|
}
|
||||||
ast::expr_check(_, e) {
|
ast::expr_check(_, e) {
|
||||||
check_pred_expr(fcx, e);
|
bot = check_pred_expr(fcx, e);
|
||||||
write::nil_ty(fcx.ccx.tcx, id);
|
write::nil_ty(fcx.ccx.tcx, id);
|
||||||
}
|
}
|
||||||
ast::expr_if_check(cond, thn, elsopt) {
|
ast::expr_if_check(cond, thn, elsopt) {
|
||||||
check_pred_expr(fcx, cond);
|
bot = check_pred_expr(fcx, cond) |
|
||||||
check_then_else(fcx, thn, elsopt, id, expr.span);
|
check_then_else(fcx, thn, elsopt, id, expr.span);
|
||||||
}
|
}
|
||||||
ast::expr_ternary(_, _, _) {
|
ast::expr_ternary(_, _, _) {
|
||||||
check_expr(fcx, ast::ternary_to_if(expr));
|
bot = check_expr(fcx, ast::ternary_to_if(expr));
|
||||||
}
|
}
|
||||||
ast::expr_assert(e) {
|
ast::expr_assert(e) {
|
||||||
check_expr(fcx, e);
|
bot = check_expr(fcx, e);
|
||||||
let ety = expr_ty(fcx.ccx.tcx, e);
|
let ety = expr_ty(fcx.ccx.tcx, e);
|
||||||
demand::simple(fcx, expr.span, ty::mk_bool(fcx.ccx.tcx), ety);
|
demand::simple(fcx, expr.span, ty::mk_bool(fcx.ccx.tcx), ety);
|
||||||
write::nil_ty(fcx.ccx.tcx, id);
|
write::nil_ty(fcx.ccx.tcx, id);
|
||||||
}
|
}
|
||||||
ast::expr_move(lhs, rhs) {
|
ast::expr_move(lhs, rhs) {
|
||||||
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
|
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) {
|
ast::expr_assign(lhs, rhs) {
|
||||||
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
|
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) {
|
ast::expr_swap(lhs, rhs) {
|
||||||
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
|
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) {
|
ast::expr_assign_op(op, lhs, rhs) {
|
||||||
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
|
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),
|
check_binop_type_compat(fcx, expr.span, expr_ty(fcx.ccx.tcx, lhs),
|
||||||
op);
|
op);
|
||||||
}
|
}
|
||||||
ast::expr_send(lhs, rhs) {
|
ast::expr_send(lhs, rhs) {
|
||||||
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
|
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
|
||||||
check_expr(fcx, lhs);
|
bot = check_expr(fcx, lhs) | check_expr(fcx, rhs);
|
||||||
check_expr(fcx, rhs);
|
|
||||||
let rhs_t = expr_ty(fcx.ccx.tcx, rhs);
|
let rhs_t = expr_ty(fcx.ccx.tcx, rhs);
|
||||||
let chan_t = ty::mk_chan(fcx.ccx.tcx, rhs_t);
|
let chan_t = ty::mk_chan(fcx.ccx.tcx, rhs_t);
|
||||||
let lhs_t = expr_ty(fcx.ccx.tcx, lhs);
|
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) {
|
ast::expr_recv(lhs, rhs) {
|
||||||
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
|
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
|
||||||
check_expr(fcx, lhs);
|
bot = check_expr(fcx, lhs) | check_expr(fcx, rhs);
|
||||||
check_expr(fcx, rhs);
|
|
||||||
let item_t = expr_ty(fcx.ccx.tcx, rhs);
|
let item_t = expr_ty(fcx.ccx.tcx, rhs);
|
||||||
let port_t = ty::mk_port(fcx.ccx.tcx, item_t);
|
let port_t = ty::mk_port(fcx.ccx.tcx, item_t);
|
||||||
demand::simple(fcx, expr.span, port_t, expr_ty(fcx.ccx.tcx, lhs));
|
demand::simple(fcx, expr.span, port_t, expr_ty(fcx.ccx.tcx, lhs));
|
||||||
write::ty_only_fixup(fcx, id, item_t);
|
write::ty_only_fixup(fcx, id, item_t);
|
||||||
}
|
}
|
||||||
ast::expr_if(cond, thn, elsopt) {
|
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),
|
demand::simple(fcx, cond.span, ty::mk_bool(fcx.ccx.tcx),
|
||||||
expr_ty(fcx.ccx.tcx, cond));
|
expr_ty(fcx.ccx.tcx, cond));
|
||||||
check_then_else(fcx, thn, elsopt, id, expr.span);
|
|
||||||
}
|
}
|
||||||
ast::expr_for(decl, seq, body) {
|
ast::expr_for(decl, seq, body) {
|
||||||
check_expr(fcx, seq);
|
bot = check_expr(fcx, seq);
|
||||||
let elt_ty;
|
let elt_ty;
|
||||||
let ety = expr_ty(fcx.ccx.tcx, seq);
|
let ety = expr_ty(fcx.ccx.tcx, seq);
|
||||||
alt structure_of(fcx, expr.span, ety) {
|
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));
|
+ "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) {
|
ast::expr_for_each(decl, seq, body) {
|
||||||
check_expr(fcx, seq);
|
bot = check_expr(fcx, seq) |
|
||||||
check_for_or_for_each(fcx, decl, expr_ty(fcx.ccx.tcx, seq), body, id);
|
check_for_or_for_each(fcx, decl, expr_ty(fcx.ccx.tcx, seq),
|
||||||
|
body, id);
|
||||||
}
|
}
|
||||||
ast::expr_while(cond, body) {
|
ast::expr_while(cond, body) {
|
||||||
check_expr(fcx, cond);
|
bot = check_expr(fcx, cond);
|
||||||
check_block(fcx, body);
|
check_block(fcx, body);
|
||||||
demand::simple(fcx, cond.span, ty::mk_bool(fcx.ccx.tcx),
|
demand::simple(fcx, cond.span, ty::mk_bool(fcx.ccx.tcx),
|
||||||
expr_ty(fcx.ccx.tcx, cond));
|
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);
|
write::ty_only_fixup(fcx, id, typ);
|
||||||
}
|
}
|
||||||
ast::expr_do_while(body, cond) {
|
ast::expr_do_while(body, cond) {
|
||||||
check_expr(fcx, cond);
|
bot = check_expr(fcx, cond);
|
||||||
check_block(fcx, body);
|
check_block(fcx, body);
|
||||||
let typ = block_ty(fcx.ccx.tcx, body);
|
let typ = block_ty(fcx.ccx.tcx, body);
|
||||||
write::ty_only_fixup(fcx, id, typ);
|
write::ty_only_fixup(fcx, id, typ);
|
||||||
}
|
}
|
||||||
ast::expr_alt(expr, arms) {
|
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
|
// Typecheck the patterns first, so that we get types for all the
|
||||||
// bindings.
|
// bindings.
|
||||||
|
|
||||||
|
@ -1983,19 +1993,19 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Now typecheck the blocks.
|
// Now typecheck the blocks.
|
||||||
|
|
||||||
let result_ty = next_ty_var(fcx);
|
let result_ty = next_ty_var(fcx);
|
||||||
|
let arm_non_bot = false;
|
||||||
for arm: ast::arm in arms {
|
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);
|
let bty = block_ty(fcx.ccx.tcx, arm.block);
|
||||||
|
|
||||||
|
|
||||||
// Failing alt arms don't need to have a matching type
|
// Failing alt arms don't need to have a matching type
|
||||||
if !ty::type_is_bot(fcx.ccx.tcx, bty) {
|
if !ty::type_is_bot(fcx.ccx.tcx, bty) {
|
||||||
result_ty =
|
result_ty =
|
||||||
demand::simple(fcx, arm.block.span, result_ty, bty);
|
demand::simple(fcx, arm.block.span, result_ty, bty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bot |= !arm_non_bot;
|
||||||
write::ty_only_fixup(fcx, id, result_ty);
|
write::ty_only_fixup(fcx, id, result_ty);
|
||||||
}
|
}
|
||||||
ast::expr_fn(f) {
|
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));
|
check_fn(fcx.ccx, f, id, some(fcx));
|
||||||
}
|
}
|
||||||
ast::expr_block(b) {
|
ast::expr_block(b) {
|
||||||
check_block(fcx, b);
|
bot = check_block(fcx, b);
|
||||||
alt b.node.expr {
|
alt b.node.expr {
|
||||||
some(expr) {
|
some(expr) {
|
||||||
let typ = expr_ty(fcx.ccx.tcx, 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) {
|
ast::expr_bind(f, args) {
|
||||||
// Call the generic checker.
|
// 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.
|
// Pull the argument and return types out.
|
||||||
let proto_1;
|
let proto_1;
|
||||||
|
@ -2067,13 +2077,16 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
|
||||||
function name onto purity-designation */
|
function name onto purity-designation */
|
||||||
|
|
||||||
require_pure_call(fcx.ccx, fcx.purity, f, expr.span);
|
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.
|
// Pull the return type out of the type of the function.
|
||||||
|
|
||||||
let rt_1;
|
let rt_1;
|
||||||
let fty = do_autoderef(fcx, expr.span, ty::expr_ty(fcx.ccx.tcx, f));
|
let fty = do_autoderef(fcx, expr.span, ty::expr_ty(fcx.ccx.tcx, f));
|
||||||
alt structure_of(fcx, expr.span, fty) {
|
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; }
|
ty::ty_native_fn(_, _, rt) { rt_1 = rt; }
|
||||||
_ {
|
_ {
|
||||||
log_err "LHS of call expr didn't have a function type?!";
|
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 {
|
alt oinfo {
|
||||||
regular_obj(_, obj_id) {
|
regular_obj(_, obj_id) {
|
||||||
let did = local_def(obj_id);
|
let did = local_def(obj_id);
|
||||||
|
|
||||||
// Try looking up the current object in the type
|
// Try looking up the current object in the type
|
||||||
// cache.
|
// cache.
|
||||||
alt fcx.ccx.tcx.tcache.find(did) {
|
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);
|
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
|
||||||
}
|
}
|
||||||
ast::expr_spawn(_, _, f, args) {
|
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 fty = expr_ty(fcx.ccx.tcx, f);
|
||||||
let ret_ty = ty::ret_ty_of_fn_ty(fcx.ccx.tcx, fty);
|
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);
|
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);
|
write::ty_only_fixup(fcx, id, typ);
|
||||||
}
|
}
|
||||||
ast::expr_cast(e, t) {
|
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);
|
let t_1 = ast_ty_to_ty_crate(fcx.ccx, t);
|
||||||
// FIXME: there are more forms of cast to support, eventually.
|
// 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 {
|
if ivec::len[@ast::expr](args) == 0u {
|
||||||
t = next_ty_var(fcx);
|
t = next_ty_var(fcx);
|
||||||
} else {
|
} else {
|
||||||
check_expr(fcx, args.(0));
|
bot |= check_expr(fcx, args.(0));
|
||||||
t = expr_ty(fcx.ccx.tcx, args.(0));
|
t = expr_ty(fcx.ccx.tcx, args.(0));
|
||||||
}
|
}
|
||||||
for e: @ast::expr in args {
|
for e: @ast::expr in args {
|
||||||
check_expr(fcx, e);
|
bot |= check_expr(fcx, e);
|
||||||
let expr_t = expr_ty(fcx.ccx.tcx, e);
|
let expr_t = expr_ty(fcx.ccx.tcx, e);
|
||||||
demand::simple(fcx, expr.span, t, expr_t);
|
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); } }
|
alt base { none. {/* no-op */ } some(b_0) { check_expr(fcx, b_0); } }
|
||||||
let fields_t: (spanned[field])[] = ~[];
|
let fields_t: (spanned[field])[] = ~[];
|
||||||
for f: ast::field in fields {
|
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_t = expr_ty(fcx.ccx.tcx, f.node.expr);
|
||||||
let expr_mt = {ty: expr_t, mut: f.node.mut};
|
let expr_mt = {ty: expr_t, mut: f.node.mut};
|
||||||
// for the most precise error message,
|
// 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);
|
write::ty_only_fixup(fcx, id, typ);
|
||||||
}
|
}
|
||||||
some(bexpr) {
|
some(bexpr) {
|
||||||
check_expr(fcx, bexpr);
|
bot |= check_expr(fcx, bexpr);
|
||||||
let bexpr_t = expr_ty(fcx.ccx.tcx, bexpr);
|
let bexpr_t = expr_ty(fcx.ccx.tcx, bexpr);
|
||||||
let base_fields: field[] = ~[];
|
let base_fields: field[] = ~[];
|
||||||
alt structure_of(fcx, expr.span, bexpr_t) {
|
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) {
|
ast::expr_field(base, field) {
|
||||||
check_expr(fcx, base);
|
bot |= check_expr(fcx, base);
|
||||||
let base_t = expr_ty(fcx.ccx.tcx, base);
|
let base_t = expr_ty(fcx.ccx.tcx, base);
|
||||||
base_t = do_autoderef(fcx, expr.span, base_t);
|
base_t = do_autoderef(fcx, expr.span, base_t);
|
||||||
alt structure_of(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) {
|
ast::expr_index(base, idx) {
|
||||||
check_expr(fcx, base);
|
bot |= check_expr(fcx, base);
|
||||||
let base_t = expr_ty(fcx.ccx.tcx, base);
|
let base_t = expr_ty(fcx.ccx.tcx, base);
|
||||||
base_t = do_autoderef(fcx, expr.span, base_t);
|
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);
|
let idx_t = expr_ty(fcx.ccx.tcx, idx);
|
||||||
if !type_is_integral(fcx, idx.span, idx_t) {
|
if !type_is_integral(fcx, idx.span, idx_t) {
|
||||||
fcx.ccx.tcx.sess.span_fatal(idx.span,
|
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) {
|
ast::expr_anon_obj(ao) {
|
||||||
|
|
||||||
let fields: ast::anon_obj_field[] = ~[];
|
let fields: ast::anon_obj_field[] = ~[];
|
||||||
alt ao.fields { none. { } some(v) { fields = v; } }
|
alt ao.fields { none. { } some(v) { fields = v; } }
|
||||||
|
|
||||||
|
@ -2369,15 +2380,11 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
|
||||||
constrs: out_constrs};
|
constrs: out_constrs};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_anon_obj_method_types(fcx: @fn_ctxt, ao: &ast::anon_obj,
|
let method_types: ty::method[] = ~[];
|
||||||
fields: &ast::anon_obj_field[]) ->
|
{
|
||||||
ty::method[] {
|
|
||||||
|
|
||||||
let methods: ty::method[] = ~[];
|
|
||||||
|
|
||||||
// Outer methods.
|
// Outer methods.
|
||||||
for m: @ast::method in ao.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.
|
// Inner methods.
|
||||||
|
@ -2392,7 +2399,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) {
|
||||||
some(e) {
|
some(e) {
|
||||||
// If there's a inner_obj, we push it onto the obj_infos stack
|
// 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.
|
// 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_ty = expr_ty(fcx.ccx.tcx, e);
|
||||||
inner_obj_sty = some(structure_of(fcx, e.span, inner_obj_ty));
|
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,
|
std::ivec::filter_map[ty::method,
|
||||||
ty::method](f, inner_obj_methods);
|
ty::method](f, inner_obj_methods);
|
||||||
|
|
||||||
methods += inner_obj_methods;
|
method_types += inner_obj_methods;
|
||||||
ret 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));
|
let ot = ty::mk_obj(fcx.ccx.tcx, ty::sort_methods(method_types));
|
||||||
|
|
||||||
write::ty_only_fixup(fcx, id, ot);
|
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"); }
|
_ { 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 {
|
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,
|
fn check_decl_initializer(fcx: &@fn_ctxt, nid: ast::node_id,
|
||||||
init: &ast::initializer) {
|
init: &ast::initializer) -> bool {
|
||||||
check_expr(fcx, init.expr);
|
let bot = check_expr(fcx, init.expr);
|
||||||
let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.expr.span, nid));
|
let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.expr.span, nid));
|
||||||
alt init.op {
|
alt init.op {
|
||||||
ast::init_assign. {
|
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));
|
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 a_id = local.node.id;
|
||||||
|
let bot = false;
|
||||||
alt fcx.locals.find(a_id) {
|
alt fcx.locals.find(a_id) {
|
||||||
none. {
|
none. {
|
||||||
fcx.ccx.tcx.sess.bug("check_decl_local: local id not found " +
|
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);
|
let t = ty::mk_var(fcx.ccx.tcx, i);
|
||||||
write::ty_only_fixup(fcx, a_id, t);
|
write::ty_only_fixup(fcx, a_id, t);
|
||||||
alt local.node.init {
|
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 */ }
|
_ {/* 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 node_id;
|
||||||
|
let bot = false;
|
||||||
alt stmt.node {
|
alt stmt.node {
|
||||||
ast::stmt_decl(decl, id) {
|
ast::stmt_decl(decl, id) {
|
||||||
node_id = id;
|
node_id = id;
|
||||||
alt decl.node {
|
alt decl.node {
|
||||||
ast::decl_local(ls) {
|
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::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);
|
write::nil_ty(fcx.ccx.tcx, node_id);
|
||||||
|
ret bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_block(fcx: &@fn_ctxt, blk: &ast::blk) {
|
fn check_block(fcx: &@fn_ctxt, blk: &ast::blk) -> bool {
|
||||||
for s: @ast::stmt in blk.node.stmts { check_stmt(fcx, s); }
|
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 {
|
alt blk.node.expr {
|
||||||
none. { write::nil_ty(fcx.ccx.tcx, blk.node.id); }
|
none. { write::nil_ty(fcx.ccx.tcx, blk.node.id); }
|
||||||
some(e) {
|
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);
|
let ety = expr_ty(fcx.ccx.tcx, e);
|
||||||
write::ty_only_fixup(fcx, blk.node.id, ety);
|
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,
|
fn check_const(ccx: &@crate_ctxt, sp: &span, e: &@ast::expr,
|
||||||
|
|
|
@ -81,7 +81,7 @@ fn from_mut[T](v: &T[mutable ]) -> T[] {
|
||||||
// Predicates
|
// Predicates
|
||||||
pred is_empty[T](v: &T[mutable? ]) -> bool {
|
pred is_empty[T](v: &T[mutable? ]) -> bool {
|
||||||
// FIXME: This would be easier if we could just call len
|
// 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;
|
ret true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue