diff --git a/src/etc/indenter b/src/etc/indenter index 49fd73fcf72..f2e41da9b4e 100755 --- a/src/etc/indenter +++ b/src/etc/indenter @@ -6,10 +6,12 @@ my $indent = 0; while (<>) { if (/^rust: ">>/) { $indent += 1; - } elsif (/^rust: "< 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 { - 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 { + 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 { 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 { 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 { 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( - vb: vals_and_bindings, 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( 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 diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 107ea65e1d9..9b25b057c3f 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -483,12 +483,26 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option) -> 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) -> 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) -> 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) -> 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; diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 3cfcb73e9ca..d9324a74d7b 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -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); diff --git a/src/test/compile-fail/regions-creating-enums3.rs b/src/test/compile-fail/regions-creating-enums3.rs new file mode 100644 index 00000000000..d650441aab7 --- /dev/null +++ b/src/test/compile-fail/regions-creating-enums3.rs @@ -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() { +} \ No newline at end of file diff --git a/src/test/compile-fail/regions-creating-enums4.rs b/src/test/compile-fail/regions-creating-enums4.rs new file mode 100644 index 00000000000..f80334d3fea --- /dev/null +++ b/src/test/compile-fail/regions-creating-enums4.rs @@ -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() { +} \ No newline at end of file diff --git a/src/test/run-pass/regions-creating-enums2.rs b/src/test/run-pass/regions-creating-enums2.rs new file mode 100644 index 00000000000..27559ea8942 --- /dev/null +++ b/src/test/run-pass/regions-creating-enums2.rs @@ -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() { +} \ No newline at end of file diff --git a/src/test/run-pass/regions-creating-enums5.rs b/src/test/run-pass/regions-creating-enums5.rs new file mode 100644 index 00000000000..a7982cb9374 --- /dev/null +++ b/src/test/run-pass/regions-creating-enums5.rs @@ -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() { +} \ No newline at end of file diff --git a/src/test/run-pass/regions-nullary-variant.rs b/src/test/run-pass/regions-nullary-variant.rs new file mode 100644 index 00000000000..ad08ec1f67b --- /dev/null +++ b/src/test/run-pass/regions-nullary-variant.rs @@ -0,0 +1,9 @@ +enum roption/& { + a, b(&uint) +} + +fn mk(cond: bool, ptr: &uint) -> roption { + if cond {a} else {b(ptr)} +} + +fn main() {} \ No newline at end of file