first shot at integrating ref/value bindings into borrowck
(more needed)
This commit is contained in:
parent
60f47eabe2
commit
aacd18f4ed
8 changed files with 120 additions and 52 deletions
|
@ -454,6 +454,12 @@ impl methods of get_type_for_node for ty::ctxt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl borrowck_ctxt {
|
||||||
|
fn is_subregion_of(r_sub: ty::region, r_sup: ty::region) -> bool {
|
||||||
|
region::is_subregion_of(self.tcx.region_map, r_sub, r_sup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl error_methods for borrowck_ctxt {
|
impl error_methods for borrowck_ctxt {
|
||||||
fn report_if_err(bres: bckres<()>) {
|
fn report_if_err(bres: bckres<()>) {
|
||||||
match bres {
|
match bres {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
import categorization::{public_methods, opt_deref_kind};
|
import categorization::{public_methods, opt_deref_kind};
|
||||||
import loan::public_methods;
|
import loan::public_methods;
|
||||||
import preserve::{public_methods, preserve_condition, pc_ok, pc_if_pure};
|
import preserve::{public_methods, preserve_condition, pc_ok, pc_if_pure};
|
||||||
|
import ty::ty_region;
|
||||||
|
|
||||||
export gather_loans;
|
export gather_loans;
|
||||||
|
|
||||||
|
@ -105,10 +106,7 @@ fn req_loans_in_expr(ex: @ast::expr,
|
||||||
|
|
||||||
// make sure that the thing we are pointing out stays valid
|
// make sure that the thing we are pointing out stays valid
|
||||||
// for the lifetime `scope_r` of the resulting ptr:
|
// for the lifetime `scope_r` of the resulting ptr:
|
||||||
let scope_r =
|
let scope_r = ty_region(tcx.ty(ex));
|
||||||
match check ty::get(tcx.ty(ex)).struct {
|
|
||||||
ty::ty_rptr(r, _) => r
|
|
||||||
};
|
|
||||||
self.guarantee_valid(base_cmt, mutbl, scope_r);
|
self.guarantee_valid(base_cmt, mutbl, scope_r);
|
||||||
visit::visit_expr(ex, self, vt);
|
visit::visit_expr(ex, self, vt);
|
||||||
}
|
}
|
||||||
|
@ -474,16 +472,33 @@ impl methods for gather_loan_ctxt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::pat_ident(_, _, none) if self.pat_is_variant(pat) => {
|
ast::pat_ident(bm, id, o_pat) if !self.pat_is_variant(pat) => {
|
||||||
// nullary variant
|
match bm {
|
||||||
debug!{"nullary variant"};
|
ast::bind_by_value => {
|
||||||
|
// copying does not borrow anything, so no check is required
|
||||||
}
|
}
|
||||||
ast::pat_ident(_, id, o_pat) => {
|
ast::bind_by_ref(mutbl) => {
|
||||||
// XXX: Needs to take by-ref/by-val into account.
|
// ref x or ref x @ p --- creates a ptr which must
|
||||||
|
// remain valid for the scope of the alt
|
||||||
|
|
||||||
// x or x @ p --- `x` must remain valid for the scope of the alt
|
// find the region of the resulting pointer (note that
|
||||||
debug!{"defines identifier %s", pprust::path_to_str(id)};
|
// the type of such a pattern will *always* be a
|
||||||
|
// region pointer)
|
||||||
|
let scope_r = ty_region(tcx.ty(pat));
|
||||||
|
|
||||||
|
// if the scope of the region ptr turns out to be
|
||||||
|
// specific to this arm, wrap the categorization with
|
||||||
|
// a cat_discr() node. There is a detailed discussion
|
||||||
|
// of the function of this node in method preserve():
|
||||||
|
let arm_scope = ty::re_scope(arm_id);
|
||||||
|
if self.bccx.is_subregion_of(scope_r, arm_scope) {
|
||||||
|
let cmt_discr = self.bccx.cat_discr(cmt, alt_id);
|
||||||
|
self.guarantee_valid(cmt_discr, mutbl, scope_r);
|
||||||
|
} else {
|
||||||
|
self.guarantee_valid(cmt, mutbl, scope_r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::bind_by_implicit_ref => {
|
||||||
// Note: there is a discussion of the function of
|
// Note: there is a discussion of the function of
|
||||||
// cat_discr in the method preserve():
|
// cat_discr in the method preserve():
|
||||||
let cmt1 = self.bccx.cat_discr(cmt, alt_id);
|
let cmt1 = self.bccx.cat_discr(cmt, alt_id);
|
||||||
|
@ -499,12 +514,18 @@ impl methods for gather_loan_ctxt {
|
||||||
self.bccx.binding_map.insert(pat.id, cmt1.mutbl);
|
self.bccx.binding_map.insert(pat.id, cmt1.mutbl);
|
||||||
|
|
||||||
self.guarantee_valid(cmt1, m_const, arm_scope);
|
self.guarantee_valid(cmt1, m_const, arm_scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
for o_pat.each |p| {
|
for o_pat.each |p| {
|
||||||
self.gather_pat(cmt, p, arm_id, alt_id);
|
self.gather_pat(cmt, p, arm_id, alt_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast::pat_ident(*) => {
|
||||||
|
// nullary variant: ignore.
|
||||||
|
assert self.pat_is_variant(pat);
|
||||||
|
}
|
||||||
|
|
||||||
ast::pat_rec(field_pats, _) => {
|
ast::pat_rec(field_pats, _) => {
|
||||||
// {f1: p1, ..., fN: pN}
|
// {f1: p1, ..., fN: pN}
|
||||||
for field_pats.each |fp| {
|
for field_pats.each |fp| {
|
||||||
|
|
|
@ -39,8 +39,7 @@ impl loan_methods for loan_ctxt {
|
||||||
fn ok_with_loan_of(cmt: cmt,
|
fn ok_with_loan_of(cmt: cmt,
|
||||||
scope_ub: ty::region,
|
scope_ub: ty::region,
|
||||||
mutbl: ast::mutability) -> bckres<()> {
|
mutbl: ast::mutability) -> bckres<()> {
|
||||||
let region_map = self.tcx().region_map;
|
if self.bccx.is_subregion_of(self.scope_region, scope_ub) {
|
||||||
if region::subregion(region_map, scope_ub, self.scope_region) {
|
|
||||||
// Note: all cmt's that we deal with will have a non-none
|
// Note: all cmt's that we deal with will have a non-none
|
||||||
// lp, because the entry point into this routine,
|
// lp, because the entry point into this routine,
|
||||||
// `borrowck_ctxt::loan()`, rejects any cmt with a
|
// `borrowck_ctxt::loan()`, rejects any cmt with a
|
||||||
|
|
|
@ -232,16 +232,6 @@ impl private_methods for &preserve_ctxt {
|
||||||
// node appears to draw the line between what will be rooted
|
// node appears to draw the line between what will be rooted
|
||||||
// in the *arm* vs the *alt*.
|
// in the *arm* vs the *alt*.
|
||||||
|
|
||||||
// current scope must be the arm, which is always a child of alt:
|
|
||||||
assert {
|
|
||||||
match check self.scope_region {
|
|
||||||
ty::re_scope(arm_id) => {
|
|
||||||
self.tcx().region_map.get(arm_id) == alt_id
|
|
||||||
}
|
|
||||||
_ => {false}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let alt_rooting_ctxt =
|
let alt_rooting_ctxt =
|
||||||
preserve_ctxt({scope_region: ty::re_scope(alt_id)
|
preserve_ctxt({scope_region: ty::re_scope(alt_id)
|
||||||
with **self});
|
with **self});
|
||||||
|
@ -289,8 +279,7 @@ impl private_methods for &preserve_ctxt {
|
||||||
/// is a subscope of `scope_ub`; if so, success.
|
/// is a subscope of `scope_ub`; if so, success.
|
||||||
fn compare_scope(cmt: cmt,
|
fn compare_scope(cmt: cmt,
|
||||||
scope_ub: ty::region) -> bckres<preserve_condition> {
|
scope_ub: ty::region) -> bckres<preserve_condition> {
|
||||||
let region_map = self.tcx().region_map;
|
if self.bccx.is_subregion_of(self.scope_region, scope_ub) {
|
||||||
if region::subregion(region_map, scope_ub, self.scope_region) {
|
|
||||||
ok(pc_ok)
|
ok(pc_ok)
|
||||||
} else {
|
} else {
|
||||||
err({cmt:cmt, code:err_out_of_scope(scope_ub,
|
err({cmt:cmt, code:err_out_of_scope(scope_ub,
|
||||||
|
@ -326,12 +315,11 @@ impl private_methods for &preserve_ctxt {
|
||||||
// we can only root values if the desired region is some concrete
|
// we can only root values if the desired region is some concrete
|
||||||
// scope within the fn body
|
// scope within the fn body
|
||||||
ty::re_scope(scope_id) => {
|
ty::re_scope(scope_id) => {
|
||||||
let region_map = self.tcx().region_map;
|
|
||||||
#debug["Considering root map entry for %s: \
|
#debug["Considering root map entry for %s: \
|
||||||
node %d:%u -> scope_id %?, root_ub %?",
|
node %d:%u -> scope_id %?, root_ub %?",
|
||||||
self.bccx.cmt_to_repr(cmt), base.id,
|
self.bccx.cmt_to_repr(cmt), base.id,
|
||||||
derefs, scope_id, self.root_ub];
|
derefs, scope_id, self.root_ub];
|
||||||
if region::subregion(region_map, root_region, self.scope_region) {
|
if self.bccx.is_subregion_of(self.scope_region, root_region) {
|
||||||
#debug["Elected to root"];
|
#debug["Elected to root"];
|
||||||
let rk = {id: base.id, derefs: derefs};
|
let rk = {id: base.id, derefs: derefs};
|
||||||
self.bccx.root_map.insert(rk, scope_id);
|
self.bccx.root_map.insert(rk, scope_id);
|
||||||
|
|
|
@ -99,15 +99,17 @@ fn scope_contains(region_map: region_map, superscope: ast::node_id,
|
||||||
/// Determines whether one region is a subregion of another. This is
|
/// Determines whether one region is a subregion of another. This is
|
||||||
/// intended to run *after inference* and sadly the logic is somewhat
|
/// intended to run *after inference* and sadly the logic is somewhat
|
||||||
/// duplicated with the code in infer.rs.
|
/// duplicated with the code in infer.rs.
|
||||||
fn subregion(region_map: region_map,
|
fn is_subregion_of(region_map: region_map,
|
||||||
super_region: ty::region,
|
sub_region: ty::region,
|
||||||
sub_region: ty::region) -> bool {
|
super_region: ty::region) -> bool {
|
||||||
super_region == sub_region ||
|
sub_region == super_region ||
|
||||||
match (super_region, sub_region) {
|
match (sub_region, super_region) {
|
||||||
(ty::re_static, _) => {true}
|
(_, ty::re_static) => {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
(ty::re_scope(super_scope), ty::re_scope(sub_scope)) |
|
(ty::re_scope(sub_scope), ty::re_scope(super_scope)) |
|
||||||
(ty::re_free(super_scope, _), ty::re_scope(sub_scope)) => {
|
(ty::re_scope(sub_scope), ty::re_free(super_scope, _)) => {
|
||||||
scope_contains(region_map, super_scope, sub_scope)
|
scope_contains(region_map, super_scope, sub_scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,7 @@ export tbox_has_flag;
|
||||||
export ty_var_id;
|
export ty_var_id;
|
||||||
export ty_to_def_id;
|
export ty_to_def_id;
|
||||||
export ty_fn_args;
|
export ty_fn_args;
|
||||||
|
export ty_region;
|
||||||
export kind, kind_implicitly_copyable, kind_send_copy, kind_copyable;
|
export kind, kind_implicitly_copyable, kind_send_copy, kind_copyable;
|
||||||
export kind_noncopyable, kind_const;
|
export kind_noncopyable, kind_const;
|
||||||
export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied;
|
export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied;
|
||||||
|
@ -2297,8 +2298,15 @@ fn ty_fn_ret_style(fty: t) -> ast::ret_style {
|
||||||
|
|
||||||
fn is_fn_ty(fty: t) -> bool {
|
fn is_fn_ty(fty: t) -> bool {
|
||||||
match get(fty).struct {
|
match get(fty).struct {
|
||||||
ty_fn(_) => return true,
|
ty_fn(_) => true,
|
||||||
_ => return false
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ty_region(ty: t) -> region {
|
||||||
|
match get(ty).struct {
|
||||||
|
ty_rptr(r, _) => r,
|
||||||
|
s => fail fmt!{"ty_region() invoked on non-rptr: %?", s}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
34
src/test/compile-fail/borrowck-pat-by-value-binding.rs
Normal file
34
src/test/compile-fail/borrowck-pat-by-value-binding.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
fn process<T>(_t: T) {}
|
||||||
|
|
||||||
|
fn match_const_opt_by_mut_ref(v: &const option<int>) {
|
||||||
|
match *v {
|
||||||
|
some(ref mut i) => process(i), //~ ERROR illegal borrow
|
||||||
|
none => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_const_opt_by_const_ref(v: &const option<int>) {
|
||||||
|
match *v {
|
||||||
|
some(ref const i) => process(i), //~ ERROR illegal borrow unless pure
|
||||||
|
//~^ NOTE impure due to
|
||||||
|
none => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_const_opt_by_imm_ref(v: &const option<int>) {
|
||||||
|
match *v {
|
||||||
|
some(ref i) => process(i), //~ ERROR illegal borrow unless pure
|
||||||
|
//~^ NOTE impure due to
|
||||||
|
none => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_const_opt_by_value(v: &const option<int>) {
|
||||||
|
match *v {
|
||||||
|
some(copy i) => process(i),
|
||||||
|
none => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
10
src/test/compile-fail/borrowck-ref-mut-of-imm.rs
Normal file
10
src/test/compile-fail/borrowck-ref-mut-of-imm.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
fn destructure(x: option<int>) -> int {
|
||||||
|
match x {
|
||||||
|
none => 0,
|
||||||
|
some(ref mut v) => *v //~ ERROR illegal borrow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert destructure(some(22)) == 22;
|
||||||
|
}
|
Loading…
Reference in a new issue