Various regions fixes.

This commit is contained in:
Niko Matsakis 2012-04-21 10:04:58 -07:00
parent 0d3658bb43
commit 30d563839e
9 changed files with 146 additions and 90 deletions

View File

@ -6,10 +6,12 @@ my $indent = 0;
while (<>) {
if (/^rust: ">>/) {
$indent += 1;
} elsif (/^rust: "<</) {
$indent -= 1;
}
printf "%03d %s%s", $indent, (" " x $indent), $_;
if (/^rust: "<</) {
$indent -= 1;
}
}

View File

@ -92,21 +92,19 @@ fn compare_tys(tcx: ty::ctxt, a: ty::t, b: ty::t) -> ures {
mk_eqty(infcx, a, b)
}
// Resolves one level of type structure but not any type variables
// that may be nested within.
fn resolve_shallow(cx: infer_ctxt, a: ty::t) -> fres<ty::t> {
resolver(cx, false, false).resolve(a)
// See comment on the type `resolve_state` below
fn resolve_shallow(cx: infer_ctxt, a: ty::t,
force_vars: bool) -> fres<ty::t> {
resolver(cx, false, force_vars).resolve(a)
}
// see resolve_deep()
// See comment on the type `resolve_state` below
fn resolve_deep_var(cx: infer_ctxt, vid: ty_vid,
force_vars: bool) -> fres<ty::t> {
resolver(cx, true, force_vars).resolve(ty::mk_var(cx.tcx, vid))
}
// Resolves all levels of type structure. If `force_vars` is true,
// then we will resolve unconstrained type/region variables to
// something arbitrary. Otherwise, we preserve them as variables.
// See comment on the type `resolve_state` below
fn resolve_deep(cx: infer_ctxt, a: ty::t, force_vars: bool) -> fres<ty::t> {
resolver(cx, true, force_vars).resolve(a)
}
@ -556,8 +554,12 @@ impl unify_methods for infer_ctxt {
}
fn eq_regions(a: ty::region, b: ty::region) -> ures {
self.sub_regions(a, b).then {||
self.sub_regions(b, a)
#debug["eq_regions(%s, %s)",
a.to_str(self), b.to_str(self)];
indent {||
self.sub_regions(a, b).then {||
self.sub_regions(b, a)
}
}
}
}
@ -599,16 +601,20 @@ impl methods for resolve_state {
fn resolve(typ: ty::t) -> fres<ty::t> {
self.err = none;
#debug["Resolving %s (deep=%b, force_vars=%b)",
ty_to_str(self.infcx.tcx, typ),
self.deep,
self.force_vars];
// n.b. This is a hokey mess because the current fold doesn't
// allow us to pass back errors in any useful way.
assert vec::is_empty(self.v_seen) && vec::is_empty(self.r_seen);
let rty = self.resolve1(typ);
let rty = indent {|| self.resolve1(typ) };
assert vec::is_empty(self.v_seen) && vec::is_empty(self.r_seen);
alt self.err {
none {
#debug["Resolved %s to %s (deep=%b, force_vars=%b)",
ty_to_str(self.infcx.tcx, typ),
#debug["Resolved to %s (deep=%b, force_vars=%b)",
ty_to_str(self.infcx.tcx, rty),
self.deep,
self.force_vars];
@ -619,25 +625,32 @@ impl methods for resolve_state {
}
fn resolve1(typ: ty::t) -> ty::t {
let tb = ty::get(typ);
alt tb.struct {
ty::ty_var(vid) { self.resolve_ty_var(vid) }
_ if !tb.has_regions && !self.deep { typ }
_ {
ty::fold_regions_and_ty(
self.infcx.tcx, typ,
{ |r| self.resolve_region(r) },
{ |t| self.resolve_if_deep(t) },
{ |t| self.resolve_if_deep(t) })
}
}
#debug("Resolve1(%s)", typ.to_str(self.infcx));
indent(fn&() -> ty::t {
if !ty::get(typ).has_vars { ret typ; }
let tb = ty::get(typ);
alt tb.struct {
ty::ty_var(vid) { self.resolve_ty_var(vid) }
_ if !tb.has_regions && !self.deep { typ }
_ {
ty::fold_regions_and_ty(
self.infcx.tcx, typ,
{ |r| self.resolve_region(r) },
{ |t| self.resolve_if_deep(t) },
{ |t| self.resolve_if_deep(t) })
}
}
})
}
fn resolve_if_deep(typ: ty::t) -> ty::t {
#debug("Resolve_if_deep(%s)", typ.to_str(self.infcx));
if !self.deep {typ} else {self.resolve1(typ)}
}
fn resolve_region(orig: ty::region) -> ty::region {
#debug("Resolve_region(%s)", orig.to_str(self.infcx));
alt orig {
ty::re_var(rid) { self.resolve_region_var(rid) }
_ { orig }
@ -650,16 +663,15 @@ impl methods for resolve_state {
ret ty::re_var(rid);
} else {
vec::push(self.r_seen, rid);
let r = self.resolve_var(
self.infcx.rb,
{|_t| false },
rid,
{||
if self.force_vars {ty::re_static}
else {ty::re_var(rid)}
});
let {root:_, bounds} = self.infcx.get(self.infcx.rb, rid);
let r1 = alt bounds {
{ ub:_, lb:some(t) } { self.resolve_region(t) }
{ ub:some(t), lb:_ } { self.resolve_region(t) }
{ ub:none, lb:none } if self.force_vars { ty::re_static }
{ ub:none, lb:none } { ty::re_var(rid) }
};
vec::pop(self.r_seen);
ret r;
ret r1;
}
}
@ -670,43 +682,25 @@ impl methods for resolve_state {
} else {
vec::push(self.v_seen, vid);
let tcx = self.infcx.tcx;
let t0 = self.resolve_var(
self.infcx.vb,
{|t| type_is_bot(t) },
vid,
{||
if self.force_vars {ty::mk_bot(tcx)}
else {ty::mk_var(tcx, vid)}
});
let t1 = self.resolve1(t0);
// Nonobvious: prefer the most specific type
// (i.e., the lower bound) to the more general
// one. More general types in Rust (e.g., fn())
// tend to carry more restrictions or higher
// perf. penalties, so it pays to know more.
let {root:_, bounds} = self.infcx.get(self.infcx.vb, vid);
let t1 = alt bounds {
{ ub:_, lb:some(t) } if !type_is_bot(t) { self.resolve1(t) }
{ ub:some(t), lb:_ } { self.resolve1(t) }
{ ub:_, lb:some(t) } { self.resolve1(t) }
{ ub:none, lb:none } if self.force_vars { ty::mk_bot(tcx) }
{ ub:none, lb:none } { ty::mk_var(tcx, vid) }
};
vec::pop(self.v_seen);
ret t1;
}
}
fn resolve_var<V: copy vid, T:copy to_str>(
vb: vals_and_bindings<V, T>, bot_guard: fn(T)->bool,
vid: V, unbound: fn() -> T) -> T {
let {root:_, bounds} = self.infcx.get(vb, vid);
#debug["resolve_var(%s) bounds=%s",
vid.to_str(),
bounds.to_str(self.infcx)];
// Nonobvious: prefer the most specific type
// (i.e., the lower bound) to the more general
// one. More general types in Rust (e.g., fn())
// tend to carry more restrictions or higher
// perf. penalties, so it pays to know more.
alt bounds {
{ ub:_, lb:some(t) } if !bot_guard(t) { t }
{ ub:some(t), lb:_ } { t }
{ ub:_, lb:some(t) } { t }
{ ub:none, lb:none } { unbound() }
}
}
}
// ______________________________________________________________________
@ -958,8 +952,9 @@ fn super_substs<C:combine>(
ok(none)
}
(some(a), some(b)) {
infcx.eq_regions(a, b);
ok(some(a))
infcx.eq_regions(a, b).then {||
ok(some(a))
}
}
(_, _) {
// If these two substitutions are for the same type (and

View File

@ -483,12 +483,26 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t {
has_vars |= t.has_vars;
has_regions |= t.has_regions;
}
fn derive_rflags(&has_vars: bool, &has_regions: bool, r: region) {
has_regions = true;
alt r {
ty::re_var(_) { has_vars = true; }
_ { }
}
}
fn derive_sflags(&has_params: bool, &has_vars: bool, &has_regions: bool,
substs: substs) {
for substs.tps.each {|tt|
derive_flags(has_params, has_vars, has_regions, tt);
}
substs.self_r.iter { |r| derive_rflags(has_vars, has_regions, r) }
}
alt st {
ty_estr(vstore_slice(_)) {
has_regions = true;
ty_estr(vstore_slice(r)) {
derive_rflags(has_vars, has_regions, r);
}
ty_evec(mt, vstore_slice(_)) {
has_regions = true;
ty_evec(mt, vstore_slice(r)) {
derive_rflags(has_vars, has_regions, r);
derive_flags(has_params, has_vars, has_regions, mt.ty);
}
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
@ -497,10 +511,7 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t {
ty_param(_, _) { has_params = true; }
ty_var(_) | ty_self(_) { has_vars = true; }
ty_enum(_, substs) | ty_class(_, substs) {
for substs.tps.each {|tt|
derive_flags(has_params, has_vars, has_regions, tt);
}
substs.self_r.iter { |_i| has_regions = true; }
derive_sflags(has_params, has_vars, has_regions, substs);
}
ty_iface(_, tys) {
for tys.each {|tt|
@ -511,11 +522,7 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t {
derive_flags(has_params, has_vars, has_regions, m.ty);
}
ty_rptr(r, m) {
alt r {
ty::re_var(_) { has_vars = true; }
_ { }
}
has_regions = true;
derive_rflags(has_vars, has_regions, r);
derive_flags(has_params, has_vars, has_regions, m.ty);
}
ty_rec(flds) {
@ -535,9 +542,7 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t {
}
ty_res(_, tt, substs) {
derive_flags(has_params, has_vars, has_regions, tt);
for substs.tps.each {|tt|
derive_flags(has_params, has_vars, has_regions, tt);
}
derive_sflags(has_params, has_vars, has_regions, substs);
}
ty_constr(tt, _) {
derive_flags(has_params, has_vars, has_regions, tt);
@ -933,10 +938,11 @@ fn subst(cx: ctxt,
substs: substs,
typ: t) -> t {
if substs_is_noop(substs) { ret typ; }
#debug["subst(substs=%s, typ=%s)",
substs_to_str(cx, substs),
ty_to_str(cx, typ)];
if substs_is_noop(substs) { ret typ; }
let r = do_subst(cx, substs, typ);
#debug[" r = %s", ty_to_str(cx, r)];
ret r;

View File

@ -258,7 +258,7 @@ fn instantiate_path(fcx: @fn_ctxt,
// Type tests
fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
alt infer::resolve_shallow(fcx.infcx, tp) {
alt infer::resolve_shallow(fcx.infcx, tp, true) {
// note: the bot type doesn't count as resolved; it's what we use when
// there is no information about a variable.
result::ok(t_s) if !ty::type_is_bot(t_s) { ret t_s; }
@ -1348,7 +1348,7 @@ mod collect {
constraints: []})
};
let tpt = {bounds: ty_param_bounds(ccx, ty_params),
rp: ast::rp_none,
rp: rp,
ty: result_ty};
tcx.tcache.insert(local_def(variant.node.id), tpt);
write_ty_to_tcx(tcx, variant.node.id, result_ty);

View File

@ -0,0 +1,11 @@
enum ast/& {
num(uint),
add(&ast, &ast)
}
fn mk_add_bad1(x: &a.ast, y: &b.ast) -> ast/&a {
add(x, y) //! ERROR mismatched types: expected `&a.ast/&a` but found `&b.ast/&b`
}
fn main() {
}

View File

@ -0,0 +1,11 @@
enum ast/& {
num(uint),
add(&ast, &ast)
}
fn mk_add_bad2(x: &a.ast, y: &a.ast, z: &ast) -> ast {
add(x, y) //! ERROR mismatched types: expected `ast/&` but found `ast/&a`
}
fn main() {
}

View File

@ -0,0 +1,11 @@
enum ast/& {
num(uint),
add(&ast, &ast)
}
fn mk_add_ok(x: &ast, y: &ast) -> ast {
add(x, y)
}
fn main() {
}

View File

@ -0,0 +1,11 @@
enum ast/& {
num(uint),
add(&ast, &ast)
}
fn mk_add_ok(x: &a.ast, y: &a.ast, z: &ast) -> ast/&a {
add(x, y)
}
fn main() {
}

View File

@ -0,0 +1,9 @@
enum roption/& {
a, b(&uint)
}
fn mk(cond: bool, ptr: &uint) -> roption {
if cond {a} else {b(ptr)}
}
fn main() {}