Revert "Revert "tamer: asg::graph::index: Use FxHashMap in place of Vec""

This reverts commit 1b7eac337cd5909c01ede3a5b3fba577898d5961.

This is a revert of the previous revert, just so that I (and you) have
references to prior rationale.

This was previously reverted because it wasn't worth doing, but now we have
a situation where we need to begin implementing lexical scoping rules for
nested containers (packages and templates).  In particular, as you'll see in
the commits that follow, we need to be able to look up an identifier that
may have been created as Missing at one level of scope (certain types of
blocks), but then define it at another level.

Or, even more simply at this point, since I'm not yet doing anything
sophisticated with scope: we're only indexing in the global environment, and
we need to be able to index elsewhere too.

The next commit will go into more information, but suffice it to say for now
that indexing is going to get more complicated than a SymbolId.

Sticking with FxHash for now; we don't need a stable hash now.

DEV-13708
main
Mike Gerwitz 2023-01-27 09:54:26 -05:00
parent 6d35e8776c
commit 5b0a4561a2
1 changed files with 8 additions and 34 deletions

View File

@ -39,6 +39,7 @@ use crate::{
span::Span,
sym::SymbolId,
};
use fxhash::FxHashMap;
use petgraph::{
graph::{DiGraph, Graph, NodeIndex},
visit::EdgeRef,
@ -109,10 +110,7 @@ pub struct Asg {
/// Note that,
/// while we store [`NodeIndex`] internally,
/// the public API encapsulates it within an [`ObjectIndex`].
index: Vec<NodeIndex<Ix>>,
/// Empty node indicating that no object exists for a given index.
empty_node: NodeIndex<Ix>,
index: FxHashMap<SymbolId, NodeIndex<Ix>>,
/// The root node used for reachability analysis and topological
/// sorting.
@ -164,12 +162,8 @@ impl Asg {
/// edge to another object.
pub fn with_capacity(objects: usize, edges: usize) -> Self {
let mut graph = Graph::with_capacity(objects, edges);
let mut index = Vec::with_capacity(objects);
// Exhaust the first index to be used as a placeholder
// (its value does not matter).
let empty_node = graph.add_node(Object::Root(Root).into());
index.push(empty_node);
let index =
FxHashMap::with_capacity_and_hasher(objects, Default::default());
// Automatically add the root which will be used to determine what
// identifiers ought to be retained by the final program.
@ -179,7 +173,6 @@ impl Asg {
Self {
graph,
index,
empty_node,
root_node,
}
}
@ -196,27 +189,11 @@ impl Asg {
/// After an identifier is indexed it is not expected to be reassigned
/// to another node.
/// Debug builds contain an assertion that will panic in this instance.
///
/// Panics
/// ======
/// Will panic if unable to allocate more space for the index.
fn index_identifier(&mut self, name: SymbolId, node: NodeIndex<Ix>) {
let i = name.as_usize();
if i >= self.index.len() {
// If this is ever a problem we can fall back to usize max and
// re-compare before panicing
let new_size = (i + 1)
.checked_next_power_of_two()
.expect("internal error: cannot allocate space for ASG index");
self.index.resize(new_size, self.empty_node);
}
let prev = self.index.insert(name, node);
// We should never overwrite indexes
debug_assert!(self.index[i] == self.empty_node);
self.index[i] = node;
debug_assert!(prev.is_none());
}
/// Lookup `ident` or add a missing identifier to the graph and return a
@ -727,12 +704,9 @@ impl Asg {
/// which is a package.
#[inline]
pub fn lookup_global(&self, id: SPair) -> Option<ObjectIndex<Ident>> {
let i = id.symbol().as_usize();
self.index
.get(i)
.filter(|ni| ni.index() > 0)
.map(|ni| ObjectIndex::new(*ni, id.span()))
.get(&id.symbol())
.map(|&ni| ObjectIndex::new(ni, id.span()))
}
/// Declare that `dep` is a dependency of `ident`.