Allow pure fns to have any return type
This commit is contained in:
parent
4dd23f24d6
commit
e241f2996d
5 changed files with 47 additions and 15 deletions
|
@ -55,6 +55,7 @@ export hash_ty;
|
|||
export idx_nil;
|
||||
export is_lval;
|
||||
export is_binopable;
|
||||
export is_pred_ty;
|
||||
export item_table;
|
||||
export lookup_item_type;
|
||||
export method;
|
||||
|
@ -1737,6 +1738,12 @@ fn is_fn_ty(cx: &ctxt, fty: t) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
// Just checks whether it's a fn that returns bool,
|
||||
// not its purity.
|
||||
fn is_pred_ty(cx: &ctxt, fty:t) -> bool {
|
||||
is_fn_ty(cx, fty) && type_is_bool(cx, ty_fn_ret(cx, fty))
|
||||
}
|
||||
|
||||
fn ty_var_id(cx: &ctxt, typ: t) -> int {
|
||||
alt struct(cx, typ) {
|
||||
ty::ty_var(vid) { ret vid; }
|
||||
|
|
|
@ -1715,6 +1715,11 @@ fn check_expr_with_unifier(fcx: &@fn_ctxt, expr: &@ast::expr, unify: &unifier,
|
|||
literals or slots */
|
||||
alt e.node {
|
||||
ast::expr_call(operator, operands) {
|
||||
if !ty::is_pred_ty(fcx.ccx.tcx, expr_ty(fcx.ccx.tcx, operator)) {
|
||||
fcx.ccx.tcx.sess.span_fatal(operator.span,
|
||||
"Operator in constraint has non-boolean return type");
|
||||
}
|
||||
|
||||
alt operator.node {
|
||||
ast::expr_path(oper_name) {
|
||||
alt fcx.ccx.tcx.def_map.find(operator.id) {
|
||||
|
@ -1723,7 +1728,7 @@ fn check_expr_with_unifier(fcx: &@fn_ctxt, expr: &@ast::expr, unify: &unifier,
|
|||
}
|
||||
_ {
|
||||
fcx.ccx.tcx.sess.span_fatal(operator.span,
|
||||
"non-predicate as operator \
|
||||
"Impure function as operator \
|
||||
in constraint");
|
||||
}
|
||||
}
|
||||
|
@ -2596,18 +2601,6 @@ fn check_fn(ccx: &@crate_ctxt, f: &ast::_fn, id: &ast::node_id,
|
|||
mutable fixups: fixups,
|
||||
ccx: ccx};
|
||||
check_block(fcx, body);
|
||||
alt decl.purity {
|
||||
ast::pure_fn. {
|
||||
|
||||
// This just checks that the declared type is bool, and trusts
|
||||
// that that's the actual return type.
|
||||
if !ty::type_is_bool(ccx.tcx, fcx.ret_ty) {
|
||||
ccx.tcx.sess.span_err(body.span,
|
||||
"Non-boolean return type in pred");
|
||||
}
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
|
||||
// For non-iterator fns, we unify the tail expr's type with the
|
||||
// function result type, if there is a tail expr.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// -*- rust -*-
|
||||
// error-pattern: non-predicate
|
||||
// error-pattern: Impure function as operator
|
||||
|
||||
fn f(q: int) -> bool { ret true; }
|
||||
|
||||
|
|
32
src/test/run-pass/non-boolean-pure-fns.rs
Normal file
32
src/test/run-pass/non-boolean-pure-fns.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
use std;
|
||||
|
||||
import std::list::*;
|
||||
|
||||
pure fn pure_length_go<@T>(ls: &list<T>, acc: uint) -> uint {
|
||||
alt ls {
|
||||
nil. { acc }
|
||||
cons(_, tl) { pure_length_go(*tl, acc + 1u) }
|
||||
}
|
||||
}
|
||||
|
||||
pure fn pure_length<@T>(ls: &list<T>) -> uint {
|
||||
pure_length_go(ls, 0u)
|
||||
}
|
||||
|
||||
pure fn nonempty_list<@T>(ls: &list<T>) -> bool {
|
||||
pure_length(ls) > 0u
|
||||
}
|
||||
|
||||
// Of course, the compiler can't take advantage of the
|
||||
// knowledge that ls is a cons node. Future work.
|
||||
// Also, this is pretty contrived since nonempty_list
|
||||
// could be a "tag refinement", if we implement those.
|
||||
fn safe_head<@T>(ls: &list<T>) : nonempty_list(ls) -> T { car(ls) }
|
||||
|
||||
fn main() {
|
||||
let mylist = cons(@1u, @nil);
|
||||
// Again, a way to eliminate such "obvious" checks seems
|
||||
// desirable. (Tags could have postconditions.)
|
||||
check(nonempty_list(mylist));
|
||||
assert (*(safe_head(mylist)) == 1u);
|
||||
}
|
|
@ -5,6 +5,6 @@
|
|||
// this checks that a pred with a non-bool return
|
||||
// type is rejected, even if the pred is never used
|
||||
|
||||
pred bad(a: int) -> int { ret 37; }
|
||||
pure fn bad(a: int) -> int { ret 37; }
|
||||
|
||||
fn main() { }
|
Loading…
Reference in a new issue