rustc: Combine and unify regions

This commit is contained in:
Patrick Walton 2012-03-26 15:07:15 -07:00
parent 03086c5304
commit b7a741b5d0
2 changed files with 88 additions and 37 deletions

View File

@ -409,39 +409,9 @@ impl unify_methods for infer_ctxt {
}
fn regions(a: ty::region, b: ty::region) -> ures {
alt (a, b) {
(ty::re_var(_), _) | (_, ty::re_var(_)) {
self.uok() // FIXME: We need region variables!
}
(ty::re_inferred, _) | (_, ty::re_inferred) {
fail "tried to unify inferred regions"
}
(ty::re_param(_), ty::re_param(_)) |
(ty::re_self, ty::re_self) {
if a == b {
self.uok()
} else {
self.uerr(ty::terr_regions_differ(false, a, b))
}
}
(ty::re_param(_), ty::re_block(_)) |
(ty::re_self, ty::re_block(_)) {
self.uok()
}
(ty::re_block(_), ty::re_param(_)) |
(ty::re_block(_), ty::re_self) {
self.uerr(ty::terr_regions_differ(false, a, b))
}
(ty::re_block(superblock), ty::re_block(subblock)) {
// The region corresponding to an outer block is a subtype of the
// region corresponding to an inner block.
let rm = self.tcx.region_map;
if region::scope_contains(rm, subblock, superblock) {
self.uok()
} else {
self.uerr(ty::terr_regions_differ(false, a, b))
}
}
alt combine_or_unify_regions(self.tcx, a, b, false) {
ok(_) { self.uok() }
err(e) { self.uerr(e) }
}
}
@ -1214,6 +1184,47 @@ fn c_tys<C:combine>(
}
}
fn combine_or_unify_regions(tcx: ty::ctxt,
a: ty::region,
b: ty::region,
contravariant_combine: bool) -> cres<ty::region> {
alt (a, b) {
(ty::re_var(_), _) | (_, ty::re_var(_)) {
ok(a) // FIXME: We need region variables!
}
(ty::re_inferred, _) | (_, ty::re_inferred) {
fail "tried to combine or unify inferred regions"
}
(ty::re_param(_), ty::re_param(_)) |
(ty::re_self, ty::re_self) {
if a == b {
ok(a)
} else {
err(ty::terr_regions_differ(false, a, b))
}
}
(ty::re_param(_), ty::re_block(_)) |
(ty::re_self, ty::re_block(_)) {
ok(a)
}
(ty::re_block(_), ty::re_param(_)) |
(ty::re_block(_), ty::re_self) {
err(ty::terr_regions_differ(false, a, b))
}
(ty::re_block(block_a), ty::re_block(block_b)) {
// The region corresponding to an outer block is a subtype of the
// region corresponding to an inner block.
let rm = tcx.region_map;
let nca_opt = region::nearest_common_ancestor(rm, block_a, block_b);
alt nca_opt {
some(nca) if nca == block_b { ok(a) }
some(nca) if contravariant_combine { ok(ty::re_block(nca)) }
_ { err(ty::terr_regions_differ(false, a, b)) }
}
}
}
}
impl of combine for lub {
fn infcx() -> infer_ctxt { *self }
@ -1232,10 +1243,6 @@ impl of combine for lub {
ok(b)
}
fn c_regions(a: ty::region, _b: ty::region) -> cres<ty::region> {
ok(a) // FIXME
}
fn c_mts(a: ty::mt, b: ty::mt) -> cres<ty::mt> {
let tcx = self.infcx().tcx;
@ -1302,6 +1309,10 @@ impl of combine for lub {
}
}
}
fn c_regions(a: ty::region, b: ty::region) -> cres<ty::region> {
ret combine_or_unify_regions(self.tcx, a, b, true);
}
}
impl of combine for glb {
@ -1410,4 +1421,8 @@ impl of combine for glb {
}
}
}
fn c_regions(a: ty::region, b: ty::region) -> cres<ty::region> {
ret combine_or_unify_regions(self.tcx, a, b, false);
}
}

View File

@ -84,6 +84,42 @@ fn scope_contains(region_map: @region_map, superscope: ast::node_id,
ret true;
}
fn nearest_common_ancestor(region_map: @region_map, scope_a: ast::node_id,
scope_b: ast::node_id) -> option<ast::node_id> {
fn ancestors_of(region_map: @region_map, scope: ast::node_id)
-> [ast::node_id] {
let mut result = [scope];
let mut scope = scope;
loop {
alt region_map.parents.find(scope) {
none { ret result; }
some(superscope) {
result += [superscope];
scope = superscope;
}
}
}
}
if scope_a == scope_b { ret some(scope_a); }
let a_ancestors = ancestors_of(region_map, scope_a);
let b_ancestors = ancestors_of(region_map, scope_b);
let mut a_index = vec::len(a_ancestors) - 1u;
let mut b_index = vec::len(b_ancestors) - 1u;
while a_ancestors[a_index] == b_ancestors[b_index] {
a_index -= 1u;
b_index -= 1u;
}
if a_index == vec::len(a_ancestors) {
ret none;
}
ret some(a_ancestors[a_index + 1u]);
}
fn get_inferred_region(cx: ctxt, sp: syntax::codemap::span) -> ty::region {
// We infer to the caller region if we're at item scope
// and to the block region if we're at block scope.