Skip to content

Commit 3ef7ff8

Browse files
committed
infer the scope of borrows
1 parent 41a21f0 commit 3ef7ff8

16 files changed

+375
-200
lines changed

src/rustc/middle/typeck/check.rs

Lines changed: 98 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,7 @@ import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope};
7474
import rscope::{in_binding_rscope, region_scope, type_rscope};
7575
import syntax::ast::ty_i;
7676
import typeck::infer::{unify_methods}; // infcx.set()
77-
import typeck::infer::{force_level, force_none, force_ty_vars_only,
78-
force_all};
77+
import typeck::infer::{resolve_type, force_tvar};
7978

8079
type fn_ctxt =
8180
// var_bindings, locals and next_var_id are shared
@@ -89,7 +88,22 @@ type fn_ctxt =
8988
infcx: infer::infer_ctxt,
9089
locals: hashmap<ast::node_id, tv_vid>,
9190

92-
mut blocks: ~[ast::node_id], // stack of blocks in scope, may be empty
91+
// Sometimes we generate region pointers where the precise region
92+
// to use is not known. For example, an expression like `&x.f`
93+
// where `x` is of type `@T`: in this case, we will be rooting
94+
// `x` onto the stack frame, and we could choose to root it until
95+
// the end of (almost) any enclosing block or expression. We
96+
// want to pick the narrowest block that encompasses all uses.
97+
//
98+
// What we do in such cases is to generate a region variable and
99+
// assign it the following two fields as bounds. The lower bound
100+
// is always the innermost enclosing expression. The upper bound
101+
// is the outermost enclosing expression that we could legally
102+
// use. In practice, this is the innermost loop or function
103+
// body.
104+
mut region_lb: ast::node_id,
105+
mut region_ub: ast::node_id,
106+
93107
in_scope_regions: isr_alist,
94108

95109
node_types: smallintmap::smallintmap<ty::t>,
@@ -98,7 +112,8 @@ type fn_ctxt =
98112
ccx: @crate_ctxt};
99113

