Skip to content

Commit 03cd7d6

Browse files
committed
extend TransitiveRelation with parents function
1 parent f0c89de commit 03cd7d6

File tree

1 file changed

+128
-2
lines changed

1 file changed

+128
-2
lines changed

src/librustc_data_structures/transitive_relation.rs

Lines changed: 128 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,14 @@ impl<T: Clone + Debug + Eq + Hash + Clone> TransitiveRelation<T> {
185185
/// b -> b1
186186
/// ```
187187
pub fn postdom_upper_bound(&self, a: &T, b: &T) -> Option<&T> {
188-
let mut mubs = self.minimal_upper_bounds(a, b);
188+
let mubs = self.minimal_upper_bounds(a, b);
189+
self.mutual_immediate_postdominator(mubs)
190+
}
191+
192+
/// Viewing the relation as a graph, computes the "mutual
193+
/// immediate postdominator" of a set of points (if one
194+
/// exists). See `postdom_upper_bound` for details.
195+
pub fn mutual_immediate_postdominator<'a>(&'a self, mut mubs: Vec<&'a T>) -> Option<&'a T> {
189196
loop {
190197
match mubs.len() {
191198
0 => return None,
@@ -277,6 +284,8 @@ impl<T: Clone + Debug + Eq + Hash + Clone> TransitiveRelation<T> {
277284
// After step 3, we know that no element can reach any of
278285
// its predecesssors (because of step 2) nor successors
279286
// (because we just called `pare_down`)
287+
//
288+
// This same algorithm is used in `parents` below.
280289

281290
let mut candidates = closure.intersection(a.0, b.0); // (1)
282291
pare_down(&mut candidates, closure); // (2)
@@ -291,6 +300,59 @@ impl<T: Clone + Debug + Eq + Hash + Clone> TransitiveRelation<T> {
291300
.collect()
292301
}
293302

303+
/// Given an element A, returns the maximal set {B} of elements B
304+
/// such that
305+
///
306+
/// - A != A
307+
/// - A R B is true
308+
/// - for each i, j: B[i] R B[j] does not hold
309+
///
310+
/// The intuition is that this moves "one step up" through a lattice
311+
/// (where the relation is encoding the `<=` relation for the lattice).
312+
/// So e.g. if the relation is `->` and we have
313+
///
314+
/// ```
315+
/// a -> b -> d -> f
316+
/// | ^
317+
/// +--> c -> e ---+
318+
/// ```
319+
///
320+
/// then `parents(a)` returns `[b, c]`. The `postdom_parent` function
321+
/// would further reduce this to just `f`.
322+
pub fn parents(&self, a: &T) -> Vec<&T> {
323+
let a = match self.index(a) {
324+
Some(a) => a,
325+
None => return vec![]
326+
};
327+
328+
// Steal the algorithm for `minimal_upper_bounds` above, but
329+
// with a slight tweak. In the case where `a R a`, we remove
330+
// that from the set of candidates.
331+
let ancestors = self.with_closure(|closure| {
332+
let mut ancestors = closure.intersection(a.0, a.0);
333+
334+
// Remove anything that can reach `a`. If this is a
335+
// reflexive relation, this will include `a` itself.
336+
ancestors.retain(|&e| !closure.contains(e, a.0));
337+
338+
pare_down(&mut ancestors, closure); // (2)
339+
ancestors.reverse(); // (3a)
340+
pare_down(&mut ancestors, closure); // (3b)
341+
ancestors
342+
});
343+
344+
ancestors.into_iter()
345+
.rev() // (4)
346+
.map(|i| &self.elements[i])
347+
.collect()
348+
}
349+
350+
/// A "best" parent in some sense. See `parents` and
351+
/// `postdom_upper_bound` for more details.
352+
pub fn postdom_parent(&self, a: &T) -> Option<&T> {
353+
self.mutual_immediate_postdominator(self.parents(a))
354+
}
355+
294356
fn with_closure<OP, R>(&self, op: OP) -> R
295357
where OP: FnOnce(&BitMatrix) -> R
296358
{
@@ -469,11 +531,17 @@ fn test_many_steps() {
469531
}
470532

471533
#[test]
472-
fn mubs_triange() {
534+
fn mubs_triangle() {
535+
// a -> tcx
536+
// ^
537+
// |
538+
// b
473539
let mut relation = TransitiveRelation::new();
474540
relation.add("a", "tcx");
475541
relation.add("b", "tcx");
476542
assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"tcx"]);
543+
assert_eq!(relation.parents(&"a"), vec![&"tcx"]);
544+
assert_eq!(relation.parents(&"b"), vec![&"tcx"]);
477545
}
478546

479547
#[test]
@@ -499,6 +567,9 @@ fn mubs_best_choice1() {
499567
relation.add("3", "2");
500568

501569
assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"2"]);
570+
assert_eq!(relation.parents(&"0"), vec![&"2"]);
571+
assert_eq!(relation.parents(&"2"), vec![&"1"]);
572+
assert!(relation.parents(&"1").is_empty());
502573
}
503574

504575
#[test]
@@ -523,6 +594,9 @@ fn mubs_best_choice2() {
523594
relation.add("3", "2");
524595

525596
assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"1"]);
597+
assert_eq!(relation.parents(&"0"), vec![&"1"]);
598+
assert_eq!(relation.parents(&"1"), vec![&"2"]);
599+
assert!(relation.parents(&"2").is_empty());
526600
}
527601

528602
#[test]
@@ -537,10 +611,15 @@ fn mubs_no_best_choice() {
537611
relation.add("3", "2");
538612

539613
assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"1", &"2"]);
614+
assert_eq!(relation.parents(&"0"), vec![&"1", &"2"]);
615+
assert_eq!(relation.parents(&"3"), vec![&"1", &"2"]);
540616
}
541617

