[ty] Refactor covering node representation

This commit doesn't change any functionality, but instead changes the
representation of `CoveringNode` to make the implementation simpler (as
well as planned future additions). By putting the found node last in the
list of ancestors (now just generically called `nodes`), we reduce the
amount of special case handling we need.

The downside is that the representation now allows invalid states (a
`CoveringNode` with no elements). But I think this is well mitigated by
encapsulation.
This commit is contained in:
Andrew Gallant 2025-06-09 14:13:41 -04:00 committed by Andrew Gallant
parent e84406d8be
commit 65f32edbc7

View file

@ -49,48 +49,41 @@ pub(crate) fn covering_node(root: AnyNodeRef, range: TextRange) -> CoveringNode
}; };
root.visit_source_order(&mut visitor); root.visit_source_order(&mut visitor);
if visitor.ancestors.is_empty() {
let minimal = visitor.ancestors.pop().unwrap_or(root); visitor.ancestors.push(root);
}
CoveringNode { CoveringNode {
node: minimal, nodes: visitor.ancestors,
ancestors: visitor.ancestors,
} }
} }
/// The node with a minimal range that fully contains the search range. /// The node with a minimal range that fully contains the search range.
pub(crate) struct CoveringNode<'a> { pub(crate) struct CoveringNode<'a> {
/// The node with a minimal range that fully contains the search range. /// The covering node, along with all of its ancestors up to the
node: AnyNodeRef<'a>, /// root. The root is always the first element and the covering
/// node found is always the last node. This sequence is guaranteed
/// The node's ancestor (the spine up to the root). /// to be non-empty.
ancestors: Vec<AnyNodeRef<'a>>, nodes: Vec<AnyNodeRef<'a>>,
} }
impl<'a> CoveringNode<'a> { impl<'a> CoveringNode<'a> {
/// Returns the covering node found.
pub(crate) fn node(&self) -> AnyNodeRef<'a> { pub(crate) fn node(&self) -> AnyNodeRef<'a> {
self.node *self.nodes.last().unwrap()
} }
/// Returns the node's parent. /// Returns the node's parent.
pub(crate) fn parent(&self) -> Option<AnyNodeRef<'a>> { pub(crate) fn parent(&self) -> Option<AnyNodeRef<'a>> {
self.ancestors.last().copied() let penultimate = self.nodes.len().checked_sub(2)?;
self.nodes.get(penultimate).copied()
} }
/// Finds the minimal node that fully covers the range and fulfills the given predicate. /// Finds the minimal node that fully covers the range and fulfills the given predicate.
pub(crate) fn find(mut self, f: impl Fn(AnyNodeRef<'a>) -> bool) -> Result<Self, Self> { pub(crate) fn find(mut self, f: impl Fn(AnyNodeRef<'a>) -> bool) -> Result<Self, Self> {
if f(self.node) { match self.nodes.iter().rposition(|node| f(*node)) {
return Ok(self);
}
match self.ancestors.iter().rposition(|node| f(*node)) {
Some(index) => { Some(index) => {
let node = self.ancestors[index]; self.nodes.truncate(index + 1);
self.ancestors.truncate(index); Ok(self)
Ok(Self {
node,
ancestors: self.ancestors,
})
} }
None => Err(self), None => Err(self),
} }
@ -99,8 +92,6 @@ impl<'a> CoveringNode<'a> {
impl fmt::Debug for CoveringNode<'_> { impl fmt::Debug for CoveringNode<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("NodeWithAncestors") f.debug_tuple("CoveringNode").field(&self.node()).finish()
.field(&self.node)
.finish()
} }
} }