Skip to content

Commit e241f29

Browse files
committed
Allow pure fns to have any return type
1 parent 4dd23f2 commit e241f29

File tree

5 files changed

+47
-15
lines changed

5 files changed

+47
-15
lines changed

src/comp/middle/ty.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export hash_ty;
5555
export idx_nil;
5656
export is_lval;
5757
export is_binopable;
58+
export is_pred_ty;
5859
export item_table;
5960
export lookup_item_type;
6061
export method;
@@ -1737,6 +1738,12 @@ fn is_fn_ty(cx: &ctxt, fty: t) -> bool {
17371738
}
17381739
}
17391740

1741+
// Just checks whether it's a fn that returns bool,
1742+
// not its purity.
1743+
fn is_pred_ty(cx: &ctxt, fty:t) -> bool {
1744+
is_fn_ty(cx, fty) && type_is_bool(cx, ty_fn_ret(cx, fty))
1745+
}
1746+
17401747
fn ty_var_id(cx: &ctxt, typ: t) -> int {
17411748
alt struct(cx, typ) {
17421749
ty::ty_var(vid) { ret vid; }

src/comp/middle/typeck.rs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,6 +1715,11 @@ fn check_expr_with_unifier(fcx: &@fn_ctxt, expr: &@ast::expr, unify: &unifier,
17151715
literals or slots */
17161716
alt e.node {
17171717
ast::expr_call(operator, operands) {
1718+
if !ty::is_pred_ty(fcx.ccx.tcx, expr_ty(fcx.ccx.tcx, operator)) {
1719+
fcx.ccx.tcx.sess.span_fatal(operator.span,
1720+
"Operator in constraint has non-boolean return type");
1721+
}
1722+
17181723
alt operator.node {
17191724
ast::expr_path(oper_name) {
17201725
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,
17231728
}
17241729
_ {
17251730
fcx.ccx.tcx.sess.span_fatal(operator.span,
1726-
"non-predicate as operator \
1731+
"Impure function as operator \
17271732
in constraint");
17281733
}
17291734
}
@@ -2596,18 +2601,6 @@ fn check_fn(ccx: &@crate_ctxt, f: &ast::_fn, id: &ast::node_id,
25962601
mutable fixups: fixups,
25972602
ccx: ccx};
25982603
check_block(fcx, body);
2599-
alt decl.purity {
2600-
ast::pure_fn. {
2601-
2602-
// This just checks that the declared type is bool, and trusts
2603-
// that that's the actual return type.
2604-
if !ty::type_is_bool(ccx.tcx, fcx.ret_ty) {
2605-
ccx.tcx.sess.span_err(body.span,
2606-
"Non-boolean return type in pred");
2607-
}
2608-
}
2609-
_ { }
2610-
}
26112604

26122605
// For non-iterator fns, we unify the tail expr's type with the
26132606
// function result type, if there is a tail expr.

src/test/compile-fail/not-a-pred-check.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// -*- rust -*-
2-
// error-pattern: non-predicate
2+
// error-pattern: Impure function as operator
33

44
fn f(q: int) -> bool { ret true; }
55

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use std;
2+
3+
import std::list::*;
4+
5+
pure fn pure_length_go<@T>(ls: &list<T>, acc: uint) -> uint {
6+
alt ls {
7+
nil. { acc }
8+
cons(_, tl) { pure_length_go(*tl, acc + 1u) }
9+
}
10+
}
11+
12+
pure fn pure_length<@T>(ls: &list<T>) -> uint {
13+
pure_length_go(ls, 0u)
14+
}
15+
16+
pure fn nonempty_list<@T>(ls: &list<T>) -> bool {
17+
pure_length(ls) > 0u
18+
}
19+
20+
// Of course, the compiler can't take advantage of the
21+
// knowledge that ls is a cons node. Future work.
22+
// Also, this is pretty contrived since nonempty_list
23+
// could be a "tag refinement", if we implement those.
24+
fn safe_head<@T>(ls: &list<T>) : nonempty_list(ls) -> T { car(ls) }
25+
26+
fn main() {
27+
let mylist = cons(@1u, @nil);
28+
// Again, a way to eliminate such "obvious" checks seems
29+
// desirable. (Tags could have postconditions.)
30+
check(nonempty_list(mylist));
31+
assert (*(safe_head(mylist)) == 1u);
32+
}

src/test/compile-fail/pred-not-bool.rs renamed to src/test/run-pass/pred-not-bool.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
// this checks that a pred with a non-bool return
66
// type is rejected, even if the pred is never used
77

8-
pred bad(a: int) -> int { ret 37; }
8+
pure fn bad(a: int) -> int { ret 37; }
99

1010
fn main() { }

0 commit comments

Comments
 (0)