From 722fa00681fe1d9538cb904e9a9489ac79bf7b5e Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Tue, 30 Aug 2011 15:45:12 -0400 Subject: [PATCH] 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.) --- src/comp/middle/trans.rs | 3 +-- src/comp/middle/tstate/states.rs | 18 ++++++------------ src/comp/middle/typeck.rs | 20 ++++++-------------- src/test/compile-fail/forgot-ret.rs | 2 +- src/test/compile-fail/missing-return2.rs | 2 +- 5 files changed, 15 insertions(+), 30 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index e6f0c7263105..56d3d19553f5 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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) }; diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index bc2beb35f5d5..915a9d6b9413 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -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); diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index bd49a7ef5fc8..215b042331b4 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -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 diff --git a/src/test/compile-fail/forgot-ret.rs b/src/test/compile-fail/forgot-ret.rs index 5d91e3212df5..65d7db8b30e9 100644 --- a/src/test/compile-fail/forgot-ret.rs +++ b/src/test/compile-fail/forgot-ret.rs @@ -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); } diff --git a/src/test/compile-fail/missing-return2.rs b/src/test/compile-fail/missing-return2.rs index 0fc48fd950a4..446dacdf4f9c 100644 --- a/src/test/compile-fail/missing-return2.rs +++ b/src/test/compile-fail/missing-return2.rs @@ -1,4 +1,4 @@ -// error-pattern: return +// error-pattern: mismatched types fn f() -> int {