Skip to content

Commit c5c8258

Browse files
committed
Rework check_expr substantially.
The bulk of check_expr is now check_expr_with_unifier, which takes an expected type and a unification function and will perform the unification on the type it produces. check_expr calls check_expr_with_unifier with a dummy unifier and a new function, check_expr_with, takes an expected type and uses the simple unifier. I think this generally makes thing cleaner, but the purpose for doing this is to enable type inferred lambda-blocks to be useful by allowing the argument types to be unified before the body of the lambda is checked.
1 parent 67e361a commit c5c8258

File tree

1 file changed

+66
-130
lines changed

1 file changed

+66
-130
lines changed

src/comp/middle/typeck.rs

Lines changed: 66 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,9 +1521,24 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: &ast::purity,
15211521
}
15221522
}
15231523

1524+
type unifier = fn(fcx: &@fn_ctxt, sp: &span,
1525+
expected: &ty::t, actual: &ty::t) -> ty::t;
1526+
15241527
fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
1525-
// fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " +
1526-
// syntax::print::pprust::expr_to_str(expr));
1528+
fn dummy_unify(fcx: &@fn_ctxt, sp: &span,
1529+
expected: &ty::t, actual: &ty::t) -> ty::t {
1530+
actual
1531+
}
1532+
ret check_expr_with_unifier(fcx, expr, dummy_unify, 0u);
1533+
}
1534+
fn check_expr_with(fcx: &@fn_ctxt, expr: &@ast::expr, expected: &ty::t)
1535+
-> bool {
1536+
ret check_expr_with_unifier(fcx, expr, demand::simple, expected);
1537+
}
1538+
1539+
fn check_expr_with_unifier(fcx: &@fn_ctxt, expr: &@ast::expr,
1540+
unify: &unifier, expected: &ty::t) -> bool {
1541+
//log_err "typechecking expr " + syntax::print::pprust::expr_to_str(expr);
15271542

15281543
// A generic function to factor out common logic from call and bind
15291544
// expressions.
@@ -1594,14 +1609,14 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
15941609
}
15951610

15961611
// Check the arguments.
1612+
let unifier =
1613+
bind demand::autoderef(_, _, _, _, AUTODEREF_BLOCK_COERCE);
15971614
let i = 0u;
15981615
for a_opt: option::t[@ast::expr] in args {
15991616
alt a_opt {
16001617
some(a) {
1601-
bot |= check_expr(fcx, a);
1602-
demand::autoderef(fcx, a.span, arg_tys.(i).ty,
1603-
expr_ty(fcx.ccx.tcx, a),
1604-
AUTODEREF_BLOCK_COERCE);
1618+
bot |= check_expr_with_unifier(fcx, a, unifier,
1619+
arg_tys.(i).ty);
16051620
}
16061621
none. { }
16071622
}
@@ -1613,9 +1628,8 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
16131628

16141629
fn check_assignment(fcx: &@fn_ctxt, sp: &span, lhs: &@ast::expr,
16151630
rhs: &@ast::expr, id: &ast::node_id) -> bool {
1616-
let bot = check_expr(fcx, lhs) | check_expr(fcx, rhs);
1617-
demand::simple(fcx, sp, expr_ty(fcx.ccx.tcx, lhs),
1618-
expr_ty(fcx.ccx.tcx, rhs));
1631+
let t = next_ty_var(fcx);
1632+
let bot = check_expr_with(fcx, lhs, t) | check_expr_with(fcx, rhs, t);
16191633
write::ty_only_fixup(fcx, id, ty::mk_nil(fcx.ccx.tcx));
16201634
ret bot;
16211635
}
@@ -1671,18 +1685,14 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
16711685
demand::simple(fcx, local.span,
16721686
ty::node_id_to_type(fcx.ccx.tcx, local.node.id),
16731687
element_ty);
1674-
let typ = ty::mk_nil(fcx.ccx.tcx);
1675-
write::ty_only_fixup(fcx, node_id, typ);
1688+
write::nil_ty(fcx.ccx.tcx, node_id);
16761689
ret bot;
16771690
}
16781691

