From bf9d714d469e595bdfa5b8b5fac61a90fc0db9e8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 24 Mar 2012 21:24:47 -0700 Subject: Avoid unifying vars when possible; handle bot (more) correctly --- src/rustc/middle/infer.rs | 39 +++++++++++++++++++++++++++++---------- src/rustc/middle/typeck.rs | 33 +++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 24 deletions(-) (limited to 'src/rustc') diff --git a/src/rustc/middle/infer.rs b/src/rustc/middle/infer.rs index abd44d6a851..6a246f6d4bc 100644 --- a/src/rustc/middle/infer.rs +++ b/src/rustc/middle/infer.rs @@ -293,14 +293,32 @@ impl unify_methods for infer_ctxt { } fn vars(a_id: uint, b_id: uint) -> ures { - #debug["vars( <: )", - a_id, b_id]; - // Need to make sub_id a subtype of sup_id. let {root: a_id, bounds: a_bounds} = self.get(a_id); let {root: b_id, bounds: b_bounds} = self.get(b_id); + #debug["vars(=%s <: =%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 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 {|| // For max perf, we should consider the rank here. 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 { - #debug["varty( <: %s)", - a_id, self.ty_to_str(b)]; let {root: a_id, bounds: a_bounds} = self.get(a_id); + #debug["varty(=%s <: %s)", + a_id, self.bounds_to_str(a_bounds), + self.ty_to_str(b)]; let b_bounds = {lb: none, ub: some(b)}; self.merge(a_id, a_bounds, b_bounds) } fn tyvar(a: ty::t, b_id: uint) -> ures { - #debug["tyvar(%s <: )", - self.ty_to_str(a), b_id]; let a_bounds = {lb: some(a), ub: none}; let {root: b_id, bounds: b_bounds} = self.get(b_id); + #debug["tyvar(%s <: =%s)", + self.ty_to_str(a), + b_id, self.bounds_to_str(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(); } alt (ty::get(a).struct, ty::get(b).struct) { + (ty::ty_bot, _) { self.uok() } + (ty::ty_var(a_id), ty::ty_var(b_id)) { 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) } - (_, ty::ty_bot) { self.uok() } - (ty::ty_bot, _) { self.uok() } - (ty::ty_nil, _) | (ty::ty_bool, _) | (ty::ty_int(_), _) | diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 5c512690c17..2dabc5b9faa 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -2483,15 +2483,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let (if_t, if_bot) = alt elsopt { some(els) { + let if_t = next_ty_var(fcx); let thn_bot = check_block(fcx, thn); let thn_t = block_ty(fcx.ccx.tcx, thn); - let els_bot = check_expr_with(fcx, els, thn_t); - let els_t = expr_ty(fcx.ccx.tcx, els); - let if_t = if !ty::type_is_bot(els_t) { - els_t - } else { - thn_t - }; + demand::simple(fcx, thn.span, if_t, thn_t); + let els_bot = check_expr_with(fcx, els, if_t); (if_t, thn_bot & els_bot) } 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) { - 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 { ast::eq | ast::lt | ast::le | ast::ne | ast::ge | 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::ge, lhs, rhs) { let tcx = fcx.ccx.tcx; - bot |= check_expr(fcx, lhs); - let lhs_t = expr_ty(tcx, lhs); - bot |= check_expr_with(fcx, rhs, lhs_t); + let tvar = next_ty_var(fcx); + bot |= check_expr_with(fcx, lhs, tvar); + bot |= check_expr_with(fcx, rhs, tvar); write_ty(tcx, id, ty::mk_bool(tcx)); } 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) { 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); } 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); } 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); // Typecheck the patterns first, so that we get types for all the // bindings. - let pattern_ty = ty::expr_ty(tcx, discrim); + //let pattern_ty = ty::expr_ty(tcx, discrim); for arm: ast::arm in arms { let pcx = { 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)); } + #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)); ret bot; } -- cgit 1.4.1-3-g733a5