Skip to content

Commit bf9d714

Browse files
committed
Avoid unifying vars when possible; handle bot (more) correctly
1 parent ee5d0f5 commit bf9d714

File tree

8 files changed

+116
-32
lines changed

8 files changed

+116
-32
lines changed

src/libcore/task.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ fn test_try_fail() {
694694
fail
695695
} {
696696
result::err(()) { }
697-
_ { fail; }
697+
result::ok(()) { fail; }
698698
}
699699
}
700700

src/rustc/middle/infer.rs

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -293,14 +293,32 @@ impl unify_methods for infer_ctxt {
293293
}
294294

295295
fn vars(a_id: uint, b_id: uint) -> ures {
296-
#debug["vars(<T%u> <: <T%u>)",
297-
a_id, b_id];
298-
299296
// Need to make sub_id a subtype of sup_id.
300297
let {root: a_id, bounds: a_bounds} = self.get(a_id);
301298
let {root: b_id, bounds: b_bounds} = self.get(b_id);
302299

300+
#debug["vars(<T%u>=%s <: <T%u>=%s)",
301+
a_id, self.bounds_to_str(a_bounds),
302+
b_id, self.bounds_to_str(b_bounds)];
303+
303304
if a_id == b_id { ret self.uok(); }
305+
306+
// If both A's UB and B's LB have already been bound to types,
307+
// see if we can make those types subtypes.
308+
alt (a_bounds.ub, b_bounds.lb) {
309+
(some(a_ub), some(b_lb)) {
310+
let r = self.try {|| self.tys(a_ub, b_lb) };
311+
alt r {
312+
result::ok(()) { ret result::ok(()); }
313+
result::err(_) { /*fallthrough */ }
314+
}
315+
}
316+
_ { /*fallthrough*/ }
317+
}
318+
319+
// Otherwise, we need to merge A and B so as to guarantee that
320+
// A remains a subtype of B. Actually, there are other options,
321+
// but that's the route we choose to take.
304322
self.merge(a_id, a_bounds, b_bounds).then {||
305323
// For max perf, we should consider the rank here.
306324
self.set(b_id, redirect(a_id));
@@ -309,18 +327,20 @@ impl unify_methods for infer_ctxt {
309327
}
310328

311329
fn varty(a_id: uint, b: ty::t) -> ures {
312-
#debug["varty(<T%u> <: %s)",
313-
a_id, self.ty_to_str(b)];
314330
let {root: a_id, bounds: a_bounds} = self.get(a_id);
331+
#debug["varty(<T%u>=%s <: %s)",
332+
a_id, self.bounds_to_str(a_bounds),
333+
self.ty_to_str(b)];
315334
let b_bounds = {lb: none, ub: some(b)};
316335
self.merge(a_id, a_bounds, b_bounds)
317336
}
318337

319338
fn tyvar(a: ty::t, b_id: uint) -> ures {
320-
#debug["tyvar(%s <: <T%u>)",
321-
self.ty_to_str(a), b_id];
322339
let a_bounds = {lb: some(a), ub: none};
323340
let {root: b_id, bounds: b_bounds} = self.get(b_id);
341+
#debug["tyvar(%s <: <T%u>=%s)",
342+
self.ty_to_str(a),
343+
b_id, self.bounds_to_str(b_bounds)];
324344
self.merge(b_id, a_bounds, b_bounds)
325345
}
326346

