Skip to content

Commit 8118478

Browse files
committed
remove dependency map and instead use a linked list of constraints
1 parent 79f4710 commit 8118478

File tree

3 files changed

+55
-17
lines changed

3 files changed

+55
-17
lines changed

src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
8484
sub,
8585
point,
8686
span,
87+
next: _,
8788
} = constraint;
8889
with_msg(&format!(
8990
"{:?}: {:?} @ {:?} due to {:?}",

src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ impl<'this, 'tcx> dot::GraphWalk<'this> for RegionInferenceContext<'tcx> {
5555
vids.into_cow()
5656
}
5757
fn edges(&'this self) -> dot::Edges<'this, Constraint> {
58-
(&self.constraints[..]).into_cow()
58+
(&self.constraints.raw[..]).into_cow()
5959
}
6060

6161
// Render `a: b` as `a <- b`, indicating the flow

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::collections::HashMap;
12-
1311
use super::universal_regions::UniversalRegions;
1412
use rustc::hir::def_id::DefId;
1513
use rustc::infer::InferCtxt;
@@ -23,9 +21,9 @@ use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegi
2321
Local, Location, Mir};
2422
use rustc::traits::ObligationCause;
2523
use rustc::ty::{self, RegionVid, Ty, TypeFoldable};
26-
use rustc::util::common::ErrorReported;
24+
use rustc::util::common::{self, ErrorReported};
2725
use rustc_data_structures::bitvec::BitVector;
28-
use rustc_data_structures::indexed_vec::IndexVec;
26+
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
2927
use std::fmt;
3028
use std::rc::Rc;
3129
use syntax::ast;
@@ -61,8 +59,15 @@ pub struct RegionInferenceContext<'tcx> {
6159
/// until `solve` is invoked.
6260
inferred_values: Option<RegionValues>,
6361

62+
/// For each variable, stores the index of the first constraint
63+
/// where that variable appears on the RHS. This is the start of a
64+
/// 'linked list' threaded by the `next` field in `Constraint`.
65+
///
66+
/// This map is build when values are inferred.
67+
dependency_map: Option<IndexVec<RegionVid, Option<ConstraintIndex>>>,
68+
6469
/// The constraints we have accumulated and used during solving.
65-
constraints: Vec<Constraint>,
70+
constraints: IndexVec<ConstraintIndex, Constraint>,
6671

6772
/// Type constraints that we check after solving.
6873
type_tests: Vec<TypeTest<'tcx>>,
@@ -143,10 +148,22 @@ pub struct Constraint {
143148
/// At this location.
144149
point: Location,
145150

151+
/// Later on, we thread the constraints onto a linked list
152+
/// sorted by their `sub` field. So if you had:
153+
///
154+
/// Index | Constraint | Next Field
155+
/// ----- | ---------- | ----------
156+
/// 0 | `'a: 'b` | Some(2)
157+
/// 1 | `'b: 'c` | None
158+
/// 2 | `'c: 'b` | None
159+
next: Option<ConstraintIndex>,
160+
146161
/// Where did this constraint arise?
147162
span: Span,
148163
}
149164

165+
newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" });
166+
150167
/// A "type test" corresponds to an outlives constraint between a type
151168
/// and a lifetime, like `T: 'x` or `<T as Foo>::Bar: 'x`. They are
152169
/// translated from the `Verify` region constraints in the ordinary
@@ -259,7 +276,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
259276
elements: elements.clone(),
260277
liveness_constraints: RegionValues::new(elements, num_region_variables),
261278
inferred_values: None,
262-
constraints: Vec::new(),
279+
dependency_map: None,
280+
constraints: IndexVec::new(),
263281
type_tests: Vec::new(),
264282
universal_regions,
265283
};
@@ -387,6 +405,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
387405
sup,
388406
sub,
389407
point,
408+
next: None,
390409
});
391410
}
392411

