Skip to content

Commit 8462c6c

Browse files
committed
rustc: Generalize several parts of infer in preparation for using them for region bounds as well
1 parent 1d7d5c1 commit 8462c6c

File tree

1 file changed

+97
-94
lines changed

1 file changed

+97
-94
lines changed

src/rustc/middle/infer.rs

Lines changed: 97 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -16,53 +16,45 @@ export fixup_vars;
1616
export resolve_var;
1717
export compare_tys;
1818

19-
type bound = option<ty::t>;
19+
type bound<T:copy> = option<T>;
2020

21-
type bounds = {lb: bound, ub: bound};
21+
type bounds<T:copy> = {lb: bound<T>, ub: bound<T>};
2222

23-
enum var_value {
23+
enum var_value<T:copy> {
2424
redirect(uint),
25-
bounded(bounds)
25+
bounded(bounds<T>)
2626
}
2727

28-
type region_bound = option<ty::region>;
29-
30-
type region_bounds = {lb: region_bound, ub: region_bound};
31-
32-
enum region_value {
33-
rv_redirect(uint),
34-
rv_bounded(region_bounds)
35-
}
28+
type vals_and_bindings<T:copy> = {
29+
vals: smallintmap<var_value<T>>,
30+
mut bindings: [(uint, var_value<T>)]
31+
};
3632

3733
enum infer_ctxt = @{
3834
tcx: ty::ctxt,
39-
vals: smallintmap<var_value>,
40-
mut bindings: [(uint, var_value)],
41-
region_vals: smallintmap<region_value>,
42-
mut region_bindings: [(uint, region_value)]
35+
vb: vals_and_bindings<ty::t>,
36+
rb: vals_and_bindings<ty::region>,
4337
};
4438

4539
type ures = result::result<(), ty::type_err>;
4640
type fres<T> = result::result<T,int>;
4741

4842
fn new_infer_ctxt(tcx: ty::ctxt) -> infer_ctxt {
4943
infer_ctxt(@{tcx: tcx,
50-
vals: smallintmap::mk(),
51-
mut bindings: [],
52-
region_vals: smallintmap::mk(),
53-
mut region_bindings: []})
44+
vb: {vals: smallintmap::mk(), mut bindings: []},
45+
rb: {vals: smallintmap::mk(), mut bindings: []}})
5446
}
5547

5648
fn mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
5749
#debug[">> mk_subty(%s <: %s)", cx.ty_to_str(a), cx.ty_to_str(b)];
58-
cx.commit {||
50+
cx.commit(cx.vb) {||
5951
cx.tys(a, b)
6052
}
6153
}
6254