542618
#[test]
543619
fn mubs_best_choice_scc() {
620+
// in this case, 1 and 2 form a cycle; we pick arbitrarily (but
621+
// consistently).
622+
544623
let mut relation = TransitiveRelation::new();
545624
relation.add("0", "1");
546625
relation.add("0", "2");
@@ -552,6 +631,7 @@ fn mubs_best_choice_scc() {
552631
relation.add("3", "2");
553632

554633
assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"1"]);
634+
assert_eq!(relation.parents(&"0"), vec![&"1"]);
555635
}
556636

557637
#[test]
@@ -573,6 +653,8 @@ fn pdub_crisscross() {
573653
assert_eq!(relation.minimal_upper_bounds(&"a", &"b"),
574654
vec![&"a1", &"b1"]);
575655
assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
656+
assert_eq!(relation.postdom_parent(&"a"), Some(&"x"));
657+
assert_eq!(relation.postdom_parent(&"b"), Some(&"x"));
576658
}
577659

578660
#[test]
@@ -604,6 +686,9 @@ fn pdub_crisscross_more() {
604686
assert_eq!(relation.minimal_upper_bounds(&"a1", &"b1"),
605687
vec![&"a2", &"b2"]);
606688
assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
689+
690+
assert_eq!(relation.postdom_parent(&"a"), Some(&"x"));
691+
assert_eq!(relation.postdom_parent(&"b"), Some(&"x"));
607692
}
608693

609694
#[test]
@@ -621,6 +706,11 @@ fn pdub_lub() {
621706

622707
assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"x"]);
623708
assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
709+
710+
assert_eq!(relation.postdom_parent(&"a"), Some(&"a1"));
711+
assert_eq!(relation.postdom_parent(&"b"), Some(&"b1"));
712+
assert_eq!(relation.postdom_parent(&"a1"), Some(&"x"));
713+
assert_eq!(relation.postdom_parent(&"b1"), Some(&"x"));
624714
}
625715

626716
#[test]
@@ -722,3 +812,39 @@ fn mubs_scc_4() {
722812

723813
assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
724814
}
815+
816+
#[test]
817+
fn parent() {
818+
// An example that was misbehaving in the compiler.
819+
//
820+
// 4 -> 1 -> 3
821+
// \ | /
822+
// \ v /
823+
// 2 -> 0
824+
//
825+
// plus a bunch of self-loops
826+
//
827+
// Here `->` represents `<=` and `0` is `'static`.
828+
829+
let pairs = vec![
830+
(2, /*->*/ 0),
831+
(2, /*->*/ 2),
832+
(0, /*->*/ 0),
833+
(0, /*->*/ 0),
834+
(1, /*->*/ 0),
835+
(1, /*->*/ 1),
836+
(3, /*->*/ 0),
837+
(3, /*->*/ 3),
838+
(4, /*->*/ 0),
839+
(4, /*->*/ 1),
840+
(1, /*->*/ 3),
841+
];
842+
843+
let mut relation = TransitiveRelation::new();
844+
for (a, b) in pairs {
845+
relation.add(a, b);
846+
}
847+
848+
let p = relation.postdom_parent(&3);
849+
assert_eq!(p, Some(&0));
850+
}

0 commit comments

Comments
 (0)