store into the borrowings table

This commit is contained in:
Niko Matsakis 2012-04-13 14:52:11 -07:00
parent 4d73185f3e
commit 378996092e
3 changed files with 61 additions and 59 deletions

View file

@ -1,6 +1,7 @@
import std::smallintmap; import std::smallintmap;
import std::smallintmap::smallintmap; import std::smallintmap::smallintmap;
import std::smallintmap::map; import std::smallintmap::map;
import std::map::hashmap;
import middle::ty; import middle::ty;
import middle::ty::{ty_vid, region_vid, vid}; import middle::ty::{ty_vid, region_vid, vid};
import syntax::ast; import syntax::ast;
@ -77,11 +78,12 @@ fn mk_eqty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
indent {|| cx.commit {|| cx.eq_tys(a, b) } }.to_ures() indent {|| cx.commit {|| cx.eq_tys(a, b) } }.to_ures()
} }
fn mk_assignty(cx: infer_ctxt, encl_node_id: ast::node_id, fn mk_assignty(cx: infer_ctxt, a_node_id: ast::node_id,
a: ty::t, b: ty::t) -> ures { a: ty::t, b: ty::t) -> ures {
#debug["mk_assignty(%s <: %s)", a.to_str(cx), b.to_str(cx)]; #debug["mk_assignty(%? / %s <: %s)",
a_node_id, a.to_str(cx), b.to_str(cx)];
indent {|| cx.commit {|| indent {|| cx.commit {||
cx.assign_tys(encl_node_id, a, b) cx.assign_tys(a_node_id, a, b)
} }.to_ures() } }.to_ures()
} }
@ -686,7 +688,7 @@ impl resolve_methods for infer_ctxt {
// Type assignment // Type assignment
// //
// True if rvalues of type `a` can be assigned to lvalues of type `b`. // True if rvalues of type `a` can be assigned to lvalues of type `b`.
// This may cause borrowing to the region scope for `encl_node_id`. // This may cause borrowing to the region scope enclosing `a_node_id`.
// //
// The strategy here is somewhat non-obvious. The problem is // The strategy here is somewhat non-obvious. The problem is
// that the constraint we wish to contend with is not a subtyping // that the constraint we wish to contend with is not a subtyping
@ -730,7 +732,7 @@ impl resolve_methods for infer_ctxt {
// this upper-bound might be stricter than what is truly needed. // this upper-bound might be stricter than what is truly needed.
impl assignment for infer_ctxt { impl assignment for infer_ctxt {
fn assign_tys(encl_node_id: ast::node_id, fn assign_tys(a_node_id: ast::node_id,
a: ty::t, b: ty::t) -> ures { a: ty::t, b: ty::t) -> ures {
fn select(fst: option<ty::t>, snd: option<ty::t>) -> option<ty::t> { fn select(fst: option<ty::t>, snd: option<ty::t>) -> option<ty::t> {
@ -745,8 +747,8 @@ impl assignment for infer_ctxt {
} }
} }
#debug["assign_tys(encl_node_id=%?, %s -> %s)", #debug["assign_tys(a_node_id=%?, %s -> %s)",
encl_node_id, a.to_str(self), b.to_str(self)]; a_node_id, a.to_str(self), b.to_str(self)];
let _r = indenter(); let _r = indenter();
alt (ty::get(a).struct, ty::get(b).struct) { alt (ty::get(a).struct, ty::get(b).struct) {
@ -759,34 +761,34 @@ impl assignment for infer_ctxt {
let {root:_, bounds: b_bounds} = self.get(self.vb, b_id); let {root:_, bounds: b_bounds} = self.get(self.vb, b_id);
let a_bnd = select(a_bounds.ub, a_bounds.lb); let a_bnd = select(a_bounds.ub, a_bounds.lb);
let b_bnd = select(b_bounds.lb, b_bounds.ub); let b_bnd = select(b_bounds.lb, b_bounds.ub);
self.assign_tys_or_sub(encl_node_id, a, b, a_bnd, b_bnd) self.assign_tys_or_sub(a_node_id, a, b, a_bnd, b_bnd)
} }
(ty::ty_var(a_id), _) { (ty::ty_var(a_id), _) {
let {root:_, bounds:a_bounds} = self.get(self.vb, a_id); let {root:_, bounds:a_bounds} = self.get(self.vb, a_id);
let a_bnd = select(a_bounds.ub, a_bounds.lb); let a_bnd = select(a_bounds.ub, a_bounds.lb);
self.assign_tys_or_sub(encl_node_id, a, b, a_bnd, some(b)) self.assign_tys_or_sub(a_node_id, a, b, a_bnd, some(b))
} }
(_, ty::ty_var(b_id)) { (_, ty::ty_var(b_id)) {
let {root:_, bounds: b_bounds} = self.get(self.vb, b_id); let {root:_, bounds: b_bounds} = self.get(self.vb, b_id);
let b_bnd = select(b_bounds.lb, b_bounds.ub); let b_bnd = select(b_bounds.lb, b_bounds.ub);
self.assign_tys_or_sub(encl_node_id, a, b, some(a), b_bnd) self.assign_tys_or_sub(a_node_id, a, b, some(a), b_bnd)
} }
(_, _) { (_, _) {
self.assign_tys_or_sub(encl_node_id, a, b, some(a), some(b)) self.assign_tys_or_sub(a_node_id, a, b, some(a), some(b))
} }
} }
} }
fn assign_tys_or_sub( fn assign_tys_or_sub(
encl_node_id: ast::node_id, a_node_id: ast::node_id,
a: ty::t, b: ty::t, a: ty::t, b: ty::t,
a_bnd: option<ty::t>, b_bnd: option<ty::t>) -> ures { a_bnd: option<ty::t>, b_bnd: option<ty::t>) -> ures {
#debug["assign_tys_or_sub(encl_node_id=%?, %s -> %s, %s -> %s)", #debug["assign_tys_or_sub(a_node_id=%?, %s -> %s, %s -> %s)",
encl_node_id, a.to_str(self), b.to_str(self), a_node_id, a.to_str(self), b.to_str(self),
a_bnd.to_str(self), b_bnd.to_str(self)]; a_bnd.to_str(self), b_bnd.to_str(self)];
let _r = indenter(); let _r = indenter();
@ -802,17 +804,17 @@ impl assignment for infer_ctxt {
alt (ty::get(a_bnd).struct, ty::get(b_bnd).struct) { alt (ty::get(a_bnd).struct, ty::get(b_bnd).struct) {
(ty::ty_box(mt_a), ty::ty_rptr(r_b, mt_b)) { (ty::ty_box(mt_a), ty::ty_rptr(r_b, mt_b)) {
let nr_b = ty::mk_box(self.tcx, mt_b); let nr_b = ty::mk_box(self.tcx, mt_b);
self.crosspolinate(encl_node_id, a, nr_b, r_b) self.crosspolinate(a_node_id, a, nr_b, r_b)
} }
(ty::ty_uniq(mt_a), ty::ty_rptr(r_b, mt_b)) { (ty::ty_uniq(mt_a), ty::ty_rptr(r_b, mt_b)) {
let nr_b = ty::mk_uniq(self.tcx, mt_b); let nr_b = ty::mk_uniq(self.tcx, mt_b);
self.crosspolinate(encl_node_id, a, nr_b, r_b) self.crosspolinate(a_node_id, a, nr_b, r_b)
} }
(ty::ty_evec(mt_a, vs_a), (ty::ty_evec(mt_a, vs_a),
ty::ty_evec(mt_b, ty::vstore_slice(r_b))) ty::ty_evec(mt_b, ty::vstore_slice(r_b)))
if is_borrowable(vs_a) { if is_borrowable(vs_a) {
let nr_b = ty::mk_evec(self.tcx, mt_b, vs_a); let nr_b = ty::mk_evec(self.tcx, mt_b, vs_a);
self.crosspolinate(encl_node_id, a, nr_b, r_b) self.crosspolinate(a_node_id, a, nr_b, r_b)
} }
_ { _ {
self.sub_tys(a, b) self.sub_tys(a, b)
@ -825,17 +827,26 @@ impl assignment for infer_ctxt {
} }
} }
fn crosspolinate(encl_node_id: ast::node_id, fn crosspolinate(a_node_id: ast::node_id,
a: ty::t, nr_b: ty::t, r_b: ty::region) -> ures { a: ty::t,
nr_b: ty::t,
r_b: ty::region) -> ures {
#debug["crosspolinate(encl_node_id=%?, a=%s, nr_b=%s, r_b=%s)", #debug["crosspolinate(a_node_id=%?, a=%s, nr_b=%s, r_b=%s)",
encl_node_id, a.to_str(self), nr_b.to_str(self), a_node_id, a.to_str(self), nr_b.to_str(self),
r_b.to_str(self)]; r_b.to_str(self)];
indent {|| indent {||
self.sub_tys(a, nr_b).then {|| self.sub_tys(a, nr_b).then {||
let r_a = ty::re_scope(encl_node_id); let a_scope_id = self.tcx.region_map.parents.get(a_node_id);
sub(self).contraregions(r_a, r_b).to_ures() let r_a = ty::re_scope(a_scope_id);
#debug["a_scope_id=%?", a_scope_id];
sub(self).contraregions(r_a, r_b).chain {|_r|
// if successful, add an entry indicating that
// borrowing occurred
self.tcx.borrowings.insert(a_node_id, ());
uok()
}
} }
} }
} }