@@ -532,6 +552,8 @@ impl unify_methods for infer_ctxt {
532552
if a == b { ret self.uok(); }
533553

534554
alt (ty::get(a).struct, ty::get(b).struct) {
555+
(ty::ty_bot, _) { self.uok() }
556+
535557
(ty::ty_var(a_id), ty::ty_var(b_id)) {
536558
self.vars(a_id as uint, b_id as uint)
537559
}
@@ -542,9 +564,6 @@ impl unify_methods for infer_ctxt {
542564
self.tyvar(a, b_id as uint)
543565
}
544566

545-
(_, ty::ty_bot) { self.uok() }
546-
(ty::ty_bot, _) { self.uok() }
547-
548567
(ty::ty_nil, _) |
549568
(ty::ty_bool, _) |
550569
(ty::ty_int(_), _) |

src/rustc/middle/typeck.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2483,15 +2483,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
24832483
let (if_t, if_bot) =
24842484
alt elsopt {
24852485
some(els) {
2486+
let if_t = next_ty_var(fcx);
24862487
let thn_bot = check_block(fcx, thn);
24872488
let thn_t = block_ty(fcx.ccx.tcx, thn);
2488-
let els_bot = check_expr_with(fcx, els, thn_t);
2489-
let els_t = expr_ty(fcx.ccx.tcx, els);
2490-
let if_t = if !ty::type_is_bot(els_t) {
2491-
els_t
2492-
} else {
2493-
thn_t
2494-
};
2489+
demand::simple(fcx, thn.span, if_t, thn_t);
2490+
let els_bot = check_expr_with(fcx, els, if_t);
24952491
(if_t, thn_bot & els_bot)
24962492
}
24972493
none {
@@ -2565,7 +2561,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
25652561
}
25662562

25672563
(_, _) if ty::is_binopable(tcx, lhs_t, op) {
2568-
let rhs_bot = check_expr_with(fcx, rhs, lhs_t);
2564+
let tvar = next_ty_var(fcx);
2565+
demand::simple(fcx, expr.span, tvar, lhs_t);
2566+
let rhs_bot = check_expr_with(fcx, rhs, tvar);
25692567
let rhs_t = alt op {
25702568
ast::eq | ast::lt | ast::le | ast::ne | ast::ge |
25712569
ast::gt {
@@ -2646,9 +2644,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
26462644
ast::expr_binary(ast::gt, lhs, rhs) |
26472645
ast::expr_binary(ast::ge, lhs, rhs) {
26482646
let tcx = fcx.ccx.tcx;
2649-
bot |= check_expr(fcx, lhs);
2650-
let lhs_t = expr_ty(tcx, lhs);
2651-
bot |= check_expr_with(fcx, rhs, lhs_t);
2647+
let tvar = next_ty_var(fcx);
2648+
bot |= check_expr_with(fcx, lhs, tvar);
2649+
bot |= check_expr_with(fcx, rhs, tvar);
26522650
write_ty(tcx, id, ty::mk_bool(tcx));
26532651
}
26542652
ast::expr_binary(op, lhs, rhs) {
@@ -2782,7 +2780,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
27822780
}
27832781
ast::expr_log(_, lv, e) {
27842782
bot = check_expr_with(fcx, lv, ty::mk_mach_uint(tcx, ast::ty_u32));
2785-
bot |= check_expr(fcx, e);
2783+
// Note: this does not always execute, so do not propagate bot:
2784+
check_expr(fcx, e);
27862785
write_nil(tcx, id);
27872786
}
27882787
ast::expr_check(_, e) {
@@ -2850,13 +2849,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
28502849
bot = !may_break(body);
28512850
}
28522851
ast::expr_alt(discrim, arms, _) {
2853-
bot = check_expr(fcx, discrim);
2852+
let pattern_ty = next_ty_var(fcx);
2853+
bot = check_expr_with(fcx, discrim, pattern_ty);
28542854

28552855
let parent_block = tcx.region_map.rvalue_to_block.get(discrim.id);
28562856

28572857
// Typecheck the patterns first, so that we get types for all the
28582858
// bindings.
2859-
let pattern_ty = ty::expr_ty(tcx, discrim);
2859+
//let pattern_ty = ty::expr_ty(tcx, discrim);
28602860
for arm: ast::arm in arms {
28612861
let pcx = {
28622862
fcx: fcx,
@@ -3205,6 +3205,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
32053205
}
32063206
if bot { write_ty(tcx, expr.id, ty::mk_bot(tcx)); }
32073207

3208+
#debug("type of expr %s is %s, expected is %s",
3209+
syntax::print::pprust::expr_to_str(expr),
3210+
ty_to_str(tcx, expr_ty(tcx, expr)),
3211+
ty_to_str(tcx, expected));
3212+
32083213
unify(fcx, expr.span, expected, expr_ty(tcx, expr));
32093214
ret bot;
32103215
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
fn takes_mut(&&x: @mut int) { }
2+
fn takes_const(&&x: @const int) { }
3+
fn takes_imm(&&x: @int) { }
4+
5+
fn apply<T>(t: T, f: fn(T)) {
6+
f(t)
7+
}
8+
9+
fn main() {
10+
apply(@3, takes_mut); //! ERROR (values differ in mutability)
11+
apply(@3, takes_const);
12+
apply(@3, takes_imm);
13+
14+
apply(@mut 3, takes_mut);
15+
apply(@mut 3, takes_const);
16+
apply(@mut 3, takes_imm); //! ERROR (values differ in mutability)
17+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
fn reproduce<T:copy>(t: T) -> fn@() -> T {
2+
fn@() -> T { t }
3+
}
4+
5+
fn main() {
6+
// type of x is the variable X,
7+
// with the lower bound @mut int
8+
let x = @mut 3;
9+
10+
// type of r is fn@() -> X
11+
let r = reproduce(x);
12+
13+
// Requires that X be a subtype of
14+
// @mut int.
15+
let f: @mut int = r();
16+
17+
// OK.
18+
let g: @const int = r();
19+
20+
// Bad.
21+
let h: @int = r(); //! ERROR (values differ in mutability)
22+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
fn mk_identity<T:copy>() -> fn@(T) -> T {
2+
fn@(t: T) -> T { t }
3+
}
4+
5+
fn main() {
6+
// type of r is fn@(X) -> X
7+
// for some fresh X
8+
let r = mk_identity();
9+
10+
// @mut int <: X
11+
r(@mut 3);
12+
13+
// @int <: X
14+
//
15+
// Note: this is really an inference failure.
16+
// The correct answer would be to make X
17+
// equal to @const int, but we are not (yet)
18+
// smart enough.
19+
r(@3); //! ERROR (values differ in mutability)
20+
21+
}

src/test/run-pass/unreachable-code.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ fn ret_guard() {
3535
}
3636
}
3737

38-
fn rec_ret() { let _r = {c: ret}; }
38+
fn rec_ret() { let _r: {c: int} = {c: ret}; }
3939

40-
fn vec_ret() { let _v = [1, 2, ret, 4]; }
40+
fn vec_ret() { let _v: [int] = [1, 2, ret, 4]; }
4141

4242
fn fail_then_concat() {
4343
let mut x = [], y = [3];

src/test/run-pass/weird-exprs.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Just a grab bag of stuff that you wouldn't want to actually write.
22

3-
fn strange() -> bool { let _x = ret true; }
3+
fn strange() -> bool { let _x: bool = ret true; }
44

55
fn funny() {
66
fn f(_x: ()) { }
@@ -19,8 +19,8 @@ fn zombiejesus() {
1919
do {
2020
while (ret) {
2121
if (ret) {
22-
alt (ret) {
23-
_ {
22+
alt check (ret) {
23+
1 {
2424
if (ret) {
2525
ret
2626
} else {
@@ -51,13 +51,13 @@ fn canttouchthis() -> uint {
5151
pure fn p() -> bool { true }
5252
let _a = (assert (true)) == (check (p()));
5353
let _c = (check (p())) == ();
54-
let _b = (log(debug, 0) == (ret 0u));
54+
let _b: bool = (log(debug, 0) == (ret 0u));
5555
}
5656

5757
fn angrydome() {
5858
loop { if break { } }
5959
let mut i = 0;
60-
do { i += 1; if i == 1 { alt cont { _ { } } } } while false
60+
do { i += 1; if i == 1 { alt check cont { 1 { } } } } while false
6161
}
6262

6363
fn evil_lincoln() { let evil <- #debug("lincoln"); }

0 commit comments

Comments
 (0)