6355
fn mk_eqty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
6456
#debug["> mk_eqty(%s <: %s)", cx.ty_to_str(a), cx.ty_to_str(b)];
65-
cx.commit {||
57+
cx.commit(cx.vb) {||
6658
mk_subty(cx, a, b).then {||
6759
mk_subty(cx, b, a)
6860
}
@@ -72,7 +64,7 @@ fn mk_eqty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
7264
fn compare_tys(tcx: ty::ctxt, a: ty::t, b: ty::t) -> ures {
7365
let infcx = new_infer_ctxt(tcx);
7466
#debug["> compare_tys(%s == %s)", infcx.ty_to_str(a), infcx.ty_to_str(b)];
75-
infcx.commit {||
67+
infcx.commit(infcx.vb) {||
7668
mk_subty(infcx, a, b).then {||
7769
mk_subty(infcx, b, a)
7870
}
@@ -122,54 +114,63 @@ impl unify_methods for infer_ctxt {
122114
ty_to_str(self.tcx, t)
123115
}
124116

125-
fn bound_to_str(b: bound) -> str {
117+
fn ty_bound_to_str(b: bound<ty::t>) -> str {
126118
alt b {
127119
none { "none" }
128120
some(t) { self.ty_to_str(t) }
129121
}
130122
}
131123

132-
fn bounds_to_str(v: bounds) -> str {
124+
fn ty_bounds_to_str(v: bounds<ty::t>) -> str {
133125
#fmt["{%s <: X <: %s}",
134-
self.bound_to_str(v.lb),
135-
self.bound_to_str(v.ub)]
126+
self.ty_bound_to_str(v.lb),
127+
self.ty_bound_to_str(v.ub)]
136128
}
137129

138-
fn var_value_to_str(v: var_value) -> str {
130+
fn ty_var_value_to_str(v: var_value<ty::t>) -> str {
139131
alt v {
140132
redirect(v) { #fmt["redirect(%u)", v] }
141-
bounded(b) { self.bounds_to_str(b) }
133+
bounded(b) { self.ty_bounds_to_str(b) }
142134
}
143135
}
144136

145-
fn set(vid: uint, +new_v: var_value) {
146-
let old_v = self.vals.get(vid);
147-
vec::push(self.bindings, (vid, old_v));
137+
fn set<T:copy>(vb: vals_and_bindings<T>, vid: uint,
138+
+new_v: var_value<T>) {
148139

140+
let old_v = vb.vals.get(vid);
141+
vec::push(vb.bindings, (vid, old_v));
142+
vb.vals.insert(vid, new_v);
143+
}
144+
145+
fn set_ty(vid: uint, +new_v: var_value<ty::t>) {
146+
let old_v = self.vb.vals.get(vid);
147+
self.set(self.vb, vid, new_v);
149148
#debug["Updating variable <T%u> from %s to %s",
150149
vid,
151-
self.var_value_to_str(old_v),
152-
self.var_value_to_str(new_v)];
153-
154-
self.vals.insert(vid, new_v);
150+
self.ty_var_value_to_str(old_v),
151+
self.ty_var_value_to_str(new_v)];
155152
}
156153

157-
fn rollback_to(len: uint) {
158-
while self.bindings.len() != len {
159-
let (vid, old_v) = vec::pop(self.bindings);
160-
self.vals.insert(vid, old_v);
154+
fn rollback_to<T:copy>(vb: vals_and_bindings<T>, len: uint) {
155+
while vb.bindings.len() != len {
156+
let (vid, old_v) = vec::pop(vb.bindings);
157+
vb.vals.insert(vid, old_v);
161158
}
162159
}
163160

164-
fn commit<T:copy,E:copy>(f: fn() -> result<T,E>) -> result<T,E> {
165-
assert self.bindings.len() == 0u;
166-
let r = self.try(f);
167-
vec::clear(self.bindings);
161+
fn commit<T:copy,E:copy,U:copy>(vb: vals_and_bindings<U>,
162+
f: fn() -> result<T,E>) -> result<T,E> {
163+
164+
assert vb.bindings.len() == 0u;
165+
let r = self.try(vb, f);
166+
vec::clear(vb.bindings);
168167
ret r;
169168
}
170169

171-
fn try<T:copy,E:copy>(f: fn() -> result<T,E>) -> result<T,E> {
172-
let l = self.bindings.len();
170+
fn try<T:copy,E:copy,U:copy>(vb: vals_and_bindings<U>,
171+
f: fn() -> result<T,E>) -> result<T,E> {
172+
173+
let l = vb.bindings.len();
173174
#debug["try(l=%u)", l];
174175
let r = f();
175176
alt r {
@@ -179,17 +180,19 @@ impl unify_methods for infer_ctxt {
179180
ret r;
180181
}
181182

182-
fn get(vid: uint) -> {root: uint, bounds:bounds} {
183-
alt self.vals.find(vid) {
183+
fn get<T:copy>(vb: vals_and_bindings<T>, vid: uint)
184+
-> {root: uint, bounds:bounds<T>} {
185+
186+
alt vb.vals.find(vid) {
184187
none {
185188
let bnds = {lb: none, ub: none};
186-
self.vals.insert(vid, bounded(bnds));
189+
vb.vals.insert(vid, bounded(bnds));
187190
{root: vid, bounds: bnds}
188191
}
189192
some(redirect(vid)) {
190-
let {root, bounds} = self.get(vid);
193+
let {root, bounds} = self.get(vb, vid);
191194
if root != vid {
192-
self.vals.insert(vid, redirect(root));
195+
vb.vals.insert(vid, redirect(root));
193196
}
194197
{root: root, bounds: bounds}
195198
}
@@ -199,31 +202,21 @@ impl unify_methods for infer_ctxt {
199202
}
200203
}
201204

202-
// FIXME: See if we can't throw some polymorphism on this to make this
203-
// less of a straight copy of the above.
204-
fn get_region(rid: uint) -> {root: uint, bounds:region_bounds} {
205-
alt self.region_vals.find(rid) {
206-
none {
207-
let bnds = {lb: none, ub: none};
208-
self.region_vals.insert(rid, rv_bounded(bnds));
209-
{root: rid, bounds: bnds}
210-
}
211-
some(rv_redirect(rid)) {
212-
let {root, bounds} = self.get_region(rid);
213-
if root != rid {
214-
self.region_vals.insert(rid, rv_redirect(root));
215-
}
216-
{root: root, bounds: bounds}
217-
}
218-
some(rv_bounded(bounds)) {
219-
{root: rid, bounds: bounds}
220-
}
221-
}
205+
fn get_var(vid: uint) -> {root: uint, bounds:bounds<ty::t>} {
206+
ret self.get(self.vb, vid);
207+
}
208+
209+
fn get_region(rid: uint) -> {root: uint, bounds:bounds<ty::region>} {
210+
ret self.get(self.rb, rid);
222211
}
223212

224213
// Combines the two bounds. Returns a bounds r where (r.lb <:
225214
// a,b) and (a,b <: r.ub) (if such a bounds exists).
226-
fn merge_bnds(a: bound, b: bound) -> result<bounds, ty::type_err> {
215+
//
216+
// TODO: Generalize this to region bounds too.
217+
fn merge_bnds(a: bound<ty::t>, b: bound<ty::t>)
218+
-> result<bounds<ty::t>, ty::type_err> {
219+
227220
alt (a, b) {
228221
(none, none) {
229222
ok({lb: none, ub: none})
@@ -235,7 +228,7 @@ impl unify_methods for infer_ctxt {
235228
ok({lb: b, ub: b})
236229
}
237230
(some(t_a), some(t_b)) {
238-
let r1 = self.try {||
231+
let r1 = self.try(self.vb) {||
239232
self.tys(t_a, t_b).then {||
240233
ok({lb: a, ub: b})
241234
}
@@ -257,7 +250,9 @@ impl unify_methods for infer_ctxt {
257250
// a.lb <: c.lb
258251
// b.lb <: c.lb
259252
// If this cannot be achieved, the result is failure.
260-
fn merge(v_id: uint, a: bounds, b: bounds) -> ures {
253+
//
254+
// TODO: Generalize to regions.
255+
fn merge(v_id: uint, a: bounds<ty::t>, b: bounds<ty::t>) -> ures {
261256
// Think of the two diamonds, we want to find the
262257
// intersection. There are basically four possibilities (you
263258
// can swap A/B in these pictures):
@@ -275,8 +270,8 @@ impl unify_methods for infer_ctxt {
275270

276271
#debug["merge(<T%u>,%s,%s)",
277272
v_id,
278-
self.bounds_to_str(a),
279-
self.bounds_to_str(b)];
273+
self.ty_bounds_to_str(a),
274+
self.ty_bounds_to_str(b)];
280275

281276
chain(self.merge_bnds(a.ub, b.ub)) {|ub|
282277
chain(self.merge_bnds(a.lb, b.lb)) {|lb|
@@ -285,17 +280,18 @@ impl unify_methods for infer_ctxt {
285280
// the new bounds must themselves
286281
// be relatable:
287282
self.bnds(lb.ub, ub.lb).then {||
288-
self.set(v_id, bounded(bnds));
283+
self.set(self.vb, v_id, bounded(bnds));
289284
self.uok()
290285
}
291286
}
292287
}
293288
}
294289

290+
// TODO: Generalize to regions.
295291
fn vars(a_id: uint, b_id: uint) -> ures {
296292
// Need to make sub_id a subtype of sup_id.
297-
let {root: a_id, bounds: a_bounds} = self.get(a_id);
298-
let {root: b_id, bounds: b_bounds} = self.get(b_id);
293+
let {root: a_id, bounds: a_bounds} = self.get(self.vb, a_id);
294+
let {root: b_id, bounds: b_bounds} = self.get(self.vb, b_id);
299295

300296
#debug["vars(<T%u>=%s <: <T%u>=%s)",
301297
a_id, self.bounds_to_str(a_bounds),
@@ -321,26 +317,26 @@ impl unify_methods for infer_ctxt {
321317
// but that's the route we choose to take.
322318
self.merge(a_id, a_bounds, b_bounds).then {||
323319
// For max perf, we should consider the rank here.
324-
self.set(b_id, redirect(a_id));
320+
self.set(self.vb, b_id, redirect(a_id));
325321
self.uok()
326322
}
327323
}
328324

329325
fn varty(a_id: uint, b: ty::t) -> ures {
330-
let {root: a_id, bounds: a_bounds} = self.get(a_id);
326+
let {root: a_id, bounds: a_bounds} = self.get(self.vb, a_id);
331327
#debug["varty(<T%u>=%s <: %s)",
332-
a_id, self.bounds_to_str(a_bounds),
328+
a_id, self.ty_bounds_to_str(a_bounds),
333329
self.ty_to_str(b)];
334330
let b_bounds = {lb: none, ub: some(b)};
335331
self.merge(a_id, a_bounds, b_bounds)
336332
}
337333

338334
fn tyvar(a: ty::t, b_id: uint) -> ures {
339335
let a_bounds = {lb: some(a), ub: none};
340-
let {root: b_id, bounds: b_bounds} = self.get(b_id);
336+
let {root: b_id, bounds: b_bounds} = self.get(self.vb, b_id);
341337
#debug["tyvar(%s <: <T%u>=%s)",
342338
self.ty_to_str(a),
343-
b_id, self.bounds_to_str(b_bounds)];
339+
b_id, self.ty_bounds_to_str(b_bounds)];
344340
self.merge(b_id, a_bounds, b_bounds)
345341
}
346342

@@ -530,10 +526,11 @@ impl unify_methods for infer_ctxt {
530526
ret self.uok();
531527
}
532528

533-
fn bnds(a: bound, b: bound) -> ures {
529+
// TODO: Generalize this.
530+
fn bnds(a: bound<ty::t>, b: bound<ty::t>) -> ures {
534531
#debug("bnds(%s <: %s)",
535-
self.bound_to_str(a),
536-
self.bound_to_str(b));
532+
self.ty_bound_to_str(a),
533+
self.ty_bound_to_str(b));
537534

538535
alt (a, b) {
539536
(none, none) |
@@ -662,8 +659,10 @@ impl resolve_methods for infer_ctxt {
662659
result::err(v)
663660
}
664661

665-
fn resolve_var(vid: int) -> fres<ty::t> {
666-
let {root:_, bounds} = self.get(vid as uint);
662+
fn resolve_var<T:copy>(vb: vals_and_bindings<T>, bot_guard: fn(T)->bool,
663+
vid: int) -> fres<T> {
664+
665+
let {root:_, bounds} = self.get(vb, vid as uint);
667666

668667
// Nonobvious: prefer the most specific type
669668
// (i.e., the lower bound) to the more general
@@ -672,16 +671,20 @@ impl resolve_methods for infer_ctxt {
672671
// perf. penalties, so it pays to know more.
673672

674673
alt bounds {
675-
{ ub:_, lb:some(t) } if !type_is_bot(t) { self.rok(t) }
676-
{ ub:some(t), lb:_ } { self.rok(t) }
677-
{ ub:_, lb:some(t) } { self.rok(t) }
674+
{ ub:_, lb:some(t) } if !bot_guard(t) { result::ok(t) }
675+
{ ub:some(t), lb:_ } { result::ok(t) }
676+
{ ub:_, lb:some(t) } { result::ok(t) }
678677
{ ub:none, lb:none } { self.rerr(vid) }
679678
}
680679
}
681680

681+
fn resolve_ty_var(vid: int) -> fres<ty::t> {
682+
ret self.resolve_var(self.vb, {|t| type_is_bot(t)}, vid);
683+
}
684+
682685
fn resolve_ty(typ: ty::t) -> fres<ty::t> {
683686
alt ty::get(typ).struct {
684-
ty::ty_var(vid) { self.resolve_var(vid) }
687+
ty::ty_var(vid) { self.resolve_ty_var(vid) }
685688
ty::ty_rptr(ty::re_var(rid), base_ty) {
686689
alt self.resolve_region(rid as int) {
687690
result::err(terr) { result::err(terr) }
@@ -699,7 +702,7 @@ impl resolve_methods for infer_ctxt {
699702
vid: int) -> ty::t {
700703
// Should really return a fixup_result instead of a t, but fold_ty
701704
// doesn't allow returning anything but a t.
702-
alt self.resolve_var(vid) {
705+
alt self.resolve_ty_var(vid) {
703706
result::err(vid) {
704707
*unresolved = some(vid);
705708
ret ty::mk_var(self.tcx, vid);

0 commit comments

Comments
 (0)