Avoid unifying vars when possible; handle bot (more) correctly
This commit is contained in:
@@ -694,7 +694,7 @@ fn test_try_fail() {
|
|||||||
fail
|
fail
|
||||||
} {
|
} {
|
||||||
result::err(()) { }
|
result::err(()) { }
|
||||||
_ { fail; }
|
result::ok(()) { fail; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -293,14 +293,32 @@ impl unify_methods for infer_ctxt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn vars(a_id: uint, b_id: uint) -> ures {
|
fn vars(a_id: uint, b_id: uint) -> ures {
|
||||||
#debug["vars(<T%u> <: <T%u>)",
|
|
||||||
a_id, b_id];
|
|
||||||
|
|
||||||
// Need to make sub_id a subtype of sup_id.
|
// Need to make sub_id a subtype of sup_id.
|
||||||
let {root: a_id, bounds: a_bounds} = self.get(a_id);
|
let {root: a_id, bounds: a_bounds} = self.get(a_id);
|
||||||
let {root: b_id, bounds: b_bounds} = self.get(b_id);
|
let {root: b_id, bounds: b_bounds} = self.get(b_id);
|
||||||
|
|
||||||
|
#debug["vars(<T%u>=%s <: <T%u>=%s)",
|
||||||
|
a_id, self.bounds_to_str(a_bounds),
|
||||||
|
b_id, self.bounds_to_str(b_bounds)];
|
||||||
|
|
||||||
if a_id == b_id { ret self.uok(); }
|
if a_id == b_id { ret self.uok(); }
|
||||||
|
|
||||||
|
// If both A's UB and B's LB have already been bound to types,
|
||||||
|
// see if we can make those types subtypes.
|
||||||
|
alt (a_bounds.ub, b_bounds.lb) {
|
||||||
|
(some(a_ub), some(b_lb)) {
|
||||||
|
let r = self.try {|| self.tys(a_ub, b_lb) };
|
||||||
|
alt r {
|
||||||
|
result::ok(()) { ret result::ok(()); }
|
||||||
|
result::err(_) { /*fallthrough */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ { /*fallthrough*/ }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we need to merge A and B so as to guarantee that
|
||||||
|
// A remains a subtype of B. Actually, there are other options,
|
||||||
|
// but that's the route we choose to take.
|
||||||
self.merge(a_id, a_bounds, b_bounds).then {||
|
self.merge(a_id, a_bounds, b_bounds).then {||
|
||||||
// For max perf, we should consider the rank here.
|
// For max perf, we should consider the rank here.
|
||||||
self.set(b_id, redirect(a_id));
|
self.set(b_id, redirect(a_id));
|
||||||
@@ -309,18 +327,20 @@ impl unify_methods for infer_ctxt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn varty(a_id: uint, b: ty::t) -> ures {
|
fn varty(a_id: uint, b: ty::t) -> ures {
|
||||||
#debug["varty(<T%u> <: %s)",
|
|
||||||
a_id, self.ty_to_str(b)];
|
|
||||||
let {root: a_id, bounds: a_bounds} = self.get(a_id);
|
let {root: a_id, bounds: a_bounds} = self.get(a_id);
|
||||||
|
#debug["varty(<T%u>=%s <: %s)",
|
||||||
|
a_id, self.bounds_to_str(a_bounds),
|
||||||
|
self.ty_to_str(b)];
|
||||||
let b_bounds = {lb: none, ub: some(b)};
|
let b_bounds = {lb: none, ub: some(b)};
|
||||||
self.merge(a_id, a_bounds, b_bounds)
|
self.merge(a_id, a_bounds, b_bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tyvar(a: ty::t, b_id: uint) -> ures {
|
fn tyvar(a: ty::t, b_id: uint) -> ures {
|
||||||
#debug["tyvar(%s <: <T%u>)",
|
|
||||||
self.ty_to_str(a), b_id];
|
|
||||||
let a_bounds = {lb: some(a), ub: none};
|
let a_bounds = {lb: some(a), ub: none};
|
||||||
let {root: b_id, bounds: b_bounds} = self.get(b_id);
|
let {root: b_id, bounds: b_bounds} = self.get(b_id);
|
||||||
|
#debug["tyvar(%s <: <T%u>=%s)",
|
||||||
|
self.ty_to_str(a),
|
||||||
|
b_id, self.bounds_to_str(b_bounds)];
|
||||||
self.merge(b_id, a_bounds, b_bounds)
|
self.merge(b_id, a_bounds, b_bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,6 +552,8 @@ impl unify_methods for infer_ctxt {
|
|||||||
if a == b { ret self.uok(); }
|
if a == b { ret self.uok(); }
|
||||||
|
|
||||||
alt (ty::get(a).struct, ty::get(b).struct) {
|
alt (ty::get(a).struct, ty::get(b).struct) {
|
||||||
|
(ty::ty_bot, _) { self.uok() }
|
||||||
|
|
||||||
(ty::ty_var(a_id), ty::ty_var(b_id)) {
|
(ty::ty_var(a_id), ty::ty_var(b_id)) {
|
||||||
self.vars(a_id as uint, b_id as uint)
|
self.vars(a_id as uint, b_id as uint)
|
||||||
}
|
}
|
||||||
@@ -542,9 +564,6 @@ impl unify_methods for infer_ctxt {
|
|||||||
self.tyvar(a, b_id as uint)
|
self.tyvar(a, b_id as uint)
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, ty::ty_bot) { self.uok() }
|
|
||||||
(ty::ty_bot, _) { self.uok() }
|
|
||||||
|
|
||||||
(ty::ty_nil, _) |
|
(ty::ty_nil, _) |
|
||||||
(ty::ty_bool, _) |
|
(ty::ty_bool, _) |
|
||||||
(ty::ty_int(_), _) |
|
(ty::ty_int(_), _) |
|
||||||
|
|||||||
@@ -2483,15 +2483,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||||||
let (if_t, if_bot) =
|
let (if_t, if_bot) =
|
||||||
alt elsopt {
|
alt elsopt {
|
||||||
some(els) {
|
some(els) {
|
||||||
|
let if_t = next_ty_var(fcx);
|
||||||
let thn_bot = check_block(fcx, thn);
|
let thn_bot = check_block(fcx, thn);
|
||||||
let thn_t = block_ty(fcx.ccx.tcx, thn);
|
let thn_t = block_ty(fcx.ccx.tcx, thn);
|
||||||
let els_bot = check_expr_with(fcx, els, thn_t);
|
demand::simple(fcx, thn.span, if_t, thn_t);
|
||||||
let els_t = expr_ty(fcx.ccx.tcx, els);
|
let els_bot = check_expr_with(fcx, els, if_t);
|
||||||
let if_t = if !ty::type_is_bot(els_t) {
|
|
||||||
els_t
|
|
||||||
} else {
|
|
||||||
thn_t
|
|
||||||
};
|
|
||||||
(if_t, thn_bot & els_bot)
|
(if_t, thn_bot & els_bot)
|
||||||
}
|
}
|
||||||
none {
|
none {
|
||||||
@@ -2565,7 +2561,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||||||
}
|
}
|
||||||
|
|
||||||
(_, _) if ty::is_binopable(tcx, lhs_t, op) {
|
(_, _) if ty::is_binopable(tcx, lhs_t, op) {
|
||||||
let rhs_bot = check_expr_with(fcx, rhs, lhs_t);
|
let tvar = next_ty_var(fcx);
|
||||||
|
demand::simple(fcx, expr.span, tvar, lhs_t);
|
||||||
|
let rhs_bot = check_expr_with(fcx, rhs, tvar);
|
||||||
let rhs_t = alt op {
|
let rhs_t = alt op {
|
||||||
ast::eq | ast::lt | ast::le | ast::ne | ast::ge |
|
ast::eq | ast::lt | ast::le | ast::ne | ast::ge |
|
||||||
ast::gt {
|
ast::gt {
|
||||||
@@ -2646,9 +2644,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||||||
ast::expr_binary(ast::gt, lhs, rhs) |
|
ast::expr_binary(ast::gt, lhs, rhs) |
|
||||||
ast::expr_binary(ast::ge, lhs, rhs) {
|
ast::expr_binary(ast::ge, lhs, rhs) {
|
||||||
let tcx = fcx.ccx.tcx;
|
let tcx = fcx.ccx.tcx;
|
||||||
bot |= check_expr(fcx, lhs);
|
let tvar = next_ty_var(fcx);
|
||||||
let lhs_t = expr_ty(tcx, lhs);
|
bot |= check_expr_with(fcx, lhs, tvar);
|
||||||
bot |= check_expr_with(fcx, rhs, lhs_t);
|
bot |= check_expr_with(fcx, rhs, tvar);
|
||||||
write_ty(tcx, id, ty::mk_bool(tcx));
|
write_ty(tcx, id, ty::mk_bool(tcx));
|
||||||
}
|
}
|
||||||
ast::expr_binary(op, lhs, rhs) {
|
ast::expr_binary(op, lhs, rhs) {
|
||||||
@@ -2782,7 +2780,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||||||
}
|
}
|
||||||
ast::expr_log(_, lv, e) {
|
ast::expr_log(_, lv, e) {
|
||||||
bot = check_expr_with(fcx, lv, ty::mk_mach_uint(tcx, ast::ty_u32));
|
bot = check_expr_with(fcx, lv, ty::mk_mach_uint(tcx, ast::ty_u32));
|
||||||
bot |= check_expr(fcx, e);
|
// Note: this does not always execute, so do not propagate bot:
|
||||||
|
check_expr(fcx, e);
|
||||||
write_nil(tcx, id);
|
write_nil(tcx, id);
|
||||||
}
|
}
|
||||||
ast::expr_check(_, e) {
|
ast::expr_check(_, e) {
|
||||||
@@ -2850,13 +2849,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||||||
bot = !may_break(body);
|
bot = !may_break(body);
|
||||||
}
|
}
|
||||||
ast::expr_alt(discrim, arms, _) {
|
ast::expr_alt(discrim, arms, _) {
|
||||||
bot = check_expr(fcx, discrim);
|
let pattern_ty = next_ty_var(fcx);
|
||||||
|
bot = check_expr_with(fcx, discrim, pattern_ty);
|
||||||
|
|
||||||
let parent_block = tcx.region_map.rvalue_to_block.get(discrim.id);
|
let parent_block = tcx.region_map.rvalue_to_block.get(discrim.id);
|
||||||
|
|
||||||
// Typecheck the patterns first, so that we get types for all the
|
// Typecheck the patterns first, so that we get types for all the
|
||||||
// bindings.
|
// bindings.
|
||||||
let pattern_ty = ty::expr_ty(tcx, discrim);
|
//let pattern_ty = ty::expr_ty(tcx, discrim);
|
||||||
for arm: ast::arm in arms {
|
for arm: ast::arm in arms {
|
||||||
let pcx = {
|
let pcx = {
|
||||||
fcx: fcx,
|
fcx: fcx,
|
||||||
@@ -3205,6 +3205,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||||||
}
|
}
|
||||||
if bot { write_ty(tcx, expr.id, ty::mk_bot(tcx)); }
|
if bot { write_ty(tcx, expr.id, ty::mk_bot(tcx)); }
|
||||||
|
|
||||||
|
#debug("type of expr %s is %s, expected is %s",
|
||||||
|
syntax::print::pprust::expr_to_str(expr),
|
||||||
|
ty_to_str(tcx, expr_ty(tcx, expr)),
|
||||||
|
ty_to_str(tcx, expected));
|
||||||
|
|
||||||
unify(fcx, expr.span, expected, expr_ty(tcx, expr));
|
unify(fcx, expr.span, expected, expr_ty(tcx, expr));
|
||||||
ret bot;
|
ret bot;
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/test/compile-fail/fn-variance-1.rs
Normal file
17
src/test/compile-fail/fn-variance-1.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
fn takes_mut(&&x: @mut int) { }
|
||||||
|
fn takes_const(&&x: @const int) { }
|
||||||
|
fn takes_imm(&&x: @int) { }
|
||||||
|
|
||||||
|
fn apply<T>(t: T, f: fn(T)) {
|
||||||
|
f(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
apply(@3, takes_mut); //! ERROR (values differ in mutability)
|
||||||
|
apply(@3, takes_const);
|
||||||
|
apply(@3, takes_imm);
|
||||||
|
|
||||||
|
apply(@mut 3, takes_mut);
|
||||||
|
apply(@mut 3, takes_const);
|
||||||
|
apply(@mut 3, takes_imm); //! ERROR (values differ in mutability)
|
||||||
|
}
|
||||||
22
src/test/compile-fail/fn-variance-2.rs
Normal file
22
src/test/compile-fail/fn-variance-2.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
fn reproduce<T:copy>(t: T) -> fn@() -> T {
|
||||||
|
fn@() -> T { t }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// type of x is the variable X,
|
||||||
|
// with the lower bound @mut int
|
||||||
|
let x = @mut 3;
|
||||||
|
|
||||||
|
// type of r is fn@() -> X
|
||||||
|
let r = reproduce(x);
|
||||||
|
|
||||||
|
// Requires that X be a subtype of
|
||||||
|
// @mut int.
|
||||||
|
let f: @mut int = r();
|
||||||
|
|
||||||
|
// OK.
|
||||||
|
let g: @const int = r();
|
||||||
|
|
||||||
|
// Bad.
|
||||||
|
let h: @int = r(); //! ERROR (values differ in mutability)
|
||||||
|
}
|
||||||
21
src/test/compile-fail/fn-variance-3.rs
Normal file
21
src/test/compile-fail/fn-variance-3.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
fn mk_identity<T:copy>() -> fn@(T) -> T {
|
||||||
|
fn@(t: T) -> T { t }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// type of r is fn@(X) -> X
|
||||||
|
// for some fresh X
|
||||||
|
let r = mk_identity();
|
||||||
|
|
||||||
|
// @mut int <: X
|
||||||
|
r(@mut 3);
|
||||||
|
|
||||||
|
// @int <: X
|
||||||
|
//
|
||||||
|
// Note: this is really an inference failure.
|
||||||
|
// The correct answer would be to make X
|
||||||
|
// equal to @const int, but we are not (yet)
|
||||||
|
// smart enough.
|
||||||
|
r(@3); //! ERROR (values differ in mutability)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -35,9 +35,9 @@ fn ret_guard() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rec_ret() { let _r = {c: ret}; }
|
fn rec_ret() { let _r: {c: int} = {c: ret}; }
|
||||||
|
|
||||||
fn vec_ret() { let _v = [1, 2, ret, 4]; }
|
fn vec_ret() { let _v: [int] = [1, 2, ret, 4]; }
|
||||||
|
|
||||||
fn fail_then_concat() {
|
fn fail_then_concat() {
|
||||||
let mut x = [], y = [3];
|
let mut x = [], y = [3];
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Just a grab bag of stuff that you wouldn't want to actually write.
|
// Just a grab bag of stuff that you wouldn't want to actually write.
|
||||||
|
|
||||||
fn strange() -> bool { let _x = ret true; }
|
fn strange() -> bool { let _x: bool = ret true; }
|
||||||
|
|
||||||
fn funny() {
|
fn funny() {
|
||||||
fn f(_x: ()) { }
|
fn f(_x: ()) { }
|
||||||
@@ -19,8 +19,8 @@ fn zombiejesus() {
|
|||||||
do {
|
do {
|
||||||
while (ret) {
|
while (ret) {
|
||||||
if (ret) {
|
if (ret) {
|
||||||
alt (ret) {
|
alt check (ret) {
|
||||||
_ {
|
1 {
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ret
|
ret
|
||||||
} else {
|
} else {
|
||||||
@@ -51,13 +51,13 @@ fn canttouchthis() -> uint {
|
|||||||
pure fn p() -> bool { true }
|
pure fn p() -> bool { true }
|
||||||
let _a = (assert (true)) == (check (p()));
|
let _a = (assert (true)) == (check (p()));
|
||||||
let _c = (check (p())) == ();
|
let _c = (check (p())) == ();
|
||||||
let _b = (log(debug, 0) == (ret 0u));
|
let _b: bool = (log(debug, 0) == (ret 0u));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn angrydome() {
|
fn angrydome() {
|
||||||
loop { if break { } }
|
loop { if break { } }
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
do { i += 1; if i == 1 { alt cont { _ { } } } } while false
|
do { i += 1; if i == 1 { alt check cont { 1 { } } } } while false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evil_lincoln() { let evil <- #debug("lincoln"); }
|
fn evil_lincoln() { let evil <- #debug("lincoln"); }
|
||||||
|
|||||||
Reference in New Issue
Block a user