Get rid of the hack that ignores () typed things in fn tail position.

Closes #868. Unfortunately, this causes certain invalid programs to
fail type-checking instead of failing type-state when a type-state
error message would probably be more intuitive. (Although, by any
reasonable interpretation of the static semantics, it technically
ought to be a type error.)
This commit is contained in:
Michael Sullivan 2011-08-30 15:45:12 -04:00
parent 498e38b705
commit 722fa00681
5 changed files with 15 additions and 30 deletions

View file

@ -5271,8 +5271,7 @@ fn trans_closure(bcx_maybe: &option::t<@block_ctxt>,
// trans_mod, trans_item, trans_obj, et cetera) and those that do
// (trans_block, trans_expr, et cetera).
let rslt =
if !ty::type_is_nil(cx.ccx.tcx, block_ty) &&
!ty::type_is_bot(cx.ccx.tcx, block_ty) &&
if !ty::type_is_bot(cx.ccx.tcx, block_ty) &&
f.proto != ast::proto_iter {
trans_block(bcx, f.body, save_in(fcx.llretptr))
} else { trans_block(bcx, f.body, return) };

View file

@ -716,7 +716,6 @@ fn find_pre_post_state_block(fcx: &fn_ctxt, pres0: &prestate, b: &blk) ->
}
fn find_pre_post_state_fn(fcx: &fn_ctxt, f: &_fn) -> bool {
let num_constrs = num_constraints(fcx.enclosing);
// All constraints are considered false until proven otherwise.
// This ensures that intersect works correctly.
@ -729,25 +728,20 @@ fn find_pre_post_state_fn(fcx: &fn_ctxt, f: &_fn) -> bool {
}
// Instantiate any constraints on the arguments so we can use them
let tsc;
for c: @constr in f.decl.constraints {
tsc = ast_constr_to_ts_constr(fcx.ccx.tcx, f.decl.inputs, c);
let tsc = ast_constr_to_ts_constr(fcx.ccx.tcx, f.decl.inputs, c);
set_in_prestate_constr(fcx, tsc, block_pre);
}
let changed = find_pre_post_state_block(fcx, block_pre, f.body);
// Treat the tail expression as a return statement
// Treat the tail expression as a return statement
alt f.body.node.expr {
some(tailexpr) {
let tailty = expr_ty(fcx.ccx.tcx, tailexpr);
// Since blocks and alts and ifs that don't have results
// implicitly result in nil, we have to be careful to not
// interpret nil-typed block results as the result of a
// function with some other return type
if !type_is_nil(fcx.ccx.tcx, tailty) &&
!type_is_bot(fcx.ccx.tcx, tailty) {
// We don't want to clear the diverges bit for bottom typed things,
// which really do diverge. I feel like there is a cleaner way
// to do this than checking the type.
if !type_is_bot(fcx.ccx.tcx, expr_ty(fcx.ccx.tcx, tailexpr)) {
let post = false_postcond(num_constrs);
// except for the "diverges" bit...
kill_poststate_(fcx, fcx.enclosing.i_diverge, post);

View file

@ -2692,22 +2692,14 @@ fn check_fn(ccx: &@crate_ctxt, f: &ast::_fn, id: &ast::node_id,
// function result type, if there is a tail expr.
// We don't do this check for an iterator, as the tail expr doesn't
// have to have the result type of the iterator.
if option::is_some(body.node.expr) && f.proto != ast::proto_iter {
let tail_expr = option::get(body.node.expr);
// The use of resolve_type_vars_if_possible makes me very
// afraid :-(
let tail_expr_ty =
resolve_type_vars_if_possible(fcx, expr_ty(ccx.tcx, tail_expr));
// Hacky compromise: use eq and not are_compatible
// This allows things like while loops and ifs with no
// else to appear in tail position without a trailing
// semicolon when the return type is non-nil, while
// making sure to unify the tailexpr-type with the result
// type when the tailexpr-type is just a type variable.
if !ty::eq_ty(tail_expr_ty, ty::mk_nil(ccx.tcx)) {
alt (body.node.expr) {
some(tail_expr) {
if f.proto != ast::proto_iter {
let tail_expr_ty = expr_ty(ccx.tcx, tail_expr);
demand::simple(fcx, tail_expr.span, fcx.ret_ty, tail_expr_ty);
}
}
none. {}
}
// If we don't have any enclosing function scope, it is time to

View file

@ -1,5 +1,5 @@
// -*- rust -*-
// error-pattern: not all control paths return
// error-pattern: mismatched types
fn god_exists(a: int) -> bool { be god_exists(a); }

View file

@ -1,4 +1,4 @@
// error-pattern: return
// error-pattern: mismatched types
fn f() -> int {