16791692
// A generic function for checking the pred in a check
16801693
// or if-check
16811694
fn check_pred_expr(fcx: &@fn_ctxt, e: &@ast::expr) -> bool {
1682-
let bot = check_expr(fcx, e);
1683-
demand::simple(fcx, e.span, ty::mk_bool(fcx.ccx.tcx),
1684-
expr_ty(fcx.ccx.tcx, e));
1685-
1695+
let bot = check_expr_with(fcx, e, ty::mk_bool(fcx.ccx.tcx));
16861696

16871697
/* e must be a call expr where all arguments are either
16881698
literals or slots */
@@ -1732,10 +1742,9 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
17321742
let if_t =
17331743
alt elsopt {
17341744
some(els) {
1735-
els_bot = check_expr(fcx, els);
17361745
let thn_t = block_ty(fcx.ccx.tcx, thn);
1746+
els_bot = check_expr_with(fcx, els, thn_t);
17371747
let elsopt_t = expr_ty(fcx.ccx.tcx, els);
1738-
demand::simple(fcx, sp, thn_t, elsopt_t);
17391748
if !ty::type_is_bot(fcx.ccx.tcx, elsopt_t) {
17401749
elsopt_t
17411750
} else { thn_t }
@@ -1769,17 +1778,13 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
17691778
write::ty_only_fixup(fcx, id, typ);
17701779
}
17711780
ast::expr_binary(binop, lhs, rhs) {
1772-
bot = check_expr(fcx, lhs);
1773-
if ast::lazy_binop(binop) {
1774-
check_expr(fcx, rhs);
1775-
} else {
1776-
bot |= check_expr(fcx, rhs);
1777-
}
1781+
let lhs_t = next_ty_var(fcx);
1782+
bot = check_expr_with(fcx, lhs, lhs_t);
17781783

1779-
let lhs_t = expr_ty(tcx, lhs);
1780-
let rhs_t = expr_ty(tcx, rhs);
1784+
let unifier = bind demand::autoderef(_, _, _, _, AUTODEREF_OK);
1785+
let rhs_bot = check_expr_with_unifier(fcx, rhs, unifier, lhs_t);
1786+
if !ast::lazy_binop(binop) { bot |= rhs_bot; }
17811787

1782-
demand::autoderef(fcx, rhs.span, lhs_t, rhs_t, AUTODEREF_OK);
17831788
let deref_t = do_autoderef(fcx, expr.span, lhs_t);
17841789
check_binop_type_compat(fcx, expr.span, deref_t, binop);
17851790

@@ -1864,9 +1869,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
18641869
alt expr_opt {
18651870
none. {/* do nothing */ }
18661871
some(e) {
1867-
check_expr(fcx, e);
1868-
let ety = expr_ty(tcx, e);
1869-
demand::simple(fcx, e.span, ty::mk_str(tcx), ety);
1872+
check_expr_with(fcx, e, ty::mk_str(tcx));
18701873
}
18711874
}
18721875
write::bot_ty(tcx, id);
@@ -1882,15 +1885,12 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
18821885
tcx.sess.span_fatal(expr.span,
18831886
"ret; in function returning non-nil");
18841887
}
1885-
write::bot_ty(tcx, id);
18861888
}
18871889
some(e) {
1888-
check_expr(fcx, e);
1889-
demand::simple(fcx, expr.span, fcx.ret_ty,
1890-
expr_ty(tcx, e));
1891-
write::bot_ty(tcx, id);
1890+
check_expr_with(fcx, e, fcx.ret_ty);
18921891
}
18931892
}
1893+
write::bot_ty(tcx, id);
18941894
}
18951895
ast::expr_put(expr_opt) {
18961896
require_impure(tcx.sess, fcx.purity, expr.span);
@@ -1906,19 +1906,16 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
19061906
}
19071907
}
19081908
some(e) {
1909-
bot = check_expr(fcx, e);
1910-
demand::simple(fcx, expr.span, fcx.ret_ty,
1911-
expr_ty(tcx, e));
1909+
bot = check_expr_with(fcx, e, fcx.ret_ty);
19121910
}
19131911
}
19141912
write::nil_ty(tcx, id);
19151913
}
19161914
ast::expr_be(e) {
19171915
// FIXME: prove instead of assert
19181916
assert (ast::is_call_expr(e));
1919-
check_expr(fcx, e);
1917+
check_expr_with(fcx, e, fcx.ret_ty);
19201918
bot = true;
1921-
demand::simple(fcx, e.span, fcx.ret_ty, expr_ty(tcx, e));
19221919
write::nil_ty(tcx, id);
19231920
}
19241921
ast::expr_log(l, e) {
@@ -1937,9 +1934,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
19371934
bot = check_expr(fcx, ast::ternary_to_if(expr));
19381935
}
19391936
ast::expr_assert(e) {
1940-
bot = check_expr(fcx, e);
1941-
let ety = expr_ty(tcx, e);
1942-
demand::simple(fcx, expr.span, ty::mk_bool(tcx), ety);
1937+
bot = check_expr_with(fcx, e, ty::mk_bool(tcx));
19431938
write::nil_ty(tcx, id);
19441939
}
19451940
ast::expr_move(lhs, rhs) {
@@ -1962,34 +1957,23 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
19621957
}
19631958
ast::expr_send(lhs, rhs) {
19641959
require_impure(tcx.sess, fcx.purity, expr.span);
1965-
bot = check_expr(fcx, lhs) | check_expr(fcx, rhs);
1966-
let rhs_t = expr_ty(tcx, rhs);
1960+
let rhs_t = next_ty_var(fcx);
19671961
let chan_t = ty::mk_chan(tcx, rhs_t);
1968-
let lhs_t = expr_ty(tcx, lhs);
1969-
alt structure_of(fcx, expr.span, lhs_t) {
1970-
ty::ty_chan(it) { }
1971-
_ {
1972-
let s = #fmt("mismatched types: expected chan but found %s",
1973-
ty_to_str(tcx, lhs_t));
1974-
tcx.sess.span_fatal(expr.span, s);
1975-
}
1976-
}
1977-
demand::simple(fcx, expr.span, chan_t, lhs_t);
1962+
bot = check_expr_with(fcx, lhs, chan_t) |
1963+
check_expr_with(fcx, rhs, rhs_t);
19781964
write::ty_only_fixup(fcx, id, chan_t);
19791965
}
19801966
ast::expr_recv(lhs, rhs) {
19811967
require_impure(tcx.sess, fcx.purity, expr.span);
1982-
bot = check_expr(fcx, lhs) | check_expr(fcx, rhs);
1983-
let item_t = expr_ty(tcx, rhs);
1984-
let port_t = ty::mk_port(tcx, item_t);
1985-
demand::simple(fcx, expr.span, port_t, expr_ty(tcx, lhs));
1986-
write::ty_only_fixup(fcx, id, item_t);
1968+
let rhs_t = next_ty_var(fcx);
1969+
let port_t = ty::mk_port(tcx, rhs_t);
1970+
bot = check_expr_with(fcx, lhs, port_t) |
1971+
check_expr_with(fcx, rhs, rhs_t);
1972+
write::ty_only_fixup(fcx, id, rhs_t);
19871973
}
19881974
ast::expr_if(cond, thn, elsopt) {
1989-
bot = check_expr(fcx, cond) |
1975+
bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)) |
19901976
check_then_else(fcx, thn, elsopt, id, expr.span);
1991-
demand::simple(fcx, cond.span, ty::mk_bool(tcx),
1992-
expr_ty(tcx, cond));
19931977
}
19941978
ast::expr_for(decl, seq, body) {
19951979
bot = check_expr(fcx, seq);
@@ -2021,24 +2005,19 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
20212005
body, id);
20222006
}
20232007
ast::expr_while(cond, body) {
2024-
bot = check_expr(fcx, cond);
2008+
bot = check_expr_with(fcx, cond, ty::mk_bool(tcx));
20252009
check_block(fcx, body);
2026-
demand::simple(fcx, cond.span, ty::mk_bool(tcx),
2027-
expr_ty(tcx, cond));
2028-
let typ = ty::mk_nil(tcx);
2029-
write::ty_only_fixup(fcx, id, typ);
2010+
write::ty_only_fixup(fcx, id, ty::mk_nil(tcx));
20302011
}
20312012
ast::expr_do_while(body, cond) {
2032-
bot = check_expr(fcx, cond);
2033-
check_block(fcx, body);
2034-
let typ = block_ty(tcx, body);
2035-
write::ty_only_fixup(fcx, id, typ);
2013+
bot = check_expr(fcx, cond) | check_block(fcx, body);
2014+
write::ty_only_fixup(fcx, id, block_ty(tcx, body));
20362015
}
20372016
ast::expr_alt(expr, arms) {
20382017
bot = check_expr(fcx, expr);
2018+
20392019
// Typecheck the patterns first, so that we get types for all the
20402020
// bindings.
2041-
20422021
let pattern_ty = ty::expr_ty(tcx, expr);
20432022
for arm: ast::arm in arms {
20442023
let id_map = ast::pat_id_map(arm.pats.(0));
@@ -2052,12 +2031,7 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
20522031
for arm: ast::arm in arms {
20532032
if !check_block(fcx, arm.block) { arm_non_bot = true; }
20542033
let bty = block_ty(tcx, arm.block);
2055-
2056-
// Failing alt arms don't need to have a matching type
2057-
if !ty::type_is_bot(tcx, bty) {
2058-
result_ty =
2059-
demand::simple(fcx, arm.block.span, result_ty, bty);
2060-
}
2034+
result_ty = demand::simple(fcx, arm.block.span, result_ty, bty);
20612035
}
20622036
bot |= !arm_non_bot;
20632037
if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
@@ -2076,16 +2050,11 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
20762050
}
20772051
ast::expr_block(b) {
20782052
bot = check_block(fcx, b);
2079-
alt b.node.expr {
2080-
some(expr) {
2081-
let typ = expr_ty(tcx, expr);
2082-
write::ty_only_fixup(fcx, id, typ);
2083-
}
2084-
none. {
2085-
let typ = ty::mk_nil(tcx);
2086-
write::ty_only_fixup(fcx, id, typ);
2087-
}
2088-
}
2053+
let typ = alt b.node.expr {
2054+
some(expr) { expr_ty(tcx, expr) }
2055+
none. { ty::mk_nil(tcx) }
2056+
};
2057+
write::ty_only_fixup(fcx, id, typ);
20892058
}
20902059
ast::expr_bind(f, args) {
20912060
// Call the generic checker.
@@ -2216,17 +2185,9 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
22162185
write::ty_only_fixup(fcx, id, t_1);
22172186
}
22182187
ast::expr_vec(args, mut, kind) {
2219-
let t: ty::t;
2220-
if ivec::len[@ast::expr](args) == 0u {
2221-
t = next_ty_var(fcx);
2222-
} else {
2223-
bot |= check_expr(fcx, args.(0));
2224-
t = expr_ty(tcx, args.(0));
2225-
}
2188+
let t: ty::t = next_ty_var(fcx);;
22262189
for e: @ast::expr in args {
2227-
bot |= check_expr(fcx, e);
2228-
let expr_t = expr_ty(tcx, e);
2229-
demand::simple(fcx, expr.span, t, expr_t);
2190+
bot |= check_expr_with(fcx, e, t);
22302191
}
22312192
let typ;
22322193
alt kind {
@@ -2350,29 +2311,13 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
23502311
}
23512312
}
23522313
ast::expr_port(typ) {
2353-
let t = next_ty_var(fcx);
2354-
alt ast_ty_to_ty_crate_infer(fcx.ccx, typ) {
2355-
some(_t) {
2356-
demand::simple(fcx, expr.span, _t, t);
2357-
}
2358-
none. { }
2359-
}
2360-
let pt = ty::mk_port(tcx, t);
2314+
let pt = ty::mk_port(tcx, ast_ty_to_ty_crate_tyvar(fcx, typ));
23612315
write::ty_only_fixup(fcx, id, pt);
23622316
}
23632317
ast::expr_chan(x) {
2364-
check_expr(fcx, x);
2365-
let port_t = expr_ty(tcx, x);
2366-
alt structure_of(fcx, expr.span, port_t) {
2367-
ty::ty_port(subtype) {
2368-
let ct = ty::mk_chan(tcx, subtype);
2369-
write::ty_only_fixup(fcx, id, ct);
2370-
}
2371-
_ {
2372-
tcx.sess.span_fatal(expr.span,
2373-
"bad port type: " + ty_to_str(tcx, port_t));
2374-
}
2375-
}
2318+
let t = next_ty_var(fcx);
2319+
check_expr_with(fcx, x, ty::mk_port(tcx, t));
2320+
write::ty_only_fixup(fcx, id, ty::mk_chan(tcx, t));
23762321
}
23772322
ast::expr_anon_obj(ao) {
23782323
let fields: [ast::anon_obj_field] = ~[];
@@ -2512,6 +2457,8 @@ fn check_expr(fcx: &@fn_ctxt, expr: &@ast::expr) -> bool {
25122457
if bot {
25132458
write::ty_only_fixup(fcx, expr.id, ty::mk_bot(tcx));
25142459
}
2460+
2461+
unify(fcx, expr.span, expected, expr_ty(tcx, expr));
25152462
ret bot;
25162463
}
25172464

@@ -2531,19 +2478,8 @@ fn get_obj_info(ccx: &@crate_ctxt) -> option::t[obj_info] {
25312478

25322479
fn check_decl_initializer(fcx: &@fn_ctxt, nid: ast::node_id,
25332480
init: &ast::initializer) -> bool {
2534-
let bot = check_expr(fcx, init.expr);
25352481
let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.expr.span, nid));
2536-
alt init.op {
2537-
ast::init_assign. {
2538-
demand::simple(fcx, init.expr.span, lty,
2539-
expr_ty(fcx.ccx.tcx, init.expr));
2540-
}
2541-
ast::init_move. {
2542-
demand::simple(fcx, init.expr.span, lty,
2543-
expr_ty(fcx.ccx.tcx, init.expr));
2544-
}
2545-
}
2546-
ret bot;
2482+
ret check_expr_with(fcx, init.expr, lty);
25472483
}
25482484

25492485
fn check_decl_local(fcx: &@fn_ctxt, local: &@ast::local) -> bool {

0 commit comments

Comments
 (0)