Various regions fixes.
This commit is contained in:
parent
0d3658bb43
commit
30d563839e
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
11
src/test/compile-fail/regions-creating-enums3.rs
Normal file
11
src/test/compile-fail/regions-creating-enums3.rs
Normal 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() {
|
||||
}
|
11
src/test/compile-fail/regions-creating-enums4.rs
Normal file
11
src/test/compile-fail/regions-creating-enums4.rs
Normal 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() {
|
||||
}
|
11
src/test/run-pass/regions-creating-enums2.rs
Normal file
11
src/test/run-pass/regions-creating-enums2.rs
Normal 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() {
|
||||
}
|
11
src/test/run-pass/regions-creating-enums5.rs
Normal file
11
src/test/run-pass/regions-creating-enums5.rs
Normal 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() {
|
||||
}
|
9
src/test/run-pass/regions-nullary-variant.rs
Normal file
9
src/test/run-pass/regions-nullary-variant.rs
Normal 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() {}
|
Loading…
Reference in New Issue
Block a user