View file

@ -192,12 +192,6 @@ enum ast_ty_to_ty_cache_entry {
atttce_resolved(t) /* resolved to a type, irrespective of region */ atttce_resolved(t) /* resolved to a type, irrespective of region */
} }
enum borrowing {
bo_none,
bo_box(@borrowing),
bo_uniq(@borrowing)
}
type ctxt = type ctxt =
@{interner: hashmap<intern_key, t_box>, @{interner: hashmap<intern_key, t_box>,
mut next_id: uint, mut next_id: uint,
@ -229,7 +223,7 @@ type ctxt =
iface_method_cache: hashmap<def_id, @[method]>, iface_method_cache: hashmap<def_id, @[method]>,
ty_param_bounds: hashmap<ast::node_id, param_bounds>, ty_param_bounds: hashmap<ast::node_id, param_bounds>,
inferred_modes: hashmap<ast::node_id, ast::mode>, inferred_modes: hashmap<ast::node_id, ast::mode>,
borrowings: hashmap<ast::node_id, borrowing>}; borrowings: hashmap<ast::node_id, ()>};
type t_box = @{struct: sty, type t_box = @{struct: sty,
id: uint, id: uint,

View file

@ -1426,15 +1426,13 @@ mod demand {
} }
} }
// Checks that the type `actual` can be assigned to `expected`, borrowing // Checks that the type `actual` can be assigned to `expected`.
// to `encl_node_id` if necessary. fn assign(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) {
fn assign(fcx: @fn_ctxt, sp: span, encl_node_id: ast::node_id, let expr_ty = fcx.expr_ty(expr);
expected: ty::t, actual: ty::t) { alt infer::mk_assignty(fcx.infcx, expr.id, expr_ty, expected) {
alt infer::mk_assignty(fcx.infcx, encl_node_id, actual, expected) {
result::ok(()) { /* ok */ } result::ok(()) { /* ok */ }
result::err(err) { result::err(err) {
fcx.report_mismatched_types(sp, expected, actual, err); fcx.report_mismatched_types(sp, expected, expr_ty, err);
} }
} }
} }
@ -2179,17 +2177,16 @@ fn require_pure_call(ccx: @crate_ctxt, caller_purity: ast::purity,
} }
} }
type unifier = fn(@fn_ctxt, span, ty::t, ty::t);
fn check_expr(fcx: @fn_ctxt, expr: @ast::expr) -> bool { fn check_expr(fcx: @fn_ctxt, expr: @ast::expr) -> bool {
ret check_expr_with_unifier(fcx, expr, ty::mk_nil(fcx.ccx.tcx)) { ret check_expr_with_unifier(fcx, expr, ty::mk_nil(fcx.ccx.tcx)) {||
|_fcx, _span, _t1, _t2| /* do not take any action on unify */
/* unify is a no-op */
}; };
} }
fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool { fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool {
ret check_expr_with_unifier(fcx, expr, expected, demand::suptype); ret check_expr_with_unifier(fcx, expr, expected) {||
demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
};
} }
// determine the `self` type, using fresh variables for all variables declared // determine the `self` type, using fresh variables for all variables declared
@ -2548,9 +2545,8 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
proto: ast::proto, proto: ast::proto,
decl: ast::fn_decl, decl: ast::fn_decl,
body: ast::blk, body: ast::blk,
unifier: unifier, is_loop_body: bool,
expected: ty::t, unifier: fn()) {
is_loop_body: bool) {
let tcx = fcx.ccx.tcx; let tcx = fcx.ccx.tcx;
let fty = ty::mk_fn(tcx, let fty = ty::mk_fn(tcx,
ty_of_fn_decl(tcx, m_check_tyvar(fcx), proto, decl)); ty_of_fn_decl(tcx, m_check_tyvar(fcx), proto, decl));
@ -2564,7 +2560,7 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
// typecheck the body so that we have more information about the // typecheck the body so that we have more information about the
// argument types in the body. This is needed to make binops and // argument types in the body. This is needed to make binops and
// record projection work on type inferred arguments. // record projection work on type inferred arguments.
unifier(fcx, expr.span, expected, fty); unifier();
let ret_ty = ty::ty_fn_ret(fty); let ret_ty = ty::ty_fn_ret(fty);
let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty }; let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty };
@ -2574,8 +2570,10 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
fcx.self_ty); fcx.self_ty);
} }
fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, fn check_expr_with_unifier(fcx: @fn_ctxt,
expected: ty::t, unifier: unifier) -> bool { expr: @ast::expr,
expected: ty::t,
unifier: fn()) -> bool {
#debug(">> typechecking expr %d (%s)", #debug(">> typechecking expr %d (%s)",
expr.id, syntax::print::pprust::expr_to_str(expr)); expr.id, syntax::print::pprust::expr_to_str(expr));
@ -2646,10 +2644,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr,
}; };
if is_block == check_blocks { if is_block == check_blocks {
let arg_ty = arg_tys[i].ty; let arg_ty = arg_tys[i].ty;
bot |= check_expr_with_unifier(fcx, a, arg_ty) { bot |= check_expr_with_unifier(fcx, a, arg_ty) {||
|fcx, span, expected, actual| demand::assign(fcx, a.span, arg_ty, a);
demand::assign(fcx, span, call_expr_id,
expected, actual);
}; };
} }
} }
@ -3071,7 +3067,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr,
fcx.write_nil(id); fcx.write_nil(id);
} }
ast::expr_copy(a) { ast::expr_copy(a) {
bot = check_expr_with_unifier(fcx, a, expected, unifier); bot = check_expr_with(fcx, a, expected);
fcx.write_ty(id, fcx.expr_ty(a)); fcx.write_ty(id, fcx.expr_ty(a));
} }
ast::expr_move(lhs, rhs) { ast::expr_move(lhs, rhs) {
@ -3142,7 +3138,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr,
} }
ast::expr_fn(proto, decl, body, captures) { ast::expr_fn(proto, decl, body, captures) {
check_expr_fn_with_unifier(fcx, expr, proto, decl, body, check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
unifier, expected, false); false, unifier);
capture::check_capture_clause(tcx, expr.id, proto, *captures); capture::check_capture_clause(tcx, expr.id, proto, *captures);
} }
ast::expr_fn_block(decl, body) { ast::expr_fn_block(decl, body) {
@ -3155,7 +3151,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr,
expr_to_str(expr), expr_to_str(expr),
ty_to_str(tcx, expected)); ty_to_str(tcx, expected));
check_expr_fn_with_unifier(fcx, expr, proto, decl, body, check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
unifier, expected, false); false, unifier);
} }
ast::expr_loop_body(b) { ast::expr_loop_body(b) {
let rty = structurally_resolved_type(fcx, expr.span, expected); let rty = structurally_resolved_type(fcx, expr.span, expected);
@ -3168,8 +3164,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr,
}; };
alt check b.node { alt check b.node {
ast::expr_fn_block(decl, body) { ast::expr_fn_block(decl, body) {
check_expr_fn_with_unifier(fcx, b, proto, decl, body, check_expr_fn_with_unifier(fcx, b, proto, decl, body, true) {||
unifier, inner_ty, true); demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
}
} }
} }
let block_ty = structurally_resolved_type( let block_ty = structurally_resolved_type(
@ -3517,7 +3514,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr,
ty_to_str(tcx, fcx.expr_ty(expr)), ty_to_str(tcx, fcx.expr_ty(expr)),
ty_to_str(tcx, expected)); ty_to_str(tcx, expected));
unifier(fcx, expr.span, expected, fcx.expr_ty(expr)); unifier();
#debug("<< bot=%b", bot); #debug("<< bot=%b", bot);
ret bot; ret bot;