Skip to content

Commit 3e28143

Browse files
committed
Union-find rank optimization for infer.
Makes deep-vector2 not run out of stack when suffix inference is enabled.
1 parent 906169d commit 3e28143

File tree

1 file changed

+78
-23
lines changed

1 file changed

+78
-23
lines changed

src/rustc/middle/typeck/infer.rs

Lines changed: 78 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ type bounds<T:copy> = {lb: bound<T>, ub: bound<T>};
267267

268268
enum var_value<V:copy, T:copy> {
269269
redirect(V),
270-
root(T)
270+
root(T, uint),
271271
}
272272

273273
type vals_and_bindings<V:copy, T:copy> = {
@@ -278,6 +278,7 @@ type vals_and_bindings<V:copy, T:copy> = {
278278
enum node<V:copy, T:copy> = {
279279
root: V,
280280
possible_types: T,
281+
rank: uint,
281282
};
282283

283284
enum infer_ctxt = @{
@@ -475,7 +476,8 @@ impl<V:copy vid, T:copy to_str> of to_str for var_value<V,T> {
475476
fn to_str(cx: infer_ctxt) -> str {
476477
alt self {
477478
redirect(vid) { #fmt("redirect(%s)", vid.to_str()) }
478-
root(pt) { #fmt("root(%s)", pt.to_str(cx)) }
479+
root(pt, rk) { #fmt("root(%s, %s)", pt.to_str(cx),
480+
uint::to_str(rk, 10u)) }
479481
}
480482
}
481483
}
@@ -578,7 +580,7 @@ impl methods for infer_ctxt {
578580
let id = *self.ty_var_counter;
579581
*self.ty_var_counter += 1u;
580582
self.tvb.vals.insert(id,
581-
root({lb: none, ub: none}));
583+
root({lb: none, ub: none}, 0u));
582584
ret tv_vid(id);
583585
}
584586

@@ -595,7 +597,7 @@ impl methods for infer_ctxt {
595597
*self.ty_var_integral_counter += 1u;
596598

597599
self.tvib.vals.insert(id,
598-
root(int_ty_set_all()));
600+
root(int_ty_set_all(), 0u));
599601
ret tvi_vid(id);
600602
}
601603

@@ -607,7 +609,7 @@ impl methods for infer_ctxt {
607609
let id = *self.region_var_counter;
608610
*self.region_var_counter += 1u;
609611
self.rb.vals.insert(id,
610-
root({lb: none, ub: none}));
612+
root({lb: none, ub: none}, 0u));
611613
ret region_vid(id);
612614
}
613615

@@ -661,8 +663,8 @@ impl unify_methods for infer_ctxt {
661663
}
662664
nde
663665
}
664-
root(pt) {
665-
node({root: vid, possible_types: pt})
666+
root(pt, rk) {
667+
node({root: vid, possible_types: pt, rank: rk})
666668
}
667669
}
668670
}
@@ -722,9 +724,10 @@ impl unify_methods for infer_ctxt {
722724
// a.lb <: c.lb
723725
// b.lb <: c.lb
724726
// If this cannot be achieved, the result is failure.
727+
725728
fn set_var_to_merged_bounds<V:copy vid, T:copy to_str st>(
726729
vb: vals_and_bindings<V, bounds<T>>,
727-
v_id: V, a: bounds<T>, b: bounds<T>) -> ures {
730+
v_id: V, a: bounds<T>, b: bounds<T>, rank: uint) -> ures {
728731

729732
// Think of the two diamonds, we want to find the
730733
// intersection. There are basically four possibilities (you
@@ -765,7 +768,7 @@ impl unify_methods for infer_ctxt {
765768
// the new bounds must themselves
766769
// be relatable:
767770
self.bnds(bnds.lb, bnds.ub).then {||
768-
self.set(vb, v_id, root(bnds));
771+
self.set(vb, v_id, root(bnds, rank));
769772
uok()
770773
}
771774
}}}}}
@@ -802,15 +805,42 @@ impl unify_methods for infer_ctxt {
802805
_ { /*fallthrough*/ }
803806
}
804807

805-
// For max perf, we should consider the rank here. But for now,
806-
// we always make b redirect to a.
807-
self.set(vb, b_id, redirect(a_id));
808-
809808
// Otherwise, we need to merge A and B so as to guarantee that
810809
// A remains a subtype of B. Actually, there are other options,
811810
// but that's the route we choose to take.
812-
self.set_var_to_merged_bounds(vb, a_id, a_bounds, b_bounds).then {||
813-
uok()
811+
812+
// Rank optimization
813+
814+
// Make the node with greater rank the parent of the node with
815+
// smaller rank.
816+
if nde_a.rank > nde_b.rank {
817+
#debug["vars(): a has smaller rank"];
818+
// a has greater rank, so a should become b's parent,
819+
// i.e., b should redirect to a.
820+
self.set(vb, b_id, redirect(a_id));
821+
self.set_var_to_merged_bounds(
822+
vb, a_id, a_bounds, b_bounds, nde_a.rank).then {||
823+
uok()
824+
}
825+
} else if nde_a.rank < nde_b.rank {
826+
#debug["vars(): b has smaller rank"];
827+
// b has geater rank, so a should redirect to b.
828+
self.set(vb, a_id, redirect(b_id));
829+
self.set_var_to_merged_bounds(
830+
vb, b_id, a_bounds, b_bounds, nde_b.rank).then {||
831+
uok()
832+
}
833+
} else {
834+
#debug["vars(): a and b have equal rank"];
835+
assert nde_a.rank == nde_b.rank;
836+
// If equal, just redirect one to the other and increment
837+
// the other's rank. We choose arbitrarily to redirect b
838+
// to a and increment a's rank.
839+
self.set(vb, b_id, redirect(a_id));
840+
self.set_var_to_merged_bounds(
841+
vb, a_id, a_bounds, b_bounds, nde_a.rank + 1u).then {||
842+
uok()
843+
}
814844
}
815845
}
816846

