Skip to content

Commit f5dbb04

Browse files
author
Markus Westerlind
committed
Document the additions
1 parent 0f08a69 commit f5dbb04

File tree

7 files changed

+84
-54
lines changed

7 files changed

+84
-54
lines changed

compiler/rustc_data_structures/src/logged_unification_table.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,15 @@ impl<K: ut::UnifyKey, I: Idx> Rollback<UndoLog<K, I>> for LoggedUnificationTable
4141
}
4242
}
4343

44+
/// Storage for `LoggedUnificationTable`
4445
pub struct LoggedUnificationTableStorage<K: ut::UnifyKey, I: Idx = K> {
4546
relations: ut::UnificationTableStorage<K>,
4647
unify_log: ul::UnifyLog<I>,
4748
modified_set: ms::ModifiedSet<I>,
4849
}
4950

51+
/// UnificationTableStorage which logs which variables has been unfified with a value, allowing watchers
52+
/// to only iterate over the changed variables instead of all variables
5053
pub struct LoggedUnificationTable<'a, K: ut::UnifyKey, I: Idx, L> {
5154
storage: &'a mut LoggedUnificationTableStorage<K, I>,
5255
undo_log: L,
@@ -170,28 +173,37 @@ where
170173
self.relations().new_key(value)
171174
}
172175

176+
/// Clears any modifications currently tracked. Usually this can only be done once there are no
177+
/// snapshots active as the modifications may otherwise be needed after a rollback
173178
pub fn clear_modified_set(&mut self) {
174179
self.storage.modified_set.clear();
175180
}
176181

