tamer: asg::graph::object: Move `lookup_local_linear` to `ObjectIndexRelTo`

This allows this method to be used on anything that is able to relate to an
identifier, which is needed for the changes being made for the template
system.

This linear lookup is actually going away (as hinted at by preceding
commits); this is extracted as part of a larger change and I wanted to get
it committed to make it easier to follow upcoming changes.

DEV-13708
main
Mike Gerwitz 2023-04-03 15:42:18 -04:00
parent 02dba0d63a
commit f1495f8cf4
2 changed files with 75 additions and 22 deletions

View File

@ -702,26 +702,12 @@ impl<O: ObjectKind> ObjectIndex<O> {
/// Attempt to look up a locally bound [`Ident`] via a linear search of
/// `self`'s edges.
///
/// Performance
/// ===========
/// _This is a linear (O(1)) search of the edges of the node
/// corresponding to `self`!_
/// At the time of writing,
/// edges are stored using index references in a manner similar to a
/// linked list (petgraph).
/// And for each such edge,
/// the target object must be resolved so that its
/// [`SymbolId`](crate::sym::SymbolId) may be retrieved and compared
/// against the provided `name`.
///
/// If the number of edges is small and the objects are fairly localized
/// in memory relative to `self`,
/// then this may not be a concern.
/// However,
/// if you've arrived at this method while investigating unfavorable
/// circumstances during profiling,
/// then you should consider caching like the global environment
/// (see [`Asg::lookup_global`]).
/// See [`ObjectIndexRelTo::lookup_local_linear`].
//
// TODO: This method exists here only as a fallback when Rust is unable
// to infer the proper type for [`ObjectIndexRelTo`].
// It can be removed once that is resolved;
// delete this method and compile to see.
pub fn lookup_local_linear(
&self,
asg: &Asg,
@ -730,8 +716,7 @@ impl<O: ObjectKind> ObjectIndex<O> {
where
O: ObjectRelTo<Ident>,
{
self.edges_filtered::<Ident>(asg)
.find(|oi| oi.resolve(asg).name().symbol() == name.symbol())
ObjectIndexRelTo::lookup_local_linear(self, asg, name)
}
/// Declare a local identifier.

View File

@ -225,6 +225,23 @@ impl<S> DynObjectRel<S, ObjectIndex<Object>> {
O::new_rel_dyn(self.target_ty(), *self.target())
}
/// Attempt to convert [`Self`] into an [`ObjectIndex`] with an
/// [`ObjectKind`] of type `O`.
///
/// This method allows marrying a dynamically determined type with a
/// context requiring a static type.
/// If the type `O` does not match the type stored at runtime,
/// [`None`] is returned.
pub fn filter_into_target<O: ObjectKind + ObjectRelatable>(
&self,
) -> Option<ObjectIndex<O>> {
if self.target_ty() == O::rel_ty() {
Some(self.target().must_narrow_into())
} else {
None
}
}
/// Pair the target [`ObjectIndex`] with its resolved [`Object`].
///
/// This allows the [`ObjectIndex`] to be refined alongside the inner
@ -609,6 +626,57 @@ pub trait ObjectIndexRelTo<OB: ObjectRelatable>: Sized + Clone + Copy {
self.add_edge_to(asg, oi, None)
}
/// Iterate over the [`ObjectIndex`]es of the outgoing edges of `self`
/// that match the [`ObjectKind`] `OB`.
///
/// Since this trait only guarantees edges to `OB`,
/// only edges targeting that type will be returned;
/// other types of edges may or may not exist.
/// See also [`ObjectIndex::edges_filtered`].
fn edges_rel_to<'a>(
&self,
asg: &'a Asg,
) -> impl Iterator<Item = ObjectIndex<OB>> + 'a {
asg.edges_dyn(self.widen())
.filter_map(|rel| rel.filter_into_target())
}
/// Attempt to look up a locally bound [`Ident`] via a linear search of
/// `self`'s edges.
///
/// Performance
/// ===========
/// _This is a linear (O(1)) search of the edges of the node
/// corresponding to `self`!_
/// At the time of writing,
/// edges are stored using index references in a manner similar to a
/// linked list (petgraph).
/// And for each such edge,
/// the target object must be resolved so that its
/// [`SymbolId`](crate::sym::SymbolId) may be retrieved and compared
/// against the provided `name`.
///
/// If the number of edges is small and the objects are fairly localized
/// in memory relative to `self`,
/// then this may not be a concern.
/// However,
/// if you've arrived at this method while investigating unfavorable
/// circumstances during profiling,
/// then you should consider caching like the global environment
/// (see [`Asg::lookup_global`]).
fn lookup_local_linear(
&self,
asg: &Asg,
name: SPair,
) -> Option<ObjectIndex<Ident>>
where
Self: ObjectIndexRelTo<Ident>,
{
// Rust fails to infer OB with `self.edges_rel_to` as of 2023-03
ObjectIndexRelTo::<Ident>::edges_rel_to(self, asg)
.find(|oi| oi.resolve(asg).name().symbol() == name.symbol())
}
/// Declare a local identifier.
///
/// A local identifier is lexically scoped to `self`.