@@ -403,6 +422,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
403422
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
404423
mir: &Mir<'tcx>,
405424
mir_def_id: DefId,
425+
) -> Option<ClosureRegionRequirements<'gcx>> {
426+
common::time(infcx.tcx.sess, &format!("solve({:?})", mir_def_id), || {
427+
self.solve_inner(infcx, mir, mir_def_id)
428+
})
429+
}
430+
431+
fn solve_inner<'gcx>(
432+
&mut self,
433+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
434+
mir: &Mir<'tcx>,
435+
mir_def_id: DefId,
406436
) -> Option<ClosureRegionRequirements<'gcx>> {
407437
assert!(self.inferred_values.is_none(), "values already inferred");
408438

@@ -448,6 +478,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
448478
/// satisfied. Note that some values may grow **too** large to be
449479
/// feasible, but we check this later.
450480
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
481+
self.dependency_map = Some(self.build_dependency_map());
451482
let inferred_values = self.compute_region_values(mir, TrackCauses(false));
452483
self.inferred_values = Some(inferred_values);
453484
}
@@ -465,17 +496,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
465496
// constraints we have accumulated.
466497
let mut inferred_values = self.liveness_constraints.duplicate(track_causes);
467498

468-
let dependency_map = self.build_dependency_map();
499+
let dependency_map = self.dependency_map.as_ref().unwrap();
469500

470501
// Constraints that may need to be repropagated (initially all):
471-
let mut dirty_list: Vec<_> = (0..self.constraints.len()).collect();
502+
let mut dirty_list: Vec<_> = self.constraints.indices().collect();
472503

473504
// Set to 0 for each constraint that is on the dirty list:
474505
let mut clean_bit_vec = BitVector::new(dirty_list.len());
475506

476507
debug!("propagate_constraints: --------------------");
477508
while let Some(constraint_idx) = dirty_list.pop() {
478-
clean_bit_vec.insert(constraint_idx);
509+
clean_bit_vec.insert(constraint_idx.index());
479510

480511
let constraint = &self.constraints[constraint_idx];
481512
debug!("propagate_constraints: constraint={:?}", constraint);
@@ -497,10 +528,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
497528
debug!("propagate_constraints: sub={:?}", constraint.sub);
498529
debug!("propagate_constraints: sup={:?}", constraint.sup);
499530

500-
for &dep_idx in dependency_map.get(&constraint.sup).unwrap_or(&vec![]) {
501-
if clean_bit_vec.remove(dep_idx) {
531+
let mut opt_dep_idx = dependency_map[constraint.sup];
532+
while let Some(dep_idx) = opt_dep_idx {
533+
if clean_bit_vec.remove(dep_idx.index()) {
502534
dirty_list.push(dep_idx);
503535
}
536+
opt_dep_idx = self.constraints[dep_idx].next;
504537
}
505538
}
506539

@@ -514,11 +547,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
514547
/// indices of constraints that need to be re-evaluated when X changes.
515548
/// These are constraints like Y: X @ P -- so if X changed, we may
516549
/// need to grow Y.
517-
fn build_dependency_map(&self) -> HashMap<RegionVid, Vec<usize>> {
518-
let mut map = HashMap::new();
519-
520-
for (idx, constraint) in self.constraints.iter().enumerate() {
521-
map.entry(constraint.sub).or_insert(Vec::new()).push(idx);
550+
#[inline(never)]
551+
fn build_dependency_map(&mut self) -> IndexVec<RegionVid, Option<ConstraintIndex>> {
552+
let mut map = IndexVec::from_elem(None, &self.definitions);
553+
554+
for (idx, constraint) in self.constraints.iter_enumerated_mut().rev() {
555+
let mut head = &mut map[constraint.sub];
556+
debug_assert!(constraint.next.is_none());
557+
constraint.next = *head;
558+
*head = Some(idx);
522559
}
523560

524561
map

0 commit comments

Comments
 (0)