177-
pub fn register(&mut self) -> ms::Offset<I> {
182+
/// Registers a watcher on the unifications done in this table
183+
pub fn register_watcher(&mut self) -> ms::Offset<I> {
178184
self.storage.modified_set.register()
179185
}
180186

181-
pub fn deregister(&mut self, offset: ms::Offset<I>) {
187+
/// Deregisters a watcher previously registered in this table
188+
pub fn deregister_watcher(&mut self, offset: ms::Offset<I>) {
182189
self.storage.modified_set.deregister(offset);
183190
}
184191

192+
/// Watches the variable at `index` allowing any watchers to be notified to unifications with
193+
/// `index`
185194
pub fn watch_variable(&mut self, index: I) {
186195
debug_assert!(index == self.relations().find(index).into());
187196
self.storage.unify_log.watch_variable(index)
188197
}
189198

199+
/// Unwatches a previous watch at `index`
190200
pub fn unwatch_variable(&mut self, index: I) {
191201
self.storage.unify_log.unwatch_variable(index)
192202
}
193203

194-
pub fn drain_modified_set(&mut self, offset: &ms::Offset<I>, mut f: impl FnMut(I) -> bool) {
204+
/// Iterates through all unified variables since the last call to `drain_modified_set`
205+
/// passing the unified variable to `f`
206+
pub fn drain_modified_set(&mut self, offset: &ms::Offset<I>, mut f: impl FnMut(I)) {
195207
let unify_log = &self.storage.unify_log;
196208
self.storage.modified_set.drain(&mut self.undo_log, offset, |vid| {
197209
for &unified_vid in unify_log.get(vid) {

compiler/rustc_data_structures/src/modified_set.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ impl<T: Idx> ModifiedSet<T> {
3939
&mut self,
4040
undo_log: &mut impl UndoLogs<Undo<T>>,
4141
index: &Offset<T>,
42-
mut f: impl FnMut(T) -> bool,
42+
mut f: impl FnMut(T),
4343
) {
4444
let offset = &mut self.offsets[index.index];
4545
if *offset < self.modified.len() {

compiler/rustc_data_structures/src/obligation_forest/mod.rs

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@
7575
use crate::fx::{FxHashMap, FxHashSet};
7676

7777
use std::cell::{Cell, RefCell};
78+
use std::cmp::Ordering;
7879
use std::collections::hash_map::Entry;
80+
use std::collections::BinaryHeap;
7981
use std::fmt::Debug;
8082
use std::hash;
8183
use std::marker::PhantomData;
@@ -87,8 +89,11 @@ mod graphviz;
8789
mod tests;
8890

8991
pub trait ForestObligation: Clone + Debug {
92+
/// A key used to avoid evaluating the same obligation twice
9093
type CacheKey: Clone + hash::Hash + Eq + Debug;
94+
/// The variable type used in the obligation when it could not yet be fulfilled
9195
type Variable: Clone + hash::Hash + Eq + Debug;
96+
/// A type which tracks which variables has been unified
9297
type WatcherOffset;
9398

9499
/// Converts this `ForestObligation` suitable for use as a cache key.
@@ -97,6 +102,8 @@ pub trait ForestObligation: Clone + Debug {
97102
/// (e.g. success for error) for the other obligation
98103
fn as_cache_key(&self) -> Self::CacheKey;
99104

105+
/// Returns which variables this obligation is currently stalled on. If the slice is empty then
106+
/// the variables stalled on are unknown.
100107
fn stalled_on(&self) -> &[Self::Variable];
101108
}
102109

@@ -124,7 +131,7 @@ pub trait ObligationProcessor {
124131
fn unblocked(
125132
&self,
126133
offset: &<Self::Obligation as ForestObligation>::WatcherOffset,
127-
f: impl FnMut(<Self::Obligation as ForestObligation>::Variable) -> bool,
134+
f: impl FnMut(<Self::Obligation as ForestObligation>::Variable),
128135
);
129136
fn register(&self) -> <Self::Obligation as ForestObligation>::WatcherOffset;
130137
fn deregister(&self, offset: <Self::Obligation as ForestObligation>::WatcherOffset);
@@ -157,9 +164,16 @@ pub struct ObligationForest<O: ForestObligation> {
157164
/// this list only contains nodes in the `Pending` or `Waiting` state.
158165
nodes: Vec<Node<O>>,
159166

160-
/// Nodes must be processed in the order that they were added which this list keeps track of.
167+
/// Nodes must be processed in the order that they were added so we give each node a unique,
168+
/// number allowing them to be ordered when processing them.
169+
node_number: u32,
170+
171+
/// Stores the indices of the nodes currently in the pending state
161172
pending_nodes: Vec<NodeIndex>,
173+
174+
/// Stores the indices of the nodes currently in the success or waiting states
162175
success_or_waiting_nodes: Vec<NodeIndex>,
176+
/// Stores the indices of the nodes currently in the error or done states
163177
error_or_done_nodes: RefCell<Vec<NodeIndex>>,
164178

165179
/// Nodes that have been removed and are ready to be reused
@@ -171,7 +185,6 @@ pub struct ObligationForest<O: ForestObligation> {
171185
active_cache: FxHashMap<O::CacheKey, Option<NodeIndex>>,
172186

173187
obligation_tree_id_generator: ObligationTreeIdGenerator,
174-
node_number: u32,
175188

176189
/// Per tree error cache. This is used to deduplicate errors,
177190
/// which is necessary to avoid trait resolution overflow in
@@ -182,18 +195,25 @@ pub struct ObligationForest<O: ForestObligation> {
182195
/// [details]: https://github.com/rust-lang/rust/pull/53255#issuecomment-421184780
183196
error_cache: FxHashMap<ObligationTreeId, FxHashSet<O::CacheKey>>,
184197

198+
/// Stores which nodes would be unblocked once `O::Variable` is unified
185199
stalled_on: FxHashMap<O::Variable, Vec<NodeIndex>>,
186-
unblocked: std::collections::BinaryHeap<Unblocked>,
200+
/// Stores the node indices that are unblocked and should be processed at the next opportunity
201+
unblocked: BinaryHeap<Unblocked>,
202+
/// Stores nodes which should be processed on the next iteration since the variables they are
203+
/// actually blocked on are unknown
187204
check_next: Vec<NodeIndex>,
205+
/// The offset that this `ObligationForest` has registered. Should be de-registered before
206+
/// dropping this forest.
188207
offset: Option<O::WatcherOffset>,
189208
}
190209

210+
/// Helper struct for use with `BinaryHeap` to process nodes in the order that they were added to
211+
/// the forest
191212
struct Unblocked {
192-
index: usize,
213+
index: NodeIndex,
193214
order: u32,
194215
}
195216

196-
use std::cmp::Ordering;
197217
impl PartialEq for Unblocked {
198218
fn eq(&self, other: &Self) -> bool {
199219
self.order == other.order
@@ -216,11 +236,14 @@ struct Node<O: ForestObligation> {
216236
obligation: O,
217237
state: Cell<NodeState>,
218238

239+
/// A predicate (and its key) can changed during processing. If it does we need to register the
240+
/// old predicate so that we can remove or mark it as done if this node errors or is done.
219241
alternative_predicates: Vec<O::CacheKey>,
220242

221243
/// Obligations that depend on this obligation for their completion. They
222244
/// must all be in a non-pending state.
223245
dependents: Vec<NodeIndex>,
246+
/// Obligations that this obligation depends on for their completion.
224247
reverse_dependents: Vec<NodeIndex>,
225248

226249
/// If true, `dependents[0]` points to a "parent" node, which requires
@@ -257,6 +280,7 @@ where
257280
}
258281
}
259282

283+
/// Initializes a node, reusing the existing allocations
260284
fn init(
261285
&mut self,
262286
parent: Option<NodeIndex>,
@@ -473,12 +497,16 @@ impl<O: ForestObligation> ObligationForest<O> {
473497
.get(&obligation_tree_id)
474498
.map(|errors| errors.contains(&obligation.as_cache_key()))
475499
.unwrap_or(false);
500+
// Retrieves a fresh number for the new node so that each node are processed in the
501+
// order that they were created
476502
let node_number = self.node_number;
477503
self.node_number += 1;
478504

479505
if already_failed {
480506
Err(())
481507
} else {
508+
// If we have a dead node we can reuse it and it's associated allocations,
509+
// otherwise allocate a new node
482510
let new_index = if let Some(new_index) = self.dead_nodes.pop() {
483511
let node = &mut self.nodes[new_index];
484512
node.init(parent, obligation, obligation_tree_id, node_number);
@@ -549,11 +577,6 @@ impl<O: ForestObligation> ObligationForest<O> {
549577
if self.offset.is_none() {
550578
self.offset = Some(processor.register());
551579
}
552-
warn!(
553-
"Begin process {}, pending: {}",
554-
self.nodes.len(),
555-
self.nodes.iter().filter(|n| n.state.get() == NodeState::Pending).count()
556-
);
557580
let mut errors = vec![];
558581
let mut stalled = true;
559582

@@ -577,6 +600,8 @@ impl<O: ForestObligation> ObligationForest<O> {
577600
if node.state.get() != NodeState::Pending {
578601
continue;
579602
}
603+
604+
// Any variables we were stalled on are now resolved so remove the watches
580605
for var in node.obligation.stalled_on() {
581606
match self.stalled_on.entry(var.clone()) {
582607
Entry::Vacant(_) => (),
@@ -607,18 +632,22 @@ impl<O: ForestObligation> ObligationForest<O> {
607632
let node = &mut self.nodes[index];
608633
match result {
609634
ProcessResult::Unchanged => {
610-
for var in node.obligation.stalled_on() {
611-
self.stalled_on
612-
.entry(var.clone())
613-
.or_insert_with(|| {
614-
processor.watch_variable(var.clone());
615-
Vec::new()
616-
})
617-
.push(index);
618-
}
619-
620-
if node.obligation.stalled_on().is_empty() {
635+
// We stalled but the variables that caused it are unknown so we run
636+
// `index` again at the next opportunity
637+
let stalled_on = node.obligation.stalled_on();
638+
if stalled_on.is_empty() {
621639
self.check_next.push(index);
640+
} else {
641+
// Register every variable that we stal
642+
for var in stalled_on {
643+
self.stalled_on
644+
.entry(var.clone())
645+
.or_insert_with(|| {
646+
processor.watch_variable(var.clone());
647+
Vec::new()
648+
})
649+
.push(index);
650+
}
622651
}
623652
// No change in state.
624653
}
@@ -646,7 +675,6 @@ impl<O: ForestObligation> ObligationForest<O> {
646675
}
647676

648677
if stalled {
649-
warn!("Stalled {}", self.nodes.len());
650678
// There's no need to perform marking, cycle processing and compression when nothing
651679
// changed.
652680
return Outcome {
@@ -655,13 +683,9 @@ impl<O: ForestObligation> ObligationForest<O> {
655683
};
656684
}
657685

658-
warn!("Compressing {}", self.nodes.len());
659686
self.mark_successes();
660687
self.process_cycles(processor);
661688
let completed = self.compress(do_completed);
662-
warn!("Compressed {}", self.nodes.len());
663-
664-
warn!("Stalled on: {:?}", self.stalled_on.keys().collect::<Vec<_>>());
665689

666690
Outcome { completed, errors }
667691
}
@@ -678,19 +702,16 @@ impl<O: ForestObligation> ObligationForest<O> {
678702
processor.unblocked(self.offset.as_ref().unwrap(), |var| {
679703
if let Some(unblocked_nodes) = stalled_on.remove(&var) {
680704
for node_index in unblocked_nodes {
705+
let node = &nodes[node_index];
681706
debug_assert!(
682-
nodes[node_index].state.get() == NodeState::Pending,
707+
node.state.get() == NodeState::Pending,
683708
"Unblocking non-pending2: {:?}",
684-
nodes[node_index].obligation
709+
node.obligation
685710
);
686-
unblocked.push(Unblocked {
687-
index: node_index,
688-
order: nodes[node_index].node_number,
689-
});
711+
unblocked.push(Unblocked { index: node_index, order: node.node_number });
690712
}
691713
temp.push(var);
692714
}
693-
true
694715
});
695716
for var in temp {
696717
processor.unwatch_variable(var);
@@ -848,6 +869,7 @@ impl<O: ForestObligation> ObligationForest<O> {
848869
fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
849870
let mut removed_done_obligations: Vec<O> = vec![];
850871

872+
// Compress the forest by removing any nodes marked as error or done
851873
let mut error_or_done_nodes = mem::take(self.error_or_done_nodes.get_mut());
852874
for &index in &error_or_done_nodes {
853875
let node = &mut self.nodes[index];

compiler/rustc_data_structures/src/obligation_forest/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ where
9696
fn unblocked(
9797
&self,
9898
_offset: &<Self::Obligation as ForestObligation>::WatcherOffset,
99-
_f: impl FnMut(<Self::Obligation as ForestObligation>::Variable) -> bool,
99+
_f: impl FnMut(<Self::Obligation as ForestObligation>::Variable),
100100
) {
101101
}
102102
fn register(&self) -> <Self::Obligation as ForestObligation>::WatcherOffset {}

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,7 +1617,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16171617
pub fn drain_modifications(
16181618
&self,
16191619
offset: &WatcherOffset,
1620-
mut f: impl FnMut(TyOrConstInferVar) -> bool,
1620+
mut f: impl FnMut(TyOrConstInferVar),
16211621
) {
16221622
let mut inner = self.inner.borrow_mut();
16231623

@@ -1643,11 +1643,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16431643
WatcherOffset {
16441644
ty_offset: inner.type_variables().register_unify_watcher(),
16451645

1646-
int_offset: inner.int_unification_table().register(),
1646+
int_offset: inner.int_unification_table().register_watcher(),
16471647

1648-
float_offset: inner.float_unification_table().register(),
1648+
float_offset: inner.float_unification_table().register_watcher(),
16491649

1650-
const_offset: inner.const_unification_table().register(),
1650+
const_offset: inner.const_unification_table().register_watcher(),
16511651
}
16521652
}
16531653

@@ -1656,11 +1656,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16561656

16571657
inner.type_variables().deregister_unify_watcher(offset.ty_offset);
16581658

1659-
inner.int_unification_table().deregister(offset.int_offset);
1659+
inner.int_unification_table().deregister_watcher(offset.int_offset);
16601660

1661-
inner.float_unification_table().deregister(offset.float_offset);
1661+
inner.float_unification_table().deregister_watcher(offset.float_offset);
16621662

1663-
inner.const_unification_table().deregister(offset.const_offset);
1663+
inner.const_unification_table().deregister_watcher(offset.const_offset);
16641664
}
16651665

16661666
pub fn watch_variable(&self, infer: TyOrConstInferVar) {

compiler/rustc_infer/src/infer/type_variable.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -437,20 +437,16 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
437437
self.eq_relations().clear_modified_set();
438438
}
439439

440-
pub fn drain_modified_set(
441-
&mut self,
442-
offset: &ms::Offset<ty::TyVid>,
443-
f: impl FnMut(ty::TyVid) -> bool,
444-
) {
440+
pub fn drain_modified_set(&mut self, offset: &ms::Offset<ty::TyVid>, f: impl FnMut(ty::TyVid)) {
445441
self.eq_relations().drain_modified_set(offset, f)
446442
}
447443

448444
pub fn register_unify_watcher(&mut self) -> ms::Offset<ty::TyVid> {
449-
self.eq_relations().register()
445+
self.eq_relations().register_watcher()
450446
}
451447

452448
pub fn deregister_unify_watcher(&mut self, offset: ms::Offset<ty::TyVid>) {
453-
self.eq_relations().deregister(offset);
449+
self.eq_relations().deregister_watcher(offset);
454450
}
455451

456452
pub fn watch_variable(&mut self, vid: ty::TyVid) {

compiler/rustc_trait_selection/src/traits/fulfill.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
568568
fn unblocked(
569569
&self,
570570
offset: &WatcherOffset,
571-
f: impl FnMut(<Self::Obligation as ForestObligation>::Variable) -> bool,
571+
f: impl FnMut(<Self::Obligation as ForestObligation>::Variable),
572572
) {
573573
self.selcx.infcx().drain_modifications(offset, f);
574574
}

0 commit comments

Comments
 (0)