Skip to content

Commit aacd18f

Browse files
committed
first shot at integrating ref/value bindings into borrowck
(more needed)
1 parent 60f47ea commit aacd18f

File tree

8 files changed

+125
-57
lines changed

8 files changed

+125
-57
lines changed

src/rustc/middle/borrowck.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,12 @@ impl methods of get_type_for_node for ty::ctxt {
454454
}
455455
}
456456

457+
impl borrowck_ctxt {
458+
fn is_subregion_of(r_sub: ty::region, r_sup: ty::region) -> bool {
459+
region::is_subregion_of(self.tcx.region_map, r_sub, r_sup)
460+
}
461+
}
462+
457463
impl error_methods for borrowck_ctxt {
458464
fn report_if_err(bres: bckres<()>) {
459465
match bres {

src/rustc/middle/borrowck/gather_loans.rs

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import categorization::{public_methods, opt_deref_kind};
1010
import loan::public_methods;
1111
import preserve::{public_methods, preserve_condition, pc_ok, pc_if_pure};
12+
import ty::ty_region;
1213

1314
export gather_loans;
1415

@@ -105,10 +106,7 @@ fn req_loans_in_expr(ex: @ast::expr,
105106

106107
// make sure that the thing we are pointing out stays valid
107108
// for the lifetime `scope_r` of the resulting ptr:
108-
let scope_r =
109-
match check ty::get(tcx.ty(ex)).struct {
110-
ty::ty_rptr(r, _) => r
111-
};
109+
let scope_r = ty_region(tcx.ty(ex));
112110
self.guarantee_valid(base_cmt, mutbl, scope_r);
113111
visit::visit_expr(ex, self, vt);
114112
}
@@ -474,37 +472,60 @@ impl methods for gather_loan_ctxt {
474472
}
475473
}
476474

477-
ast::pat_ident(_, _, none) if self.pat_is_variant(pat) => {
478-
// nullary variant
479-
debug!{"nullary variant"};
480-
}
481-
ast::pat_ident(_, id, o_pat) => {
482-
// XXX: Needs to take by-ref/by-val into account.
483-
484-
// x or x @ p --- `x` must remain valid for the scope of the alt
485-
debug!{"defines identifier %s", pprust::path_to_str(id)};
486-
487-
// Note: there is a discussion of the function of
488-
// cat_discr in the method preserve():
489-
let cmt1 = self.bccx.cat_discr(cmt, alt_id);
490-
let arm_scope = ty::re_scope(arm_id);
491-
492-
// Remember the mutability of the location that this
493-
// binding refers to. This will be used later when
494-
// categorizing the binding. This is a bit of a hack that
495-
// would be better fixed by #2329; in that case we could
496-
// allow the user to specify if they want an imm, const,
497-
// or mut binding, or else just reflect the mutability
498-
// through the type of the region pointer.
499-
self.bccx.binding_map.insert(pat.id, cmt1.mutbl);
500-
501-
self.guarantee_valid(cmt1, m_const, arm_scope);
502-
475+
ast::pat_ident(bm, id, o_pat) if !self.pat_is_variant(pat) => {
476+
match bm {
477+
ast::bind_by_value => {
478+
// copying does not borrow anything, so no check is required
479+
}
480+
ast::bind_by_ref(mutbl) => {
481+
// ref x or ref x @ p --- creates a ptr which must
482+
// remain valid for the scope of the alt
483+
484+
// find the region of the resulting pointer (note that
485+
// the type of such a pattern will *always* be a
486+
// region pointer)
487+
let scope_r = ty_region(tcx.ty(pat));
488+
489+
// if the scope of the region ptr turns out to be
490+
// specific to this arm, wrap the categorization with
491+
// a cat_discr() node. There is a detailed discussion
492+
// of the function of this node in method preserve():
493+
let arm_scope = ty::re_scope(arm_id);
494+
if self.bccx.is_subregion_of(scope_r, arm_scope) {
495+
let cmt_discr = self.bccx.cat_discr(cmt, alt_id);
496+
self.guarantee_valid(cmt_discr, mutbl, scope_r);
497+
} else {
498+
self.guarantee_valid(cmt, mutbl, scope_r);
499+
}
500+
}
501+
ast::bind_by_implicit_ref => {
502+
// Note: there is a discussion of the function of
503+
// cat_discr in the method preserve():
504+
let cmt1 = self.bccx.cat_discr(cmt, alt_id);
505+
let arm_scope = ty::re_scope(arm_id);
506+
507+
// Remember the mutability of the location that this
508+
// binding refers to. This will be used later when
509+
// categorizing the binding. This is a bit of a hack that
510+
// would be better fixed by #2329; in that case we could
511+
// allow the user to specify if they want an imm, const,
512+
// or mut binding, or else just reflect the mutability
513+
// through the type of the region pointer.
514+
self.bccx.binding_map.insert(pat.id, cmt1.mutbl);
515+
516+
self.guarantee_valid(cmt1, m_const, arm_scope);
517+
}
518+
}
503519
for o_pat.each |p| {
504520
self.gather_pat(cmt, p, arm_id, alt_id);
505521
}
506522
}
507523

524+
ast::pat_ident(*) => {
525+
// nullary variant: ignore.
526+
assert self.pat_is_variant(pat);
527+
}
528+
508529
ast::pat_rec(field_pats, _) => {
509530
// {f1: p1, ..., fN: pN}
510531
for field_pats.each |fp| {

src/rustc/middle/borrowck/loan.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ impl loan_methods for loan_ctxt {
3939
fn ok_with_loan_of(cmt: cmt,
4040
scope_ub: ty::region,
4141
mutbl: ast::mutability) -> bckres<()> {
42-
let region_map = self.tcx().region_map;
43-
if region::subregion(region_map, scope_ub, self.scope_region) {
42+
if self.bccx.is_subregion_of(self.scope_region, scope_ub) {
4443
// Note: all cmt's that we deal with will have a non-none
4544
// lp, because the entry point into this routine,
4645
// `borrowck_ctxt::loan()`, rejects any cmt with a

src/rustc/middle/borrowck/preserve.rs

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -232,16 +232,6 @@ impl private_methods for &preserve_ctxt {
232232
// node appears to draw the line between what will be rooted
233233
// in the *arm* vs the *alt*.
234234

235-
// current scope must be the arm, which is always a child of alt:
236-
assert {
237-
match check self.scope_region {
238-
ty::re_scope(arm_id) => {
239-
self.tcx().region_map.get(arm_id) == alt_id
240-
}
241-
_ => {false}
242-
}
243-
};
244-
245235
let alt_rooting_ctxt =
246236
preserve_ctxt({scope_region: ty::re_scope(alt_id)
247237
with **self});
@@ -289,8 +279,7 @@ impl private_methods for &preserve_ctxt {
289279
/// is a subscope of `scope_ub`; if so, success.
290280
fn compare_scope(cmt: cmt,
291281
scope_ub: ty::region) -> bckres<preserve_condition> {
292-
let region_map = self.tcx().region_map;
293-
if region::subregion(region_map, scope_ub, self.scope_region) {
282+
if self.bccx.is_subregion_of(self.scope_region, scope_ub) {
294283
ok(pc_ok)
295284
} else {
296285
err({cmt:cmt, code:err_out_of_scope(scope_ub,
@@ -326,12 +315,11 @@ impl private_methods for &preserve_ctxt {
326315
// we can only root values if the desired region is some concrete
327316
// scope within the fn body
328317
ty::re_scope(scope_id) => {
329-
let region_map = self.tcx().region_map;
330318
#debug["Considering root map entry for %s: \
331319
node %d:%u -> scope_id %?, root_ub %?",
332320
self.bccx.cmt_to_repr(cmt), base.id,
333321
derefs, scope_id, self.root_ub];
334-
if region::subregion(region_map, root_region, self.scope_region) {
322+
if self.bccx.is_subregion_of(self.scope_region, root_region) {
335323
#debug["Elected to root"];
336324
let rk = {id: base.id, derefs: derefs};
337325
self.bccx.root_map.insert(rk, scope_id);

src/rustc/middle/region.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,17 @@ fn scope_contains(region_map: region_map, superscope: ast::node_id,
9999
/// Determines whether one region is a subregion of another. This is
100100
/// intended to run *after inference* and sadly the logic is somewhat
101101
/// duplicated with the code in infer.rs.
102-
fn subregion(region_map: region_map,
103-
super_region: ty::region,
104-
sub_region: ty::region) -> bool {
105-
super_region == sub_region ||
106-
match (super_region, sub_region) {
107-
(ty::re_static, _) => {true}
108-
109-
(ty::re_scope(super_scope), ty::re_scope(sub_scope)) |
110-
(ty::re_free(super_scope, _), ty::re_scope(sub_scope)) => {
102+
fn is_subregion_of(region_map: region_map,
103+
sub_region: ty::region,
104+
super_region: ty::region) -> bool {
105+
sub_region == super_region ||
106+
match (sub_region, super_region) {
107+
(_, ty::re_static) => {
108+
true
109+
}
110+
111+
(ty::re_scope(sub_scope), ty::re_scope(super_scope)) |
112+
(ty::re_scope(sub_scope), ty::re_free(super_scope, _)) => {
111113
scope_contains(region_map, super_scope, sub_scope)
112114
}
113115

src/rustc/middle/ty.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export tbox_has_flag;
107107
export ty_var_id;
108108
export ty_to_def_id;
109109
export ty_fn_args;
110+
export ty_region;
110111
export kind, kind_implicitly_copyable, kind_send_copy, kind_copyable;
111112
export kind_noncopyable, kind_const;
112113
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 {
22972298
22982299
fn is_fn_ty(fty: t) -> bool {
22992300
match get(fty).struct {
2300-
ty_fn(_) => return true,
2301-
_ => return false
2301+
ty_fn(_) => true,
2302+
_ => false
2303+
}
2304+
}
2305+
2306+
fn ty_region(ty: t) -> region {
2307+
match get(ty).struct {
2308+
ty_rptr(r, _) => r,
2309+
s => fail fmt!{"ty_region() invoked on non-rptr: %?", s}
23022310
}
23032311
}
23042312
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
fn process<T>(_t: T) {}
2+
3+
fn match_const_opt_by_mut_ref(v: &const option<int>) {
4+
match *v {
5+
some(ref mut i) => process(i), //~ ERROR illegal borrow
6+
none => ()
7+
}
8+
}
9+
10+
fn match_const_opt_by_const_ref(v: &const option<int>) {
11+
match *v {
12+
some(ref const i) => process(i), //~ ERROR illegal borrow unless pure
13+
//~^ NOTE impure due to
14+
none => ()
15+
}
16+
}
17+
18+
fn match_const_opt_by_imm_ref(v: &const option<int>) {
19+
match *v {
20+
some(ref i) => process(i), //~ ERROR illegal borrow unless pure
21+
//~^ NOTE impure due to
22+
none => ()
23+
}
24+
}
25+
26+
fn match_const_opt_by_value(v: &const option<int>) {
27+
match *v {
28+
some(copy i) => process(i),
29+
none => ()
30+
}
31+
}
32+
33+
fn main() {
34+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
fn destructure(x: option<int>) -> int {
2+
match x {
3+
none => 0,
4+
some(ref mut v) => *v //~ ERROR illegal borrow
5+
}
6+
}
7+
8+
fn main() {
9+
assert destructure(some(22)) == 22;
10+
}

0 commit comments

Comments
 (0)