repair LUB/GLB of free/scope regions, and enable test

This commit is contained in:
Niko Matsakis 2012-04-17 08:40:06 -07:00
parent 58f8cb343d
commit 6b549f9f14
3 changed files with 74 additions and 41 deletions

View File

@ -1373,23 +1373,28 @@ impl of combine for lub {
ok(ty::re_static) // nothing lives longer than static
}
(ty::re_var(a_id), ty::re_var(b_id)) {
lattice_vars(self, self.infcx().rb,
a, a_id, b_id,
{|x, y| self.regions(x, y) })
(ty::re_var(_), _) | (_, ty::re_var(_)) {
lattice_rvars(self, a, b)
}
(ty::re_var(v_id), r) | (r, ty::re_var(v_id)) {
lattice_var_t(self, self.infcx().rb,
v_id, r,
{|x, y| self.regions(x, y) })
}
(f @ ty::re_free(f_id, f_br), ty::re_scope(s_id)) |
(ty::re_scope(s_id), f @ ty::re_free(f_id, f_br)) {
// for LUB, the scope is within the function and the free
// region is always a parameter to the method.
ok(f) // NDM--not so for nested functions
(f @ ty::re_free(f_id, _), ty::re_scope(s_id)) |
(ty::re_scope(s_id), f @ ty::re_free(f_id, _)) {
// For LUB, generally the scope is within the fn and
// the free region is a parameter to the fn. In that case,
// the free region will always live as long as the fn,
// which is longer than the scope.
//
// However, with nested fns, it can happen that the
// scope surrounds the fn itself. In that case, we do
// not know which will live longer---it depends on the
// value provided for the free region in any given
// call. And so we must just back off to re_static as
// the LUB.
let rm = self.infcx().tcx.region_map;
alt region::nearest_common_ancestor(rm, f_id, s_id) {
some(r_id) if r_id == f_id { ok(f) }
_ { ok(ty::re_static) }
}
}
(ty::re_scope(a_id), ty::re_scope(b_id)) {
@ -1399,7 +1404,7 @@ impl of combine for lub {
let rm = self.infcx().tcx.region_map;
alt region::nearest_common_ancestor(rm, a_id, b_id) {
some(r_id) { ok(ty::re_scope(r_id)) }
_ { err(ty::terr_regions_differ(b, a)) }
_ { ok(ty::re_static) }
}
}
@ -1414,7 +1419,7 @@ impl of combine for lub {
if a == b {
ok(a)
} else {
err(ty::terr_regions_differ(b, a))
ok(ty::re_static)
}
}
}
@ -1551,24 +1556,26 @@ impl of combine for glb {
ok(r)
}
(ty::re_var(a_id), ty::re_var(b_id)) {
lattice_vars(self, self.infcx().rb,
a, a_id, b_id,
{|x, y| self.regions(x, y) })
(ty::re_var(_), _) | (_, ty::re_var(_)) {
lattice_rvars(self, a, b)
}
(ty::re_var(v_id), r) | (r, ty::re_var(v_id)) {
lattice_var_t(self, self.infcx().rb,
v_id, r,
{|x, y| self.regions(x, y) })
}
(f @ ty::re_free(f_id, f_br), ty::re_scope(s_id)) |
(ty::re_scope(s_id), f @ ty::re_free(f_id, f_br)) {
// for GLB, the scope is within the function and the free
// region is always a parameter to the method. So the GLB
// must be the scope.
ok(b) // NDM--not so for nested functions
(ty::re_free(f_id, _), s @ ty::re_scope(s_id)) |
(s @ ty::re_scope(s_id), ty::re_free(f_id, _)) {
// For GLB, generally the scope is within the fn and
// the free region is a parameter to the fn. In that case,
// the scope is always shorter than the free region.
//
// However, with nested fns, it can happen that the
// scope surrounds the fn itself. In that case, we do
// not know which will live longer---it depends on the
// value provided for the free region in any given
// call. And so we cannot give a GLB.
let rm = self.infcx().tcx.region_map;
alt region::nearest_common_ancestor(rm, f_id, s_id) {
some(r_id) if r_id == f_id { ok(s) }
_ { err(ty::terr_regions_differ(b, a)) }
}
}
(ty::re_scope(a_id), ty::re_scope(b_id)) {
@ -1704,6 +1711,34 @@ fn lattice_tys<L:lattice_ops combine>(
}
}
// Pull out some common code from LUB/GLB for handling region vars:
fn lattice_rvars<L:lattice_ops combine>(
self: L, a: ty::region, b: ty::region) -> cres<ty::region> {
alt (a, b) {
(ty::re_var(a_id), ty::re_var(b_id)) {
lattice_vars(self, self.infcx().rb,
a, a_id, b_id,
{|x, y| self.regions(x, y) })
}
(ty::re_var(v_id), r) | (r, ty::re_var(v_id)) {
lattice_var_t(self, self.infcx().rb,
v_id, r,
{|x, y| self.regions(x, y) })
}
_ {
self.infcx().tcx.sess.bug(
#fmt["%s: lattice_rvars invoked with a=%s and b=%s, \
neither of which are region variables",
self.tag(),
a.to_str(self.infcx()),
b.to_str(self.infcx())]);
}
}
}
fn lattice_vars<V:copy vid, T:copy to_str st, L:lattice_ops combine>(
self: L, vb: vals_and_bindings<V, T>,
a_t: T, a_vid: V, b_vid: V,

View File

@ -2078,8 +2078,8 @@ fn type_err_to_str(cx: ctxt, err: type_err) -> str {
ty_constr_to_str(a_constr);
}
terr_regions_differ(subregion, superregion) {
ret #fmt("references with lifetime %s do not outlive references with \
lifetime %s",
ret #fmt("references with lifetime %s do not necessarily \
outlive references with lifetime %s",
region_to_str(cx, subregion),
region_to_str(cx, superregion));
}

View File

@ -1,5 +1,3 @@
// xfail-test
fn ignore<T>(t: T) {}
fn nested(x: &x.int) {
@ -9,13 +7,13 @@ fn nested(x: &x.int) {
ignore(fn&(z: &z.int) {
ay = x;
ay = &y;
ay = z; //! ERROR foo
ay = z; //! ERROR references with lifetime
});
ignore(fn&(z: &z.int) -> &z.int {
if false { ret x; } //! ERROR bar
if false { ret &y; } //! ERROR bar
if false { ret ay; } //! ERROR bar
if false { ret x; } //! ERROR references with lifetime
if false { ret &y; } //! ERROR references with lifetime
if false { ret ay; } //! ERROR references with lifetime
ret z;
});
}