@@ -835,8 +865,29 @@ impl unify_methods for infer_ctxt {
835865
if *intersection == INT_TY_SET_EMPTY {
836866
ret err(ty::terr_no_integral_type);
837867
}
838-
self.set(vb, a_id, root(intersection));
839-
self.set(vb, b_id, redirect(a_id));
868+
869+
// Rank optimization
870+
if nde_a.rank > nde_b.rank {
871+
#debug["vars_integral(): a has smaller rank"];
872+
// a has greater rank, so a should become b's parent,
873+
// i.e., b should redirect to a.
874+
self.set(vb, a_id, root(intersection, nde_a.rank));
875+
self.set(vb, b_id, redirect(a_id));
876+
} else if nde_a.rank < nde_b.rank {
877+
#debug["vars_integral(): b has smaller rank"];
878+
// b has greater rank, so a should redirect to b.
879+
self.set(vb, b_id, root(intersection, nde_b.rank));
880+
self.set(vb, a_id, redirect(b_id));
881+
} else {
882+
#debug["vars_integral(): a and b have equal rank"];
883+
assert nde_a.rank == nde_b.rank;
884+
// If equal, just redirect one to the other and increment
885+
// the other's rank. We choose arbitrarily to redirect b
886+
// to a and increment a's rank.
887+
self.set(vb, a_id, root(intersection, nde_a.rank + 1u));
888+
self.set(vb, b_id, redirect(a_id));
889+
};
890+
840891
uok()
841892
}
842893

@@ -852,7 +903,8 @@ impl unify_methods for infer_ctxt {
852903
a_id.to_str(), a_bounds.to_str(self),
853904
b.to_str(self)];
854905
let b_bounds = {lb: none, ub: some(b)};
855-
self.set_var_to_merged_bounds(vb, a_id, a_bounds, b_bounds)
906+
self.set_var_to_merged_bounds(vb, a_id, a_bounds, b_bounds,
907+
nde_a.rank)
856908
}
857909

858910
fn vart_integral<V: copy vid>(
@@ -871,7 +923,7 @@ impl unify_methods for infer_ctxt {
871923
if *intersection == INT_TY_SET_EMPTY {
872924
ret err(ty::terr_no_integral_type);
873925
}
874-
self.set(vb, a_id, root(intersection));
926+
self.set(vb, a_id, root(intersection, nde_a.rank));
875927
uok()
876928
}
877929

@@ -887,7 +939,8 @@ impl unify_methods for infer_ctxt {
887939
#debug["tvar(%s <: %s=%s)",
888940
a.to_str(self),
889941
b_id.to_str(), b_bounds.to_str(self)];
890-
self.set_var_to_merged_bounds(vb, b_id, a_bounds, b_bounds)
942+
self.set_var_to_merged_bounds(vb, b_id, a_bounds, b_bounds,
943+
nde_b.rank)
891944
}
892945

893946
fn tvar_integral<V: copy vid>(
@@ -906,7 +959,7 @@ impl unify_methods for infer_ctxt {
906959
if *intersection == INT_TY_SET_EMPTY {
907960
ret err(ty::terr_no_integral_type);
908961
}
909-
self.set(vb, b_id, root(intersection));
962+
self.set(vb, b_id, root(intersection, nde_b.rank));
910963
uok()
911964
}
912965

@@ -1197,7 +1250,8 @@ impl methods for resolve_state {
11971250
self.infcx.set(
11981251
self.infcx.tvib, vid,
11991252
root(convert_integral_ty_to_int_ty_set(self.infcx.tcx,
1200-
ty)));
1253+
ty),
1254+
nde.rank));
12011255
ty
12021256
}
12031257
force_none {
@@ -2564,7 +2618,8 @@ fn lattice_var_t<V:copy vid, T:copy to_str st, L:lattice_ops combine>(
25642618
#debug["bnd=none"];
25652619
let a_bounds = self.with_bnd(a_bounds, b);
25662620
self.infcx().bnds(a_bounds.lb, a_bounds.ub).then {||
2567-
self.infcx().set(vb, a_id, root(a_bounds));
2621+
self.infcx().set(vb, a_id, root(a_bounds,
2622+
nde_a.rank));
25682623
ok(b)
25692624
}
25702625
}

0 commit comments

Comments
 (0)