Skip to content

Commit b247402

Browse files
committed
nits from pnkfelix
1 parent 10b8941 commit b247402

File tree

3 files changed

+76
-45
lines changed

3 files changed

+76
-45
lines changed

src/librustc/middle/free_region.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_data_structures::transitive_relation::TransitiveRelation;
1616

1717
#[derive(Clone)]
1818
pub struct FreeRegionMap {
19+
// Stores the relation `a < b`, where `a` and `b` are regions.
1920
relation: TransitiveRelation<Region>
2021
}
2122

src/librustc_data_structures/bitvec.rs

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,15 @@ impl BitVector {
5252

5353
/// A "bit matrix" is basically a square matrix of booleans
5454
/// represented as one gigantic bitvector. In other words, it is as if
55-
/// you have N bitvectors, each of length N.
55+
/// you have N bitvectors, each of length N. Note that `elements` here is `N`/
5656
#[derive(Clone)]
5757
pub struct BitMatrix {
5858
elements: usize,
5959
vector: Vec<u64>,
6060
}
6161

6262
impl BitMatrix {
63+
// Create a new `elements x elements` matrix, initially empty.
6364
pub fn new(elements: usize) -> BitMatrix {
6465
// For every element, we need one bit for every other
6566
// element. Round up to an even number of u64s.
@@ -88,15 +89,17 @@ impl BitMatrix {
8889
}
8990

9091
/// Do the bits from `source` contain `target`?
91-
/// Put another way, can `source` reach `target`?
92+
///
93+
/// Put another way, if the matrix represents (transitive)
94+
/// reachability, can `source` reach `target`?
9295
pub fn contains(&self, source: usize, target: usize) -> bool {
9396
let (start, _) = self.range(source);
9497
let (word, mask) = word_mask(target);
9598
(self.vector[start+word] & mask) != 0
9699
}
97100

98-
/// Returns those indices that are reachable from both source and
99-
/// target. This is an O(n) operation where `n` is the number of
101+
/// Returns those indices that are reachable from both `a` and
102+
/// `b`. This is an O(n) operation where `n` is the number of
100103
/// elements (somewhat independent from the actual size of the
101104
/// intersection, in particular).
102105
pub fn intersection(&self, a: usize, b: usize) -> Vec<usize> {
@@ -114,24 +117,24 @@ impl BitMatrix {
114117
result
115118
}
116119

117-
/// Add the bits from source to the bits from destination,
120+
/// Add the bits from `read` to the bits from `write`,
118121
/// return true if anything changed.
119122
///
120-
/// This is used when computing reachability because if you have
121-
/// an edge `destination -> source`, because in that case
122-
/// `destination` can reach everything that `source` can (and
123+
/// This is used when computing transitive reachability because if
124+
/// you have an edge `write -> read`, because in that case
125+
/// `write` can reach everything that `read` can (and
123126
/// potentially more).
124-
pub fn merge(&mut self, source: usize, destination: usize) -> bool {
125-
let (source_start, source_end) = self.range(source);
126-
let (destination_start, destination_end) = self.range(destination);
127+
pub fn merge(&mut self, read: usize, write: usize) -> bool {
128+
let (read_start, read_end) = self.range(read);
129+
let (write_start, write_end) = self.range(write);
127130
let vector = &mut self.vector[..];
128131
let mut changed = false;
129-
for (source_index, destination_index) in
130-
(source_start..source_end).zip(destination_start..destination_end)
132+
for (read_index, write_index) in
133+
(read_start..read_end).zip(write_start..write_end)
131134
{
132-
let v1 = vector[destination_index];
133-
let v2 = v1 | vector[source_index];
134-
vector[destination_index] = v2;
135+
let v1 = vector[write_index];
136+
let v2 = v1 | vector[read_index];
137+
vector[write_index] = v2;
135138
changed = changed | (v1 != v2);
136139
}
137140
changed
@@ -183,25 +186,29 @@ fn grow() {
183186
fn matrix_intersection() {
184187
let mut vec1 = BitMatrix::new(200);
185188

189+
// (*) Elements reachable from both 2 and 65.
190+
186191
vec1.add(2, 3);
187192
vec1.add(2, 6);
188-
vec1.add(2, 10);
189-
vec1.add(2, 64);
193+
vec1.add(2, 10); // (*)
194+
vec1.add(2, 64); // (*)
190195
vec1.add(2, 65);
191196
vec1.add(2, 130);
192-
vec1.add(2, 160);
197+
vec1.add(2, 160); // (*)
198+
199+
vec1.add(64, 133);
193200

194201
vec1.add(65, 2);
195202
vec1.add(65, 8);
196-
vec1.add(65, 10); // X
197-
vec1.add(65, 64); // X
203+
vec1.add(65, 10); // (*)
204+
vec1.add(65, 64); // (*)
198205
vec1.add(65, 68);
199206
vec1.add(65, 133);
200-
vec1.add(65, 160); // X
207+
vec1.add(65, 160); // (*)
201208

202209
let intersection = vec1.intersection(2, 64);
203210
assert!(intersection.is_empty());
204211

205212
let intersection = vec1.intersection(2, 65);
206-
assert_eq!(intersection, vec![10, 64, 160]);
213+
assert_eq!(intersection, &[10, 64, 160]);
207214
}

src/librustc_data_structures/transitive_relation.rs

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
6161
Some(i) => i,
6262
None => {
6363
self.elements.push(a);
64+
65+
// if we changed the dimensions, clear the cache
66+
*self.closure.borrow_mut() = None;
67+
6468
Index(self.elements.len() - 1)
6569
}
6670
}
@@ -73,17 +77,17 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
7377
let edge = Edge { source: a, target: b };
7478
if !self.edges.contains(&edge) {
7579
self.edges.push(edge);
76-
}
7780

78-
// clear cached closure, if any
79-
*self.closure.borrow_mut() = None;
81+
// added an edge, clear the cache
82+
*self.closure.borrow_mut() = None;
83+
}
8084
}
8185

8286
/// Check whether `a < target` (transitively)
8387
pub fn contains(&self, a: &T, b: &T) -> bool {
8488
match (self.index(a), self.index(b)) {
8589
(Some(a), Some(b)) =>
86-
self.take_closure(|closure| closure.contains(a.0, b.0)),
90+
self.with_closure(|closure| closure.contains(a.0, b.0)),
8791
(None, _) | (_, None) =>
8892
false,
8993
}
@@ -102,7 +106,8 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
102106
/// itself is not fully sufficient).
103107
///
104108
/// Examples are probably clearer than any prose I could write
105-
/// (there are corresponding tests below, btw):
109+
/// (there are corresponding tests below, btw). In each case,
110+
/// the query is `best_upper_bound(a, b)`:
106111
///
107112
/// ```
108113
/// // returns Some(x), which is also LUB
@@ -140,7 +145,11 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
140145
/// Returns the set of bounds `X` such that:
141146
///
142147
/// - `a < X` and `b < X`
143-
/// - there is no `Y` such that `a < Y` and `Y < X`
148+
/// - there is no `Y != X` such that `a < Y` and `Y < X`
149+
/// - except for the case where `X < a` (i.e., a strongly connected
150+
/// component in the graph). In that case, the smallest
151+
/// representative of the SCC is returned (as determined by the
152+
/// internal indices).
144153
///
145154
/// Note that this set can, in principle, have any size.
146155
pub fn minimal_upper_bounds(&self, a: &T, b: &T) -> Vec<&T> {
@@ -157,7 +166,7 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
157166
mem::swap(&mut a, &mut b);
158167
}
159168

160-
let lub_indices = self.take_closure(|closure| {
169+
let lub_indices = self.with_closure(|closure| {
161170
// Easy case is when either a < b or b < a:
162171
if closure.contains(a.0, b.0) {
163172
return vec![b.0];
@@ -178,18 +187,28 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
178187
// to the steps below.
179188
// - This vector contains upper bounds, but they are
180189
// not minimal upper bounds. So you may have e.g.
181-
// `[a, b, tcx, x]` where `a < tcx` and `b < tcx` and
182-
// `x < a` and `x < b`. This could be reduced to
183-
// just `[x]`.
190+
// `[x, y, tcx, z]` where `x < tcx` and `y < tcx` and
191+
// `z < x` and `z < y`:
192+
//
193+
// z --+---> x ----+----> tcx
194+
// | |
195+
// | |
196+
// +---> y ----+
197+
//
198+
// In this case, we really want to return just `[z]`.
199+
// The following steps below achieve this by gradually
200+
// reducing the list.
184201
// 2. Pare down the vector using `pare_down`. This will
185202
// remove elements from the vector that can be reached
186203
// by an earlier element.
187-
// - In the example above, this would convert
188-
// `[a, b, tcx, x]` to `[a, b, x]`. Note that `x`
189-
// remains because `x < a` but not `a < x.`
204+
// - In the example above, this would convert `[x, y,
205+
// tcx, z]` to `[x, y, z]`. Note that `x` and `y` are
206+
// still in the vector; this is because while `z < x`
207+
// (and `z < y`) holds, `z` comes after them in the
208+
// vector.
190209
// 3. Reverse the vector and repeat the pare down process.
191210
// - In the example above, we would reverse to
192-
// `[x, b, a]` and then pare down to `[x]`.
211+
// `[z, y, x]` and then pare down to `[z]`.
193212
// 4. Reverse once more just so that we yield a vector in
194213
// increasing order of index. Maybe this is silly.
195214
//
@@ -213,7 +232,7 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
213232
.collect()
214233
}
215234

216-
fn take_closure<OP,R>(&self, op: OP) -> R
235+
fn with_closure<OP,R>(&self, op: OP) -> R
217236
where OP: FnOnce(&BitMatrix) -> R
218237
{
219238
let mut closure_cell = self.closure.borrow_mut();
@@ -248,7 +267,8 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
248267
/// there exists an earlier element i<j such that i -> j. That is,
249268
/// after you run `pare_down`, you know that for all elements that
250269
/// remain in candidates, they cannot reach any of the elements that
251-
/// come after them.
270+
/// come after them. (Note that it may permute the ordering in some
271+
/// cases.)
252272
///
253273
/// Examples follow. Assume that a -> b -> c and x -> y -> z.
254274
///
@@ -264,9 +284,13 @@ fn pare_down(candidates: &mut Vec<usize>, closure: &BitMatrix) {
264284
let mut j = i;
265285
while j < candidates.len() {
266286
if closure.contains(candidate, candidates[j]) {
267-
// if i can reach j, then we can remove j
268-
println!("pare_down: candidates[{:?}]={:?} candidates[{:?}] = {:?}",
269-
i-1, candidate, j, candidates[j]);
287+
// If `i` can reach `j`, then we can remove `j`. Given
288+
// how careful this algorithm is about ordering, it
289+
// may seem odd to use swap-remove. The reason it is
290+
// ok is that we are swapping two elements (`j` and
291+
// `max`) that are both to the right of our cursor
292+
// `i`, and the invariant that we are establishing
293+
// continues to hold for everything left of `i`.
270294
candidates.swap_remove(j);
271295
} else {
272296
j += 1;
@@ -371,9 +395,8 @@ fn mubs_best_choice2() {
371395

372396
#[test]
373397
fn mubs_no_best_choice() {
374-
// in this case, the intersection yields [1, 2],
375-
// and we need the first "pare down" call to narrow
376-
// this down to [2]
398+
// in this case, the intersection yields [1, 2], and the "pare
399+
// down" calls find nothing to remove.
377400
let mut relation = TransitiveRelation::new();
378401
relation.add("0", "1");
379402
relation.add("0", "2");

0 commit comments

Comments
 (0)