100114
// Used by check_const and check_enum_variants
101-
fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t) -> @fn_ctxt {
115+
fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t,
116+
region_bnd: ast::node_id) -> @fn_ctxt {
102117
// It's kind of a kludge to manufacture a fake function context
103118
// and statement context, but we might as well do write the code only once
104119
@{self_ty: none,
@@ -107,7 +122,8 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t) -> @fn_ctxt {
107122
purity: ast::pure_fn,
108123
infcx: infer::new_infer_ctxt(ccx.tcx),
109124
locals: int_hash(),
110-
mut blocks: ~[],
125+
mut region_lb: region_bnd,
126+
mut region_ub: region_bnd,
111127
in_scope_regions: @nil,
112128
node_types: smallintmap::mk(),
113129
node_type_substs: map::int_hash(),
@@ -217,7 +233,8 @@ fn check_fn(ccx: @crate_ctxt,
217233
purity: purity,
218234
infcx: infcx,
219235
locals: locals,
220-
mut blocks: ~[],
236+
mut region_lb: body.node.id,
237+
mut region_ub: body.node.id,
221238
in_scope_regions: isr,
222239
node_types: node_types,
223240
node_type_substs: node_type_substs,
@@ -307,9 +324,12 @@ fn check_fn(ccx: @crate_ctxt,
307324
};
308325

309326
let visit_block = fn@(b: ast::blk, &&e: (), v: visit::vt<()>) {
310-
vec::push(fcx.blocks, b.node.id);
311-
visit::visit_block(b, e, v);
312-
vec::pop(fcx.blocks);
327+
// non-obvious: the `blk` variable maps to region lb, so
328+
// we have to keep this up-to-date. This
329+
// is... unfortunate. It'd be nice to not need this.
330+
do fcx.with_region_lb(b.node.id) {
331+
visit::visit_block(b, e, v);
332+
}
313333
};
314334

315335
// Don't descend into fns and items
@@ -430,7 +450,7 @@ impl of ast_conv for @fn_ctxt {
430450

431451
impl of region_scope for @fn_ctxt {
432452
fn anon_region() -> result<ty::region, ~str> {
433-
result::ok(self.infcx.next_region_var())
453+
result::ok(self.infcx.next_region_var_nb())
434454
}
435455
fn named_region(id: ast::ident) -> result<ty::region, ~str> {
436456
do empty_rscope.named_region(id).chain_err |_e| {
@@ -448,10 +468,7 @@ impl of region_scope for @fn_ctxt {
448468
impl methods for @fn_ctxt {
449469
fn tag() -> ~str { #fmt["%x", ptr::addr_of(*self) as uint] }
450470
fn block_region() -> result<ty::region, ~str> {
451-
alt vec::last_opt(self.blocks) {
452-
some(bid) { result::ok(ty::re_scope(bid)) }
453-
none { result::err(~"no block is in scope here") }
454-
}
471+
result::ok(ty::re_scope(self.region_lb))
455472
}
456473
#[inline(always)]
457474
fn write_ty(node_id: ast::node_id, ty: ty::t) {
@@ -534,15 +551,17 @@ impl methods for @fn_ctxt {
534551
infer::can_mk_subty(self.infcx, sub, sup)
535552
}
536553

537-
fn mk_assignty(expr: @ast::expr, borrow_scope: ast::node_id,
554+
fn mk_assignty(expr: @ast::expr, borrow_lb: ast::node_id,
538555
sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
539-
let anmnt = {expr_id: expr.id, borrow_scope: borrow_scope};
556+
let anmnt = {expr_id: expr.id, borrow_lb: borrow_lb,
557+
borrow_ub: self.region_ub};
540558
infer::mk_assignty(self.infcx, anmnt, sub, sup)
541559
}
542560

543-
fn can_mk_assignty(expr: @ast::expr, borrow_scope: ast::node_id,
561+
fn can_mk_assignty(expr: @ast::expr, borrow_lb: ast::node_id,
544562
sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
545-
let anmnt = {expr_id: expr.id, borrow_scope: borrow_scope};
563+
let anmnt = {expr_id: expr.id, borrow_lb: borrow_lb,
564+
borrow_ub: self.region_ub};
546565
infer::can_mk_assignty(self.infcx, anmnt, sub, sup)
547566
}
548567

@@ -564,6 +583,20 @@ impl methods for @fn_ctxt {
564583
}
565584
}
566585
}
586+
fn with_region_lb<R>(lb: ast::node_id, f: fn() -> R) -> R {
587+
let old_region_lb = self.region_lb;
588+
self.region_lb = lb;
589+
let v <- f();
590+
self.region_lb = old_region_lb;
591+
ret v;
592+
}
593+
fn with_region_ub<R>(ub: ast::node_id, f: fn() -> R) -> R {
594+
let old_region_ub = self.region_ub;
595+
self.region_ub = ub;
596+
let v <- f();
597+
self.region_ub = old_region_ub;
598+
ret v;
599+
}
567600
}
568601

569602
fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> ty::t {
@@ -682,7 +715,7 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty {
682715
raw_ty: ity.ty}
683716
};
684717

685-
let self_r = if rp {some(fcx.infcx.next_region_var())} else {none};
718+
let self_r = if rp {some(fcx.infcx.next_region_var_nb())} else {none};
686719
let tps = fcx.infcx.next_ty_vars(n_tps);
687720

688721
let substs = {self_r: self_r, self_ty: none, tps: tps};
@@ -733,7 +766,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
733766
sty @ ty::ty_fn(fn_ty) {
734767
replace_bound_regions_in_fn_ty(
735768
fcx.ccx.tcx, @nil, none, fn_ty,
736-
|_br| fcx.infcx.next_region_var()).fn_ty
769+
|_br| fcx.infcx.next_region_var_nb()).fn_ty
737770
}
738771
sty {
739772
// I would like to make this span_err, but it's
@@ -1017,7 +1050,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
10171050
-> option<O> {
10181051
alt expected {
10191052
some(t) {
1020-
alt infer::resolve_shallow(fcx.infcx, t, force_none) {
1053+
alt resolve_type(fcx.infcx, t, force_tvar) {
10211054
result::ok(t) { unpack(ty::get(t).struct) }
10221055
_ { none }
10231056
}
@@ -1119,9 +1152,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
11191152

11201153
// this will be the call or block that immediately
11211154
// encloses the method call
1122-
let borrow_scope = fcx.tcx().region_map.get(expr.id);
1155+
let borrow_lb = fcx.tcx().region_map.get(expr.id);
11231156

1124-
let lkup = method::lookup(fcx, expr, base, borrow_scope,
1157+
let lkup = method::lookup(fcx, expr, base, borrow_lb,
11251158
expr.id, field, expr_t, tps,
11261159
is_self_ref);
11271160
alt lkup.method() {
@@ -1364,13 +1397,17 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
13641397
}
13651398
ast::expr_while(cond, body) {
13661399
bot = check_expr_with(fcx, cond, ty::mk_bool(tcx));
1367-
check_block_no_value(fcx, body);
1400+
do fcx.with_region_ub(body.node.id) {
1401+
check_block_no_value(fcx, body);
1402+
}
13681403
fcx.write_ty(id, ty::mk_nil(tcx));
13691404
}
13701405
ast::expr_loop(body) {
1371-
check_block_no_value(fcx, body);
1372-
fcx.write_ty(id, ty::mk_nil(tcx));
1373-
bot = !may_break(body);
1406+
do fcx.with_region_ub(body.node.id) {
1407+
check_block_no_value(fcx, body);
1408+
}
1409+
fcx.write_ty(id, ty::mk_nil(tcx));
1410+
bot = !may_break(body);
13741411
}
13751412
ast::expr_alt(discrim, arms, _) {
13761413
bot = alt::check_alt(fcx, expr, discrim, arms);
@@ -1754,44 +1791,44 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool {
17541791
ast::unsafe_blk { @{purity: ast::unsafe_fn with *fcx0} }
17551792
ast::default_blk { fcx0 }
17561793
};
1757-
vec::push(fcx.blocks, blk.node.id);
1758-
let mut bot = false;
1759-
let mut warned = false;
1760-
for blk.node.stmts.each |s| {
1761-
if bot && !warned &&
1762-
alt s.node {
1763-
ast::stmt_decl(@{node: ast::decl_local(_), _}, _) |
1764-
ast::stmt_expr(_, _) | ast::stmt_semi(_, _) {
1765-
true
1766-
}
1767-
_ { false }
1768-
} {
1769-
fcx.ccx.tcx.sess.span_warn(s.span, ~"unreachable statement");
1770-
warned = true;
1794+
do fcx.with_region_lb(blk.node.id) {
1795+
let mut bot = false;
1796+
let mut warned = false;
1797+
for blk.node.stmts.each |s| {
1798+
if bot && !warned &&
1799+
alt s.node {
1800+
ast::stmt_decl(@{node: ast::decl_local(_), _}, _) |
1801+
ast::stmt_expr(_, _) | ast::stmt_semi(_, _) {
1802+
true
1803+
}
1804+
_ { false }
1805+
} {
1806+
fcx.ccx.tcx.sess.span_warn(s.span, ~"unreachable statement");
1807+
warned = true;
1808+
}
1809+
bot |= check_stmt(fcx, s);
17711810
}
1772-
bot |= check_stmt(fcx, s);
1773-
}
1774-
alt blk.node.expr {
1775-
none { fcx.write_nil(blk.node.id); }
1776-
some(e) {
1777-
if bot && !warned {
1778-
fcx.ccx.tcx.sess.span_warn(e.span, ~"unreachable expression");
1811+
alt blk.node.expr {
1812+
none { fcx.write_nil(blk.node.id); }
1813+
some(e) {
1814+
if bot && !warned {
1815+
fcx.ccx.tcx.sess.span_warn(e.span, ~"unreachable expression");
1816+
}
1817+
bot |= check_expr(fcx, e, none);
1818+
let ety = fcx.expr_ty(e);
1819+
fcx.write_ty(blk.node.id, ety);
1820+
}
17791821
}
1780-
bot |= check_expr(fcx, e, none);
1781-
let ety = fcx.expr_ty(e);
1782-
fcx.write_ty(blk.node.id, ety);
1783-
}
1784-
}
1785-
if bot {
1786-
fcx.write_bot(blk.node.id);
1822+
if bot {
1823+
fcx.write_bot(blk.node.id);
1824+
}
1825+
bot
17871826
}
1788-
vec::pop(fcx.blocks);
1789-
ret bot;
17901827
}
17911828

17921829
fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) {
17931830
let rty = ty::node_id_to_type(ccx.tcx, id);
1794-
let fcx = blank_fn_ctxt(ccx, rty);
1831+
let fcx = blank_fn_ctxt(ccx, rty, e.id);
17951832
check_expr(fcx, e, none);
17961833
let cty = fcx.expr_ty(e);
17971834
let declty = fcx.ccx.tcx.tcache.get(local_def(id)).ty;
@@ -1817,13 +1854,13 @@ fn check_enum_variants(ccx: @crate_ctxt,
18171854
vs: ~[ast::variant],
18181855
id: ast::node_id) {
18191856
let rty = ty::node_id_to_type(ccx.tcx, id);
1820-
let fcx = blank_fn_ctxt(ccx, rty);
18211857
let mut disr_vals: ~[int] = ~[];
18221858
let mut disr_val = 0;
18231859
let mut variants = ~[];
18241860
for vs.each |v| {
18251861
alt v.node.disr_expr {
18261862
some(e) {
1863+
let fcx = blank_fn_ctxt(ccx, rty, e.id);
18271864
check_expr(fcx, e, none);
18281865
let cty = fcx.expr_ty(e);
18291866
let declty = ty::mk_int(ccx.tcx);
@@ -2003,7 +2040,7 @@ fn instantiate_path(fcx: @fn_ctxt,
20032040
some(ast_region_to_region(fcx, fcx, sp, r))
20042041
}
20052042
none if tpt.rp => {
2006-
some(fcx.infcx.next_region_var())
2043+
some(fcx.infcx.next_region_var_nb())
20072044
}
20082045
none => {
20092046
none
@@ -2037,8 +2074,7 @@ fn instantiate_path(fcx: @fn_ctxt,
20372074
// Resolves `typ` by a single level if `typ` is a type variable. If no
20382075
// resolution is possible, then an error is reported.
20392076
fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
2040-
alt infer::resolve_shallow(fcx.infcx, tp,
2041-
force_ty_vars_only) {
2077+
alt infer::resolve_type(fcx.infcx, tp, force_tvar) {
20422078
result::ok(t_s) if !ty::type_is_var(t_s) { ret t_s; }
20432079
_ {
20442080
fcx.ccx.tcx.sess.span_fatal

src/rustc/middle/typeck/check/demand.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,10 @@ fn eqtype(fcx: @fn_ctxt, sp: span,
2626
}
2727

2828
// Checks that the type `actual` can be assigned to `expected`.
29-
fn assign(fcx: @fn_ctxt, sp: span, borrow_scope: ast::node_id,
29+
fn assign(fcx: @fn_ctxt, sp: span, borrow_lb: ast::node_id,
3030
expected: ty::t, expr: @ast::expr) {
3131
let expr_ty = fcx.expr_ty(expr);
32-
let anmnt = {expr_id: expr.id, borrow_scope: borrow_scope};
33-
alt infer::mk_assignty(fcx.infcx, anmnt, expr_ty, expected) {
32+
alt fcx.mk_assignty(expr, borrow_lb, expr_ty, expected) {
3433
result::ok(()) { /* ok */ }
3534
result::err(err) {
3635
fcx.report_mismatched_types(sp, expected, expr_ty, err);

src/rustc/middle/typeck/check/method.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class lookup {
1919
let fcx: @fn_ctxt;
2020
let expr: @ast::expr;
2121
let self_expr: @ast::expr;
22-
let borrow_scope: ast::node_id;
22+
let borrow_lb: ast::node_id;
2323
let node_id: ast::node_id;
2424
let m_name: ast::ident;
2525
let mut self_ty: ty::t;
@@ -32,7 +32,7 @@ class lookup {
3232
new(fcx: @fn_ctxt,
3333
expr: @ast::expr, //expr for a.b in a.b()
3434
self_expr: @ast::expr, //a in a.b(...)
35-
borrow_scope: ast::node_id, //scope to borrow the expr for
35+
borrow_lb: ast::node_id, //scope to borrow the expr for
3636
node_id: ast::node_id, //node id where to store type of fn
3737
m_name: ast::ident, //b in a.b(...)
3838
self_ty: ty::t, //type of a in a.b(...)
@@ -42,7 +42,7 @@ class lookup {
4242
self.fcx = fcx;
4343
self.expr = expr;
4444
self.self_expr = self_expr;
45-
self.borrow_scope = borrow_scope;
45+
self.borrow_lb = borrow_lb;
4646
self.node_id = node_id;
4747
self.m_name = m_name;
4848
self.self_ty = self_ty;
@@ -315,7 +315,7 @@ class lookup {
315315
// type assignability. Collect the matches.
316316
let matches = if use_assignability {
317317
self.fcx.can_mk_assignty(
318-
self.self_expr, self.borrow_scope,
318+
self.self_expr, self.borrow_lb,
319319
self.self_ty, impl_ty)
320320
} else {
321321
self.fcx.can_mk_subty(self.self_ty, impl_ty)
@@ -377,7 +377,7 @@ class lookup {
377377
// Make the actual receiver type (cand.self_ty) assignable to the
378378
// required receiver type (cand.rcvr_ty). If this method is not
379379
// from an impl, this'll basically be a no-nop.
380-
alt self.fcx.mk_assignty(self.self_expr, self.borrow_scope,
380+
alt self.fcx.mk_assignty(self.self_expr, self.borrow_lb,
381381
cand.self_ty, cand.rcvr_ty) {
382382
result::ok(_) {}
383383
result::err(_) {

0 commit comments

Comments
 (0)