Skip to content

Commit b7a741b

Browse files
committed
rustc: Combine and unify regions
1 parent 03086c5 commit b7a741b

File tree

2 files changed

+88
-37
lines changed

2 files changed

+88
-37
lines changed

src/rustc/middle/infer.rs

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -409,39 +409,9 @@ impl unify_methods for infer_ctxt {
409409
}
410410

411411
fn regions(a: ty::region, b: ty::region) -> ures {
412-
alt (a, b) {
413-
(ty::re_var(_), _) | (_, ty::re_var(_)) {
414-
self.uok() // FIXME: We need region variables!
415-
}
416-
(ty::re_inferred, _) | (_, ty::re_inferred) {
417-
fail "tried to unify inferred regions"
418-
}
419-
(ty::re_param(_), ty::re_param(_)) |
420-
(ty::re_self, ty::re_self) {
421-
if a == b {
422-
self.uok()
423-
} else {
424-
self.uerr(ty::terr_regions_differ(false, a, b))
425-
}
426-
}
427-
(ty::re_param(_), ty::re_block(_)) |
428-
(ty::re_self, ty::re_block(_)) {
429-
self.uok()
430-
}
431-
(ty::re_block(_), ty::re_param(_)) |
432-
(ty::re_block(_), ty::re_self) {
433-
self.uerr(ty::terr_regions_differ(false, a, b))
434-
}
435-
(ty::re_block(superblock), ty::re_block(subblock)) {
436-
// The region corresponding to an outer block is a subtype of the
437-
// region corresponding to an inner block.
438-
let rm = self.tcx.region_map;
439-
if region::scope_contains(rm, subblock, superblock) {
440-
self.uok()
441-
} else {
442-
self.uerr(ty::terr_regions_differ(false, a, b))
443-
}
444-
}
412+
alt combine_or_unify_regions(self.tcx, a, b, false) {
413+
ok(_) { self.uok() }
414+
err(e) { self.uerr(e) }
445415
}
446416
}
447417

@@ -1214,6 +1184,47 @@ fn c_tys<C:combine>(
12141184
}
12151185
}
12161186

1187+
fn combine_or_unify_regions(tcx: ty::ctxt,
1188+
a: ty::region,
1189+
b: ty::region,
1190+
contravariant_combine: bool) -> cres<ty::region> {
1191+
alt (a, b) {
1192+
(ty::re_var(_), _) | (_, ty::re_var(_)) {
1193+
ok(a) // FIXME: We need region variables!
1194+
}
1195+
(ty::re_inferred, _) | (_, ty::re_inferred) {
1196+
fail "tried to combine or unify inferred regions"
1197+
}
1198+
(ty::re_param(_), ty::re_param(_)) |
1199+
(ty::re_self, ty::re_self) {
1200+
if a == b {
1201+
ok(a)
1202+
} else {
1203+
err(ty::terr_regions_differ(false, a, b))
1204+
}
1205+
}
1206+
(ty::re_param(_), ty::re_block(_)) |
1207+
(ty::re_self, ty::re_block(_)) {
1208+
ok(a)
1209+
}
1210+
(ty::re_block(_), ty::re_param(_)) |
1211+
(ty::re_block(_), ty::re_self) {
1212+
err(ty::terr_regions_differ(false, a, b))
1213+
}
1214+
(ty::re_block(block_a), ty::re_block(block_b)) {
1215+
// The region corresponding to an outer block is a subtype of the
1216+
// region corresponding to an inner block.
1217+
let rm = tcx.region_map;
1218+
let nca_opt = region::nearest_common_ancestor(rm, block_a, block_b);
1219+
alt nca_opt {
1220+
some(nca) if nca == block_b { ok(a) }
1221+
some(nca) if contravariant_combine { ok(ty::re_block(nca)) }
1222+
_ { err(ty::terr_regions_differ(false, a, b)) }
1223+
}
1224+
}
1225+
}
1226+
}
1227+
12171228
impl of combine for lub {
12181229
fn infcx() -> infer_ctxt { *self }
12191230

@@ -1232,10 +1243,6 @@ impl of combine for lub {
12321243
ok(b)
12331244
}
12341245

1235-
fn c_regions(a: ty::region, _b: ty::region) -> cres<ty::region> {
1236-
ok(a) // FIXME
1237-
}
1238-
12391246
fn c_mts(a: ty::mt, b: ty::mt) -> cres<ty::mt> {
12401247
let tcx = self.infcx().tcx;
12411248

@@ -1302,6 +1309,10 @@ impl of combine for lub {
13021309
}
13031310
}
13041311
}
1312+
1313+
fn c_regions(a: ty::region, b: ty::region) -> cres<ty::region> {
1314+
ret combine_or_unify_regions(self.tcx, a, b, true);
1315+
}
13051316
}
13061317

13071318
impl of combine for glb {
@@ -1410,4 +1421,8 @@ impl of combine for glb {
14101421
}
14111422
}
14121423
}
1424+
1425+
fn c_regions(a: ty::region, b: ty::region) -> cres<ty::region> {
1426+
ret combine_or_unify_regions(self.tcx, a, b, false);
1427+
}
14131428
}

src/rustc/middle/region.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,42 @@ fn scope_contains(region_map: @region_map, superscope: ast::node_id,
8484
ret true;
8585
}
8686

87+
fn nearest_common_ancestor(region_map: @region_map, scope_a: ast::node_id,
88+
scope_b: ast::node_id) -> option<ast::node_id> {
89+
90+
fn ancestors_of(region_map: @region_map, scope: ast::node_id)
91+
-> [ast::node_id] {
92+
let mut result = [scope];
93+
let mut scope = scope;
94+
loop {
95+
alt region_map.parents.find(scope) {
96+
none { ret result; }
97+
some(superscope) {
98+
result += [superscope];
99+
scope = superscope;
100+
}
101+
}
102+
}
103+
}
104+
105+
if scope_a == scope_b { ret some(scope_a); }
106+
107+
let a_ancestors = ancestors_of(region_map, scope_a);
108+
let b_ancestors = ancestors_of(region_map, scope_b);
109+
let mut a_index = vec::len(a_ancestors) - 1u;
110+
let mut b_index = vec::len(b_ancestors) - 1u;
111+
while a_ancestors[a_index] == b_ancestors[b_index] {
112+
a_index -= 1u;
113+
b_index -= 1u;
114+
}
115+
116+
if a_index == vec::len(a_ancestors) {
117+
ret none;
118+
}
119+
120+
ret some(a_ancestors[a_index + 1u]);
121+
}
122+
87123
fn get_inferred_region(cx: ctxt, sp: syntax::codemap::span) -> ty::region {
88124
// We infer to the caller region if we're at item scope
89125
// and to the block region if we're at block scope.

0 commit comments

Comments
 (0)