Skip to content

Commit

Permalink
Redefine NodeIndex as a newtype_index!.
Browse files Browse the repository at this point in the history
This commit removes the custom index implementation of `NodeIndex`,
which probably predates `newtype_index!`.

As well as eliminating code, it improves the debugging experience,
because the custom implementation had the property of being incremented
by 1 (so it could use `NonZeroU32`), which was incredibly confusing if
you didn't expect it.

For some reason, I also had to remove an `unsafe` block marker from
`from_u32_unchecked()` that the compiler said was now unnecessary.
  • Loading branch information
nnethercote committed Sep 16, 2019
1 parent 04b1111 commit 43c0d2c
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 42 deletions.
2 changes: 1 addition & 1 deletion src/librustc_data_structures/indexed_vec.rs
Expand Up @@ -149,7 +149,7 @@ macro_rules! newtype_index {

#[inline]
$v const unsafe fn from_u32_unchecked(value: u32) -> Self {
unsafe { $type { private: value } }
$type { private: value }
}

/// Extracts the value of this index as an integer.
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_data_structures/obligation_forest/graphviz.rs
Expand Up @@ -74,9 +74,9 @@ impl<'a, O: ForestObligation + 'a> dot::GraphWalk<'a> for &'a ObligationForest<O
.flat_map(|i| {
let node = &self.nodes[i];

node.parent.iter().map(|p| p.get())
.chain(node.dependents.iter().map(|p| p.get()))
.map(move |p| (p, i))
node.parent.iter()
.chain(node.dependents.iter())
.map(move |p| (p.index(), i))
})
.collect()
}
Expand Down
49 changes: 31 additions & 18 deletions src/librustc_data_structures/obligation_forest/mod.rs
Expand Up @@ -81,21 +81,24 @@
//! nodes, which aren't needed anymore.

use crate::fx::{FxHashMap, FxHashSet};
use crate::indexed_vec::Idx;
use crate::newtype_index;

use std::cell::Cell;
use std::collections::hash_map::Entry;
use std::fmt::Debug;
use std::hash;
use std::marker::PhantomData;

mod node_index;
use self::node_index::NodeIndex;

mod graphviz;

#[cfg(test)]
mod tests;

newtype_index! {
pub struct NodeIndex { .. }
}

pub trait ForestObligation : Clone + Debug {
type Predicate : Clone + hash::Hash + Eq + Debug;

Expand Down Expand Up @@ -151,6 +154,10 @@ pub struct ObligationForest<O: ForestObligation> {
/// At all times we maintain the invariant that every node appears
/// at a higher index than its parent. This is needed by the
/// backtrace iterator (which uses `split_at`).
///
/// Ideally, this would be an `IndexVec<NodeIndex, Node<O>>`. But that is
/// slower, because this vector is accessed so often that the
/// `u32`-to-`usize` conversions required for accesses are significant.
nodes: Vec<Node<O>>,

/// A cache of predicates that have been successfully completed.
Expand Down Expand Up @@ -178,13 +185,19 @@ struct Node<O> {
obligation: O,
state: Cell<NodeState>,

/// The parent of a node - the original obligation of
/// which it is a subobligation. Except for error reporting,
/// it is just like any member of `dependents`.
/// The parent of a node - the original obligation of which it is a
/// subobligation. Except for error reporting, it is just like any member
/// of `dependents`.
///
/// Unlike `ObligationForest::nodes`, this uses `NodeIndex` rather than
/// `usize` for the index, because keeping the size down is more important
/// than the cost of converting to a `usize` for indexing.
parent: Option<NodeIndex>,

/// Obligations that depend on this obligation for their
/// completion. They must all be in a non-pending state.
/// Obligations that depend on this obligation for their completion. They
/// must all be in a non-pending state.
///
/// This uses `NodeIndex` for the same reason as `parent`.
dependents: Vec<NodeIndex>,

/// Identifier of the obligation tree to which this node belongs.
Expand Down Expand Up @@ -294,7 +307,7 @@ impl<O: ForestObligation> ObligationForest<O> {
Entry::Occupied(o) => {
debug!("register_obligation_at({:?}, {:?}) - duplicate of {:?}!",
obligation, parent, o.get());
let node = &mut self.nodes[o.get().get()];
let node = &mut self.nodes[o.get().index()];
if let Some(parent_index) = parent {
// If the node is already in `waiting_cache`, it's already
// been marked with a parent. (It's possible that parent
Expand All @@ -318,7 +331,7 @@ impl<O: ForestObligation> ObligationForest<O> {

let obligation_tree_id = match parent {
Some(parent_index) => {
self.nodes[parent_index.get()].obligation_tree_id
self.nodes[parent_index.index()].obligation_tree_id
}
None => self.obligation_tree_id_generator.next().unwrap()
};
Expand Down Expand Up @@ -506,7 +519,7 @@ impl<O: ForestObligation> ObligationForest<O> {
node.state.set(NodeState::OnDfsStack);
stack.push(i);
for index in node.parent.iter().chain(node.dependents.iter()) {
self.find_cycles_from_node(stack, processor, index.get());
self.find_cycles_from_node(stack, processor, index.index());
}
stack.pop();
node.state.set(NodeState::Done);
Expand All @@ -531,11 +544,11 @@ impl<O: ForestObligation> ObligationForest<O> {
let node = &self.nodes[i];
node.state.set(NodeState::Error);
trace.push(node.obligation.clone());
error_stack.extend(node.dependents.iter().map(|index| index.get()));
error_stack.extend(node.dependents.iter().map(|index| index.index()));

// Loop to the parent.
match node.parent {
Some(parent_index) => i = parent_index.get(),
Some(parent_index) => i = parent_index.index(),
None => break
}
}
Expand All @@ -548,7 +561,7 @@ impl<O: ForestObligation> ObligationForest<O> {
}

error_stack.extend(
node.parent.iter().chain(node.dependents.iter()).map(|index| index.get())
node.parent.iter().chain(node.dependents.iter()).map(|index| index.index())
);
}

Expand All @@ -560,7 +573,7 @@ impl<O: ForestObligation> ObligationForest<O> {
#[inline(always)]
fn inlined_mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
for dependent in node.parent.iter().chain(node.dependents.iter()) {
self.mark_as_waiting_from(&self.nodes[dependent.get()]);
self.mark_as_waiting_from(&self.nodes[dependent.index()]);
}
}

Expand Down Expand Up @@ -686,7 +699,7 @@ impl<O: ForestObligation> ObligationForest<O> {

for node in &mut self.nodes {
if let Some(index) = node.parent {
let new_i = node_rewrites[index.get()];
let new_i = node_rewrites[index.index()];
if new_i >= nodes_len {
// parent dead due to error
node.parent = None;
Expand All @@ -697,7 +710,7 @@ impl<O: ForestObligation> ObligationForest<O> {

let mut i = 0;
while i < node.dependents.len() {
let new_i = node_rewrites[node.dependents[i].get()];
let new_i = node_rewrites[node.dependents[i].index()];
if new_i >= nodes_len {
node.dependents.swap_remove(i);
} else {
Expand All @@ -709,7 +722,7 @@ impl<O: ForestObligation> ObligationForest<O> {

let mut kill_list = vec![];
for (predicate, index) in &mut self.waiting_cache {
let new_i = node_rewrites[index.get()];
let new_i = node_rewrites[index.index()];
if new_i >= nodes_len {
kill_list.push(predicate.clone());
} else {
Expand Down
20 changes: 0 additions & 20 deletions src/librustc_data_structures/obligation_forest/node_index.rs

This file was deleted.

0 comments on commit 43c0d2c

Please sign in to comment.