Skip to content

Commit 8871462

Browse files
committed
Do a bunch more typechecking for iters and for each loops.
Closes #771. Closes #772. Closes #796.
1 parent 3254fb9 commit 8871462

File tree

5 files changed

+70
-31
lines changed

5 files changed

+70
-31
lines changed

src/comp/middle/typeck.rs

+60-30
Original file line numberDiff line numberDiff line change
@@ -1531,9 +1531,27 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
15311531
_ { fty }
15321532
};
15331533

1534-
// Grab the argument types and the return type.
1534+
let sty = structure_of(fcx, sp, fty_stripped);
1535+
1536+
// Check that we aren't confusing iter calls and fn calls
1537+
alt sty {
1538+
ty::ty_fn(ast::proto_iter., _, _, _, _) {
1539+
if call_kind != kind_for_each {
1540+
fcx.ccx.tcx.sess.span_err(
1541+
sp, "calling iter outside of for each loop");
1542+
}
1543+
}
1544+
_ {
1545+
if call_kind == kind_for_each {
1546+
fcx.ccx.tcx.sess.span_err(
1547+
sp, "calling non-iter as sequence of for each loop");
1548+
}
1549+
}
1550+
}
1551+
1552+
// Grab the argument types
15351553
let arg_tys;
1536-
alt structure_of(fcx, sp, fty_stripped) {
1554+
alt sty {
15371555
ty::ty_fn(_, arg_tys_0, _, _, _) |
15381556
ty::ty_native_fn(_, arg_tys_0, _) { arg_tys = arg_tys_0; }
15391557
_ {
@@ -1590,8 +1608,8 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
15901608
write::ty_only_fixup(fcx, id, ty::mk_nil(fcx.ccx.tcx));
15911609
ret bot;
15921610
}
1593-
// A generic function for checking call expressions
15941611

1612+
// A generic function for checking call expressions
15951613
fn check_call(fcx: &@fn_ctxt, sp: &span, f: &@ast::expr,
15961614
args: &(@ast::expr)[], call_kind: call_kind) -> bool {
15971615
let args_opt_0: (option::t[@ast::expr])[] = ~[];
@@ -1602,8 +1620,34 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
16021620
// Call the generic checker.
16031621
ret check_call_or_bind(fcx, sp, f, args_opt_0, call_kind);
16041622
}
1605-
// A generic function for checking for or for-each loops
16061623

1624+
// A generic function for doing all of the checking for call expressions
1625+
fn check_call_full(fcx: &@fn_ctxt, sp: &span, f: &@ast::expr,
1626+
args: &(@ast::expr)[], call_kind: call_kind,
1627+
id: ast::node_id) -> bool {
1628+
/* here we're kind of hosed, as f can be any expr
1629+
need to restrict it to being an explicit expr_path if we're
1630+
inside a pure function, and need an environment mapping from
1631+
function name onto purity-designation */
1632+
require_pure_call(fcx.ccx, fcx.purity, f, sp);
1633+
let bot = check_call(fcx, sp, f, args, call_kind);
1634+
1635+
// Pull the return type out of the type of the function.
1636+
let rt_1;
1637+
let fty = do_autoderef(fcx, sp, ty::expr_ty(fcx.ccx.tcx, f));
1638+
alt structure_of(fcx, sp, fty) {
1639+
ty::ty_fn(_, _, rt, cf, _) {
1640+
bot |= cf == ast::noreturn;
1641+
rt_1 = rt;
1642+
}
1643+
ty::ty_native_fn(_, _, rt) { rt_1 = rt; }
1644+
_ { fail "LHS of call expr didn't have a function type?!"; }
1645+
}
1646+
write::ty_only_fixup(fcx, id, rt_1);
1647+
ret bot;
1648+
}
1649+
1650+
// A generic function for checking for or for-each loops
16071651
fn check_for_or_for_each(fcx: &@fn_ctxt, local: &@ast::local,
16081652
element_ty: ty::t, body: &ast::blk,
16091653
node_id: ast::node_id) -> bool {
@@ -1952,9 +1996,16 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
19521996
bot |= check_for_or_for_each(fcx, decl, elt_ty, body, id);
19531997
}
19541998
ast::expr_for_each(decl, seq, body) {
1955-
bot = check_expr(fcx, seq) |
1956-
check_for_or_for_each(fcx, decl, expr_ty(tcx, seq),
1957-
body, id);
1999+
alt (seq.node) {
2000+
ast::expr_call(f, args) {
2001+
bot = check_call_full(fcx, seq.span, f, args,
2002+
kind_for_each, seq.id);
2003+
}
2004+
_ { tcx.sess.span_fatal(
2005+
expr.span, "sequence in for each loop not a call"); }
2006+
}
2007+
bot |= check_for_or_for_each(fcx, decl, expr_ty(tcx, seq),
2008+
body, id);
19582009
}
19592010
ast::expr_while(cond, body) {
19602011
bot = check_expr(fcx, cond);
@@ -1973,7 +2024,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
19732024
ast::expr_alt(expr, arms) {
19742025
bot = check_expr(fcx, expr);
19752026
// Typecheck the patterns first, so that we get types for all the
1976-
// bindings.
2027+
// bindings.
19772028

19782029
let pattern_ty = ty::expr_ty(tcx, expr);
19792030
for arm: ast::arm in arms {
@@ -2060,28 +2111,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
20602111
write::ty_only_fixup(fcx, id, t_1);
20612112
}
20622113
ast::expr_call(f, args) {
2063-
/* here we're kind of hosed, as f can be any expr
2064-
need to restrict it to being an explicit expr_path if we're
2065-
inside a pure function, and need an environment mapping from
2066-
function name onto purity-designation */
2067-
2068-
require_pure_call(fcx.ccx, fcx.purity, f, expr.span);
2069-
bot = check_call(fcx, expr.span, f, args, kind_call);
2070-
// Pull the return type out of the type of the function.
2071-
2072-
let rt_1;
2073-
let fty = do_autoderef(fcx, expr.span, ty::expr_ty(tcx, f));
2074-
alt structure_of(fcx, expr.span, fty) {
2075-
ty::ty_fn(_, _, rt, cf, _) {
2076-
bot |= cf == ast::noreturn;
2077-
rt_1 = rt;
2078-
}
2079-
ty::ty_native_fn(_, _, rt) { rt_1 = rt; }
2080-
_ {
2081-
fail "LHS of call expr didn't have a function type?!";
2082-
}
2083-
}
2084-
write::ty_only_fixup(fcx, id, rt_1);
2114+
bot = check_call_full(fcx, expr.span, f, args, kind_call, expr.id);
20852115
}
20862116
ast::expr_self_method(ident) {
20872117
let t = ty::mk_nil(tcx);

src/comp/util/common.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,14 @@ fn lit_eq(l: &@ast::lit, m: &@ast::lit) -> bool {
150150
}
151151
}
152152

153-
tag call_kind { kind_call; kind_spawn; kind_bind; }
153+
tag call_kind { kind_call; kind_spawn; kind_bind; kind_for_each; }
154154

155155
fn call_kind_str(c: call_kind) -> str {
156156
alt c {
157157
kind_call. { "Call" }
158158
kind_spawn. { "Spawn" }
159159
kind_bind. { "Bind" }
160+
kind_for_each. { "For-Each" }
160161
}
161162
}
162163

src/test/compile-fail/fn-as-iter.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// error-pattern:calling non-iter as sequence of for each loop
2+
fn f() -> int { ret 4; }
3+
fn main() { for each i in f() { } }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// error-pattern:sequence in for each loop not a call
2+
fn main() { for each p in 1 {} }

src/test/compile-fail/iter-as-fn.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// error-pattern:calling iter outside of for each loop
2+
iter i() { }
3+
fn main() { i(); }

0 commit comments

Comments
 (0)