Skip to content

Commit 10120cc

Browse files
committed
typeck: Take more care to pass down expected types
This helps with prototype inference and avoids some 'must be known in this context' errors.
1 parent 2b71535 commit 10120cc

File tree

2 files changed

+98
-50
lines changed

2 files changed

+98
-50
lines changed

src/rustc/middle/typeck.rs

Lines changed: 86 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2371,15 +2371,16 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity,
23712371
}
23722372
}
23732373

2374-
fn check_expr(fcx: @fn_ctxt, expr: @ast::expr) -> bool {
2375-
ret check_expr_with_unifier(fcx, expr, ty::mk_nil(fcx.ccx.tcx)) {||
2376-
/* do not take any action on unify */
2377-
};
2374+
fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool {
2375+
check_expr(fcx, expr, some(expected))
23782376
}
23792377

2380-
fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool {
2378+
fn check_expr(fcx: @fn_ctxt, expr: @ast::expr,
2379+
expected: option<ty::t>) -> bool {
23812380
ret check_expr_with_unifier(fcx, expr, expected) {||
2382-
demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
2381+
for expected.each {|t|
2382+
demand::suptype(fcx, expr.span, t, fcx.expr_ty(expr));
2383+
}
23832384
};
23842385
}
23852386

@@ -2790,7 +2791,7 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
27902791

27912792
fn check_expr_with_unifier(fcx: @fn_ctxt,
27922793
expr: @ast::expr,
2793-
expected: ty::t,
2794+
expected: option<ty::t>,
27942795
unifier: fn()) -> bool {
27952796

27962797
#debug(">> typechecking expr %d (%s)",
@@ -2861,7 +2862,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
28612862
};
28622863
if is_block == check_blocks {
28632864
let arg_ty = arg_tys[i];
2864-
bot |= check_expr_with_unifier(fcx, a, arg_ty) {||
2865+
bot |= check_expr_with_unifier(
2866+
fcx, a, some(arg_ty)) {||
28652867
demand::assign(fcx, a.span, arg_ty, a);
28662868
};
28672869
}
@@ -2881,7 +2883,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
28812883
// A generic function for checking assignment expressions
28822884
fn check_assignment(fcx: @fn_ctxt, _sp: span, lhs: @ast::expr,
28832885
rhs: @ast::expr, id: ast::node_id) -> bool {
2884-
let mut bot = check_expr(fcx, lhs);
2886+
let mut bot = check_expr(fcx, lhs, none);
28852887
bot |= check_expr_with(fcx, rhs, fcx.expr_ty(lhs));
28862888
fcx.write_ty(id, ty::mk_nil(fcx.ccx.tcx));
28872889
ret bot;
@@ -2891,7 +2893,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
28912893
fn check_call(fcx: @fn_ctxt, sp: span, call_expr_id: ast::node_id,
28922894
f: @ast::expr, args: [@ast::expr]) -> bool {
28932895

2894-
let mut bot = check_expr(fcx, f);
2896+
let mut bot = check_expr(fcx, f, none);
28952897
let fn_ty = fcx.expr_ty(f);
28962898

28972899
// Call the generic checker.
@@ -2992,7 +2994,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
29922994
lhs: @ast::expr,
29932995
rhs: @ast::expr) -> bool {
29942996
let tcx = fcx.ccx.tcx;
2995-
let lhs_bot = check_expr(fcx, lhs);
2997+
let lhs_bot = check_expr(fcx, lhs, none);
29962998
let lhs_t = fcx.expr_ty(lhs);
29972999
let lhs_t = structurally_resolved_type(fcx, lhs.span, lhs_t);
29983000
ret alt (op, ty::get(lhs_t).struct) {
@@ -3015,7 +3017,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
30153017
(_, _) if ty::type_is_integral(lhs_t) &&
30163018
ast_util::is_shift_binop(op) {
30173019
// Shift is a special case: rhs can be any integral type
3018-
let rhs_bot = check_expr(fcx, rhs);
3020+
let rhs_bot = check_expr(fcx, rhs, none);
30193021
let rhs_t = fcx.expr_ty(rhs);
30203022
require_integral(fcx, rhs.span, rhs_t);
30213023
fcx.write_ty(expr.id, lhs_t);
@@ -3063,7 +3065,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
30633065
}
30643066
_ {}
30653067
}
3066-
check_expr(fcx, rhs);
3068+
check_expr(fcx, rhs, none);
30673069
tcx.sess.span_err(
30683070
ex.span, "binary operation " + ast_util::binop_to_str(op) +
30693071
" cannot be applied to type `" +
@@ -3083,6 +3085,19 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
30833085
}
30843086
}
30853087
}
3088+
fn unpack_expected<O: copy>(fcx: @fn_ctxt, expected: option<ty::t>,
3089+
unpack: fn(ty::sty) -> option<O>)
3090+
-> option<O> {
3091+
alt expected {
3092+
some(t) {
3093+
alt infer::resolve_shallow(fcx.infcx, t, true) {
3094+
result::ok(t) { unpack(ty::get(t).struct) }
3095+
_ { none }
3096+
}
3097+
}
3098+
_ { none }
3099+
}
3100+
}
30863101

30873102
let tcx = fcx.ccx.tcx;
30883103
let id = expr.id;
@@ -3147,7 +3162,19 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
31473162
fcx.write_nil(expr.id);
31483163
}
31493164
ast::expr_unary(unop, oper) {
3150-
bot = check_expr(fcx, oper);
3165+
let exp_inner = unpack_expected(fcx, expected) {|sty|
3166+
alt unop {
3167+
ast::box(_) | ast::uniq(_) {
3168+
alt sty {
3169+
ty::ty_box(mt) | ty::ty_uniq(mt) { some(mt.ty) }
3170+
_ { none }
3171+
}
3172+
}
3173+
ast::not | ast::neg { some(expected.get()) }
3174+
ast::deref { none }
3175+
}
3176+
};
3177+
bot = check_expr(fcx, oper, exp_inner);
31513178
let mut oper_t = fcx.expr_ty(oper);
31523179
alt unop {
31533180
ast::box(mutbl) {
@@ -3202,12 +3229,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
32023229
fcx.write_ty(id, oper_t);
32033230
}
32043231
ast::expr_addr_of(mutbl, oper) {
3205-
bot = check_expr(fcx, oper);
3206-
let mut oper_t = fcx.expr_ty(oper);
3207-
3232+
bot = check_expr(fcx, oper, unpack_expected(fcx, expected) {|ty|
3233+
alt ty { ty::ty_rptr(_, mt) { some(mt.ty) } _ { none } }
3234+
});
32083235
let region = region_of(fcx, oper);
3209-
let tm = { ty: oper_t, mutbl: mutbl };
3210-
oper_t = ty::mk_rptr(tcx, region, tm);
3236+
let tm = { ty: fcx.expr_ty(oper), mutbl: mutbl };
3237+
let oper_t = ty::mk_rptr(tcx, region, tm);
32113238
fcx.write_ty(id, oper_t);
32123239
}
32133240
ast::expr_path(pth) {
@@ -3255,7 +3282,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
32553282
ast::expr_log(_, lv, e) {
32563283
bot = check_expr_with(fcx, lv, ty::mk_mach_uint(tcx, ast::ty_u32));
32573284
// Note: this does not always execute, so do not propagate bot:
3258-
check_expr(fcx, e);
3285+
check_expr(fcx, e, none);
32593286
fcx.write_nil(id);
32603287
}
32613288
ast::expr_check(_, e) {
@@ -3272,7 +3299,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
32723299
fcx.write_nil(id);
32733300
}
32743301
ast::expr_copy(a) {
3275-
bot = check_expr_with(fcx, a, expected);
3302+
bot = check_expr(fcx, a, expected);
32763303
fcx.write_ty(id, fcx.expr_ty(a));
32773304
}
32783305
ast::expr_move(lhs, rhs) {
@@ -3348,26 +3375,22 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
33483375
}
33493376
ast::expr_fn_block(decl, body) {
33503377
// Take the prototype from the expected type, but default to block:
3351-
let proto = alt ty::get(expected).struct {
3352-
ty::ty_fn({proto, _}) { proto }
3353-
_ { ast::proto_box }
3354-
};
3355-
#debug("checking expr_fn_block %s expected=%s",
3356-
expr_to_str(expr),
3357-
ty_to_str(tcx, expected));
3378+
let proto = unpack_expected(fcx, expected, {|sty|
3379+
alt sty { ty::ty_fn({proto, _}) { some(proto) } _ { none } }
3380+
}).get_default(ast::proto_box);
33583381
check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
33593382
false, unifier);
33603383
}
33613384
ast::expr_loop_body(b) {
3362-
let rty = structurally_resolved_type(fcx, expr.span, expected);
3363-
let (inner_ty, proto) = alt check ty::get(rty).struct {
3385+
let expected_sty = unpack_expected(fcx, expected, {|x|some(x)}).get();
3386+
let (inner_ty, proto) = alt expected_sty {
33643387
ty::ty_fn(fty) {
33653388
alt infer::mk_subty(fcx.infcx, fty.output, ty::mk_bool(tcx)) {
33663389
result::ok(_) {}
33673390
result::err(err) {
33683391
tcx.sess.span_fatal(
3369-
expr.span, #fmt("a loop function's last argument should \
3370-
return `bool`, not `%s`",
3392+
expr.span, #fmt("a loop function's last argument \
3393+
should return `bool`, not `%s`",
33713394
ty_to_str(tcx, fty.output)));
33723395
}
33733396
}
@@ -3406,7 +3429,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
34063429
}
34073430
ast::expr_bind(f, args) {
34083431
// Call the generic checker.
3409-
bot = check_expr(fcx, f);
3432+
bot = check_expr(fcx, f, none);
34103433

34113434
let {fty, bot: ccob_bot} = {
34123435
let fn_ty = fcx.expr_ty(f);
@@ -3465,7 +3488,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
34653488
bot = check_call(fcx, expr.span, expr.id, f, args);
34663489
}
34673490
ast::expr_cast(e, t) {
3468-
bot = check_expr(fcx, e);
3491+
bot = check_expr(fcx, e, none);
34693492
let t_1 = fcx.to_ty(t);
34703493
let t_e = fcx.expr_ty(e);
34713494

@@ -3506,18 +3529,29 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
35063529
ast::expr_tup(elts) {
35073530
let mut elt_ts = [];
35083531
vec::reserve(elt_ts, vec::len(elts));
3509-
for elts.each {|e|
3510-
check_expr(fcx, e);
3532+
let flds = unpack_expected(fcx, expected) {|sty|
3533+
alt sty { ty::ty_tup(flds) { some(flds) } _ { none } }
3534+
};
3535+
for elts.eachi {|i, e|
3536+
check_expr(fcx, e, flds.map {|fs| fs[i]});
35113537
let ety = fcx.expr_ty(e);
35123538
elt_ts += [ety];
35133539
}
35143540
let typ = ty::mk_tup(tcx, elt_ts);
35153541
fcx.write_ty(id, typ);
35163542
}
35173543
ast::expr_rec(fields, base) {
3518-
option::iter(base) {|b| check_expr(fcx, b); }
3544+
option::iter(base) {|b| check_expr(fcx, b, expected); }
3545+
let expected = if expected == none && base != none {
3546+
some(fcx.expr_ty(base.get()))
3547+
} else { expected };
3548+
let flds = unpack_expected(fcx, expected) {|sty|
3549+
alt sty { ty::ty_rec(flds) { some(flds) } _ { none } }
3550+
};
35193551
let fields_t = vec::map(fields, {|f|
3520-
bot |= check_expr(fcx, f.node.expr);
3552+
bot |= check_expr(fcx, f.node.expr, flds.chain {|flds|
3553+
vec::find(flds) {|tf| tf.ident == f.node.ident}
3554+
}.map {|tf| tf.mt.ty});
35213555
let expr_t = fcx.expr_ty(f.node.expr);
35223556
let expr_mt = {ty: expr_t, mutbl: f.node.mutbl};
35233557
// for the most precise error message,
@@ -3531,7 +3565,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
35313565
fcx.write_ty(id, typ);
35323566
}
35333567
some(bexpr) {
3534-
bot |= check_expr(fcx, bexpr);
35353568
let bexpr_t = fcx.expr_ty(bexpr);
35363569
let mut base_fields: [field] = [];
35373570
alt structure_of(fcx, expr.span, bexpr_t) {
@@ -3560,7 +3593,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
35603593
}
35613594
}
35623595
ast::expr_field(base, field, tys) {
3563-
bot |= check_expr(fcx, base);
3596+
bot |= check_expr(fcx, base, none);
35643597
let expr_t = structurally_resolved_type(fcx, expr.span,
35653598
fcx.expr_ty(base));
35663599
let base_t = do_autoderef(fcx, expr.span, expr_t);
@@ -3638,10 +3671,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
36383671
}
36393672
}
36403673
ast::expr_index(base, idx) {
3641-
bot |= check_expr(fcx, base);
3674+
bot |= check_expr(fcx, base, none);
36423675
let raw_base_t = fcx.expr_ty(base);
36433676
let base_t = do_autoderef(fcx, expr.span, raw_base_t);
3644-
bot |= check_expr(fcx, idx);
3677+
bot |= check_expr(fcx, idx, none);
36453678
let idx_t = fcx.expr_ty(idx);
36463679
alt structure_of(fcx, expr.span, base_t) {
36473680
ty::ty_evec(mt, _) |
@@ -3671,8 +3704,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
36713704
}
36723705
}
36733706
ast::expr_new(p, alloc_id, v) {
3674-
bot |= check_expr(fcx, p);
3675-
bot |= check_expr(fcx, v);
3707+
bot |= check_expr(fcx, p, none);
3708+
bot |= check_expr(fcx, v, none);
36763709

36773710
let p_ty = fcx.expr_ty(p);
36783711

@@ -3728,7 +3761,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
37283761
#debug("type of expr %s is %s, expected is %s",
37293762
syntax::print::pprust::expr_to_str(expr),
37303763
ty_to_str(tcx, fcx.expr_ty(expr)),
3731-
ty_to_str(tcx, expected));
3764+
alt expected {
3765+
some(t) { ty_to_str(tcx, t) }
3766+
_ { "empty" }
3767+
});
37323768

37333769
unifier();
37343770

@@ -3739,7 +3775,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
37393775
fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) {
37403776
if !type_is_integral(fcx, sp, t) {
37413777
fcx.ccx.tcx.sess.span_err(sp, "mismatched types: expected \
3742-
`integer` but found `"
3778+
integral type but found `"
37433779
+ fcx.ty_to_str(t) + "`");
37443780
}
37453781
}
@@ -3796,7 +3832,7 @@ fn check_stmt(fcx: @fn_ctxt, stmt: @ast::stmt) -> bool {
37963832
}
37973833
ast::stmt_semi(expr, id) {
37983834
node_id = id;
3799-
bot = check_expr(fcx, expr);
3835+
bot = check_expr(fcx, expr, none);
38003836
}
38013837
}
38023838
fcx.write_nil(node_id);
@@ -3841,7 +3877,7 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool {
38413877
if bot && !warned {
38423878
fcx.ccx.tcx.sess.span_warn(e.span, "unreachable expression");
38433879
}
3844-
bot |= check_expr(fcx, e);
3880+
bot |= check_expr(fcx, e, none);
38453881
let ety = fcx.expr_ty(e);
38463882
fcx.write_ty(blk.node.id, ety);
38473883
}
@@ -3870,7 +3906,7 @@ fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) {
38703906
node_types: smallintmap::mk(),
38713907
node_type_substs: map::int_hash(),
38723908
ccx: ccx};
3873-
check_expr(fcx, e);
3909+
check_expr(fcx, e, none);
38743910
let cty = fcx.expr_ty(e);
38753911
let declty = fcx.ccx.tcx.tcache.get(local_def(id)).ty;
38763912
demand::suptype(fcx, e.span, declty, cty);
@@ -3915,7 +3951,7 @@ fn check_enum_variants(ccx: @crate_ctxt,
39153951
for vs.each {|v|
39163952
alt v.node.disr_expr {
39173953
some(e) {
3918-
check_expr(fcx, e);
3954+
check_expr(fcx, e, none);
39193955
let cty = fcx.expr_ty(e);
39203956
let declty = ty::mk_int(ccx.tcx);
39213957
demand::suptype(fcx, e.span, declty, cty);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Tests the passing down of expected types through boxing and
2+
// wrapping in a record or tuple. (The a.x would complain about 'this
3+
// type must be known in this context' if the passing down doesn't
4+
// happen.)
5+
6+
fn eat_tup(_r: ~@(int, fn@({x: int, y: int}) -> int)) {}
7+
fn eat_rec(_r: @~{a: int, b: fn@({x: int, y: int}) -> int}) {}
8+
9+
fn main() {
10+
eat_tup(~@(10, {|a| a.x}));
11+
eat_rec(@~{a: 10, b: {|a| a.x}});
12+
}

0 commit comments

Comments
 (0)