tamer: asg::graph: Strict static enforcement of tree/cross edge spans
We are now able to have confidence that the graph is properly constructed with or without a reference span depending on whether the edge is a tree or cross edge. Consequently, the span is now a reliable indicator of whether an edge is tree or cross in _all_ cases, not just in dynamic ones. In fact, this did catch a couple cases where the spans were _not_ properly applied. This will in turn give me confidence moving forward with static analysis based on the graph (and edge hooks). I could go further than this by introducing a new span type in place of `Option<Span>`, which would also allow me to get rid of having two methods on `Asg`, but I want to move on for now; this can be cleaned up more later on. It's also worth noting that this explicit method-based distinction between edge types also means that each caller will carefully consider how the operation affects the graph. Previously, that consideration was framed very differently: "do I need a contextual span or not?". That's not the right question to ask. DEV-13163main
parent
c0ba827d90
commit
9f74c0fc92
|
@ -863,7 +863,7 @@ impl AirAggregateCtx {
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
oi_pkg.root(&mut self.asg)?;
|
oi_pkg.root_tree(&mut self.asg)?;
|
||||||
self.ooi_pkg.replace(oi_pkg);
|
self.ooi_pkg.replace(oi_pkg);
|
||||||
|
|
||||||
Ok(oi_pkg)
|
Ok(oi_pkg)
|
||||||
|
@ -921,7 +921,7 @@ impl AirAggregateCtx {
|
||||||
/// A value of [`None`] indicates that expressions are not permitted to
|
/// A value of [`None`] indicates that expressions are not permitted to
|
||||||
/// dangle in the current context
|
/// dangle in the current context
|
||||||
/// (and so must be identified).
|
/// (and so must be identified).
|
||||||
fn dangling_expr_oi(&self) -> Option<ObjectIndexTo<Expr>> {
|
fn dangling_expr_oi(&self) -> Option<ObjectIndexToTree<Expr>> {
|
||||||
use AirAggregate::*;
|
use AirAggregate::*;
|
||||||
|
|
||||||
self.stack.iter().rev().find_map(|st| match st {
|
self.stack.iter().rev().find_map(|st| match st {
|
||||||
|
@ -963,7 +963,7 @@ impl AirAggregateCtx {
|
||||||
///
|
///
|
||||||
/// A value of [`None`] indicates that template expansion is not
|
/// A value of [`None`] indicates that template expansion is not
|
||||||
/// permitted in this current context.
|
/// permitted in this current context.
|
||||||
fn expansion_oi(&self) -> Option<ObjectIndexTo<Tpl>> {
|
fn expansion_oi(&self) -> Option<ObjectIndexToTree<Tpl>> {
|
||||||
use AirAggregate::*;
|
use AirAggregate::*;
|
||||||
|
|
||||||
self.stack.iter().rev().find_map(|st| match st {
|
self.stack.iter().rev().find_map(|st| match st {
|
||||||
|
|
|
@ -30,7 +30,7 @@ use super::{
|
||||||
AirAggregate, AirAggregateCtx,
|
AirAggregate, AirAggregateCtx,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
asg::{graph::object::ObjectIndexTo, ObjectKind},
|
asg::{graph::object::ObjectIndexToTree, ObjectKind},
|
||||||
f::Map,
|
f::Map,
|
||||||
parse::prelude::*,
|
parse::prelude::*,
|
||||||
};
|
};
|
||||||
|
@ -204,7 +204,7 @@ impl AirExprAggregate {
|
||||||
/// then an [`AsgError::DanglingExpr`] will be returned.
|
/// then an [`AsgError::DanglingExpr`] will be returned.
|
||||||
fn hold_dangling(
|
fn hold_dangling(
|
||||||
asg: &mut Asg,
|
asg: &mut Asg,
|
||||||
oi_root: Option<ObjectIndexTo<Expr>>,
|
oi_root: Option<ObjectIndexToTree<Expr>>,
|
||||||
oi_expr: ObjectIndex<Expr>,
|
oi_expr: ObjectIndex<Expr>,
|
||||||
) -> Result<(), AsgError> {
|
) -> Result<(), AsgError> {
|
||||||
let oi_container = oi_root
|
let oi_container = oi_root
|
||||||
|
|
|
@ -88,7 +88,7 @@ impl ParseState for AirOpaqueAggregate {
|
||||||
|
|
||||||
(Ready, IdentRoot(name)) => ctx
|
(Ready, IdentRoot(name)) => ctx
|
||||||
.lookup_lexical_or_missing(name)
|
.lookup_lexical_or_missing(name)
|
||||||
.root(ctx.asg_mut())
|
.root_cross(ctx.asg_mut())
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.transition(Ready),
|
.transition(Ready),
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
//! ![Visualization of ASG ontology](../ontviz.svg)
|
//! ![Visualization of ASG ontology](../ontviz.svg)
|
||||||
|
|
||||||
use self::object::{
|
use self::object::{
|
||||||
DynObjectRel, ObjectIndexRelTo, ObjectRelFrom, ObjectRelTy,
|
DynObjectRel, ObjectIndexCrossRelTo, ObjectIndexRelTo,
|
||||||
ObjectRelatable, Root,
|
ObjectIndexTreeRelTo, ObjectRelFrom, ObjectRelTy, ObjectRelatable, Root,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AsgError, Object, ObjectIndex, ObjectKind};
|
use super::{AsgError, Object, ObjectIndex, ObjectKind};
|
||||||
|
@ -190,32 +190,74 @@ impl Asg {
|
||||||
ObjectIndex::new(node_id, span)
|
ObjectIndex::new(node_id, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an edge from the [`Object`] represented by the
|
/// Add a tree edge from the [`Object`] represented by the
|
||||||
/// [`ObjectIndex`] `from_oi` to the object represented by `to_oi`.
|
/// [`ObjectIndex`] `from_oi` to the object represented by `to_oi`.
|
||||||
///
|
///
|
||||||
/// The edge may optionally contain a _contextual [`Span`]_,
|
/// A tree edge represents _ownership_ over the target object
|
||||||
/// in cases where it is important to distinguish between the span
|
/// (`from_oi` owns `to_oi`),
|
||||||
/// associated with the target and the span associated with the
|
/// forming a tree parent/child relationships between objects.
|
||||||
/// _reference_ to the target.
|
/// To reference objects from other trees
|
||||||
|
/// (crossing trees),
|
||||||
|
/// see [`Self::add_cross_edge`].
|
||||||
///
|
///
|
||||||
/// For more information on how the ASG's ontology is enforced statically,
|
/// For more information on how the ASG's ontology is enforced statically,
|
||||||
/// see [`ObjectRelTo`](object::ObjectRelTo).
|
/// see [`object`].
|
||||||
///
|
///
|
||||||
/// Callers external to this module should use [`ObjectIndex`] APIs to
|
/// Callers external to this module should use [`ObjectIndex`] APIs to
|
||||||
/// manipulate the graph;
|
/// manipulate the graph;
|
||||||
/// this allows those objects to uphold their own invariants
|
/// this allows those objects to uphold their own invariants
|
||||||
/// relative to the state of the graph.
|
/// relative to the state of the graph.
|
||||||
fn add_edge<OA: ObjectIndexRelTo<OB>, OB: ObjectKind + ObjectRelatable>(
|
fn add_tree_edge<
|
||||||
|
OA: ObjectIndexTreeRelTo<OB>,
|
||||||
|
OB: ObjectKind + ObjectRelatable,
|
||||||
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
from_oi: OA,
|
from_oi: OA,
|
||||||
to_oi: ObjectIndex<OB>,
|
to_oi: ObjectIndex<OB>,
|
||||||
ref_span: Option<Span>,
|
|
||||||
) -> Result<(), AsgError> {
|
) -> Result<(), AsgError> {
|
||||||
from_oi.pre_add_edge(self, to_oi, ref_span, |asg| {
|
from_oi.pre_add_edge(self, to_oi, None, |asg| {
|
||||||
asg.graph.add_edge(
|
asg.graph.add_edge(
|
||||||
from_oi.widen().into(),
|
from_oi.widen().into(),
|
||||||
to_oi.into(),
|
to_oi.into(),
|
||||||
(from_oi.src_rel_ty(), OB::rel_ty(), ref_span),
|
(from_oi.src_rel_ty(), OB::rel_ty(), None),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a cross edge from the [`Object`] represented by the
|
||||||
|
/// [`ObjectIndex`] `from_oi` to the object represented by `to_oi`.
|
||||||
|
///
|
||||||
|
/// A cross edge represents a _reference_ to another object,
|
||||||
|
/// crossing into another tree.
|
||||||
|
/// To indicate ownership,
|
||||||
|
/// see [`Self::add_tree_edge`].
|
||||||
|
///
|
||||||
|
/// The edge must contain a _reference [`Span`]_,
|
||||||
|
/// which represents the location of the reference _to_ the
|
||||||
|
/// object `to_oi`,
|
||||||
|
/// rather than the object itself.
|
||||||
|
///
|
||||||
|
/// For more information on how the ASG's ontology is enforced statically,
|
||||||
|
/// see [`object`].
|
||||||
|
///
|
||||||
|
/// Callers external to this module should use [`ObjectIndex`] APIs to
|
||||||
|
/// manipulate the graph;
|
||||||
|
/// this allows those objects to uphold their own invariants
|
||||||
|
/// relative to the state of the graph.
|
||||||
|
fn add_cross_edge<
|
||||||
|
OA: ObjectIndexCrossRelTo<OB>,
|
||||||
|
OB: ObjectKind + ObjectRelatable,
|
||||||
|
>(
|
||||||
|
&mut self,
|
||||||
|
from_oi: OA,
|
||||||
|
to_oi: ObjectIndex<OB>,
|
||||||
|
ref_span: Span,
|
||||||
|
) -> Result<(), AsgError> {
|
||||||
|
from_oi.pre_add_edge(self, to_oi, Some(ref_span), |asg| {
|
||||||
|
asg.graph.add_edge(
|
||||||
|
from_oi.widen().into(),
|
||||||
|
to_oi.into(),
|
||||||
|
(from_oi.src_rel_ty(), OB::rel_ty(), Some(ref_span)),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -409,9 +451,11 @@ fn diagnostic_node_missing_desc<O: ObjectKind>(
|
||||||
///
|
///
|
||||||
/// How Does This Work With Trait Specialization?
|
/// How Does This Work With Trait Specialization?
|
||||||
/// =============================================
|
/// =============================================
|
||||||
/// [`Asg::add_edge`] is provided a [`ObjectIndexRelTo`],
|
/// [`Asg::add_tree_edge`]/[`Asg::add_cross_edge`] is provided a
|
||||||
/// which needs narrowing to an appropriate source [`ObjectKind`] so that
|
/// [`ObjectIndexRelTo`],
|
||||||
/// we can invoke [`<O as AsgRelMut>::pre_add_edge`](AsgRelMut::pre_add_edge).
|
/// which needs narrowing to an appropriate source [`ObjectKind`] so
|
||||||
|
/// that we can invoke
|
||||||
|
/// [`<O as AsgRelMut>::pre_add_edge`](AsgRelMut::pre_add_edge).
|
||||||
///
|
///
|
||||||
/// At the time of writing,
|
/// At the time of writing,
|
||||||
/// there are two implementors of [`ObjectIndexRelTo`]:
|
/// there are two implementors of [`ObjectIndexRelTo`]:
|
||||||
|
@ -469,7 +513,8 @@ fn diagnostic_node_missing_desc<O: ObjectKind>(
|
||||||
/// and uses the appropriate specialization.
|
/// and uses the appropriate specialization.
|
||||||
///
|
///
|
||||||
/// Because of other trait bounds leading up to this point,
|
/// Because of other trait bounds leading up to this point,
|
||||||
/// including those on [`Asg::add_edge`] and [`ObjectIndexRelTo`],
|
/// including those on [`Asg::add_tree_edge`]/[`Asg::add_cross_edge`] and
|
||||||
|
/// [`ObjectIndexRelTo`],
|
||||||
/// this cannot be invoked for any `to_oi` that is not a valid target
|
/// this cannot be invoked for any `to_oi` that is not a valid target
|
||||||
/// for `Self`.
|
/// for `Self`.
|
||||||
/// But we cannot be too strict on that bound _here_,
|
/// But we cannot be too strict on that bound _here_,
|
||||||
|
@ -499,14 +544,15 @@ pub trait AsgRelMut<OB: ObjectRelatable>: ObjectRelatable {
|
||||||
/// since the [`ObjectIndex`] APIs may not be utilized
|
/// since the [`ObjectIndex`] APIs may not be utilized
|
||||||
/// (e.g. in the case of [`ObjectIndexRelTo`].
|
/// (e.g. in the case of [`ObjectIndexRelTo`].
|
||||||
///
|
///
|
||||||
/// This is invoked by [`Asg::add_edge`].
|
/// This is invoked by [`Asg::add_tree_edge`] and
|
||||||
|
/// [`Asg::add_cross_edge`].
|
||||||
/// The provided `commit` callback will complete the addition of the
|
/// The provided `commit` callback will complete the addition of the
|
||||||
/// edge if provided [`Ok`],
|
/// edge if provided [`Ok`],
|
||||||
/// and the commit cannot fail.
|
/// and the commit cannot fail.
|
||||||
/// If [`Err`] is provided to `commit`,
|
/// If [`Err`] is provided to `commit`,
|
||||||
/// then [`Asg::add_edge`] will fail with that error.
|
/// then the calling [`Asg`] method will fail with that error.
|
||||||
///
|
///
|
||||||
/// Unlike the type of [`Asg::add_edge`],
|
/// Unlike the type of [`Asg::add_tree_edge`]/[`Asg::add_cross_edge`],
|
||||||
/// the source [`ObjectIndex`] has been narrowed to the appropriate
|
/// the source [`ObjectIndex`] has been narrowed to the appropriate
|
||||||
/// type for you.
|
/// type for you.
|
||||||
fn pre_add_edge(
|
fn pre_add_edge(
|
||||||
|
@ -537,11 +583,19 @@ impl<OA: ObjectRelatable, OB: ObjectRelatable> AsgRelMut<OB> for OA {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The relationship proposed by [`Asg::add_edge`],
|
/// The relationship proposed by [`Asg::add_tree_edge`] or
|
||||||
|
/// [`Asg::add_cross_edge`],
|
||||||
/// requiring approval from [`AsgRelMut::pre_add_edge`].
|
/// requiring approval from [`AsgRelMut::pre_add_edge`].
|
||||||
pub struct ProposedRel<OA: ObjectKind, OB: ObjectKind> {
|
pub struct ProposedRel<OA: ObjectKind, OB: ObjectKind> {
|
||||||
from_oi: ObjectIndex<OA>,
|
from_oi: ObjectIndex<OA>,
|
||||||
to_oi: ObjectIndex<OB>,
|
to_oi: ObjectIndex<OB>,
|
||||||
|
|
||||||
|
/// Reference span.
|
||||||
|
///
|
||||||
|
/// This will be [`Some`] by [`Asg::add_cross_edge`],
|
||||||
|
/// but will always be [`None`] via [`Asg::add_tree_edge`].
|
||||||
|
/// This can therefore be used to determine whether an edge is a tree or
|
||||||
|
/// a cross edge.
|
||||||
ref_span: Option<Span>,
|
ref_span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,9 +152,10 @@ pub use ident::Ident;
|
||||||
pub use meta::Meta;
|
pub use meta::Meta;
|
||||||
pub use pkg::Pkg;
|
pub use pkg::Pkg;
|
||||||
pub use rel::{
|
pub use rel::{
|
||||||
DynObjectRel, ObjectIndexRelTo, ObjectIndexTo, ObjectIndexToTree,
|
DynObjectRel, ObjectCrossRelTo, ObjectIndexCrossRelTo, ObjectIndexRelTo,
|
||||||
ObjectIndexTreeRelTo, ObjectRel, ObjectRelFrom, ObjectRelTo, ObjectRelTy,
|
ObjectIndexTo, ObjectIndexToCross, ObjectIndexToTree, ObjectIndexTreeRelTo,
|
||||||
ObjectRelatable, ObjectTreeRelTo,
|
ObjectRel, ObjectRelFrom, ObjectRelTo, ObjectRelTy, ObjectRelatable,
|
||||||
|
ObjectTreeRelTo,
|
||||||
};
|
};
|
||||||
pub use root::Root;
|
pub use root::Root;
|
||||||
pub use tpl::Tpl;
|
pub use tpl::Tpl;
|
||||||
|
@ -163,9 +164,10 @@ pub use tpl::Tpl;
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use super::{
|
pub use super::{
|
||||||
super::{super::error::AsgError, Asg, AsgRelMut},
|
super::{super::error::AsgError, Asg, AsgRelMut},
|
||||||
Object, ObjectIndex, ObjectIndexRelTo, ObjectKind, ObjectRel,
|
Object, ObjectCrossRelTo, ObjectIndex, ObjectIndexCrossRelTo,
|
||||||
ObjectRelFrom, ObjectRelTo, ObjectRelTy, ObjectRelatable,
|
ObjectIndexRelTo, ObjectIndexToCross, ObjectIndexToTree,
|
||||||
ObjectTreeRelTo,
|
ObjectIndexTreeRelTo, ObjectKind, ObjectRel, ObjectRelFrom,
|
||||||
|
ObjectRelTo, ObjectRelTy, ObjectRelatable, ObjectTreeRelTo,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,52 +595,81 @@ impl<O: ObjectKind> ObjectIndex<O> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an edge from `self` to `to_oi` on the provided [`Asg`].
|
/// Add a tree edge from `self` to `to_oi` on the provided [`Asg`].
|
||||||
///
|
///
|
||||||
/// Since the only invariant asserted by [`ObjectIndexRelTo`] is that
|
/// See also [`Self::add_tree_edge_from`].
|
||||||
/// it may be related to `OB`,
|
|
||||||
/// this method will only permit edges to `OB`;
|
|
||||||
/// nothing else about the inner object is statically known.
|
|
||||||
///
|
|
||||||
/// See also [`Self::add_edge_from`].
|
|
||||||
///
|
///
|
||||||
/// _This method must remain private_,
|
/// _This method must remain private_,
|
||||||
/// forcing callers to go through APIs for specific operations that
|
/// forcing callers to go through APIs for specific operations that
|
||||||
/// allow objects to enforce their own invariants.
|
/// allow objects to enforce their own invariants.
|
||||||
/// This is also the reason why this method is defined here rather than
|
/// This is also the reason why this method is defined here rather than
|
||||||
/// on [`ObjectIndexRelTo`].
|
/// on [`ObjectIndexRelTo`].
|
||||||
fn add_edge_to<OB: ObjectRelatable>(
|
fn add_tree_edge_to<OB: ObjectRelatable>(
|
||||||
self,
|
self,
|
||||||
asg: &mut Asg,
|
asg: &mut Asg,
|
||||||
to_oi: ObjectIndex<OB>,
|
to_oi: ObjectIndex<OB>,
|
||||||
ctx_span: Option<Span>,
|
|
||||||
) -> Result<Self, AsgError>
|
) -> Result<Self, AsgError>
|
||||||
where
|
where
|
||||||
Self: ObjectIndexRelTo<OB>,
|
Self: ObjectIndexTreeRelTo<OB>,
|
||||||
{
|
{
|
||||||
asg.add_edge(self, to_oi, ctx_span).map(|()| self)
|
asg.add_tree_edge(self, to_oi).map(|()| self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an edge from `from_oi` to `self` on the provided [`Asg`].
|
/// Add a tree edge from `from_oi` to `self` on the provided [`Asg`].
|
||||||
///
|
///
|
||||||
/// An edge can only be added if ontologically valid;
|
/// An edge can only be added if ontologically valid;
|
||||||
/// see [`ObjectRelTo`] for more information.
|
/// see [`ObjectRelTo`] for more information.
|
||||||
///
|
///
|
||||||
/// See also [`Self::add_edge_to`].
|
/// See also [`Self::add_tree_edge_to`].
|
||||||
///
|
///
|
||||||
/// _This method must remain private_,
|
/// _This method must remain private_,
|
||||||
/// forcing callers to go through APIs for specific operations that
|
/// forcing callers to go through APIs for specific operations that
|
||||||
/// allow objects to enforce their own invariants.
|
/// allow objects to enforce their own invariants.
|
||||||
fn add_edge_from<OA: ObjectIndexRelTo<O>>(
|
fn add_tree_edge_from<OA: ObjectIndexTreeRelTo<O>>(
|
||||||
self,
|
self,
|
||||||
asg: &mut Asg,
|
asg: &mut Asg,
|
||||||
from_oi: OA,
|
from_oi: OA,
|
||||||
ctx_span: Option<Span>,
|
|
||||||
) -> Result<Self, AsgError>
|
) -> Result<Self, AsgError>
|
||||||
where
|
where
|
||||||
O: ObjectRelatable,
|
O: ObjectRelatable,
|
||||||
{
|
{
|
||||||
asg.add_edge(from_oi, self, ctx_span).map(|()| self)
|
asg.add_tree_edge(from_oi, self).map(|()| self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a cross edge from `self` to `to_oi` on the provided [`Asg`].
|
||||||
|
///
|
||||||
|
/// For more information,
|
||||||
|
/// see [`Self::add_tree_edge_to`].
|
||||||
|
///
|
||||||
|
/// See also [`Self::add_cross_edge_from`].
|
||||||
|
fn add_cross_edge_to<OB: ObjectRelatable>(
|
||||||
|
self,
|
||||||
|
asg: &mut Asg,
|
||||||
|
to_oi: ObjectIndex<OB>,
|
||||||
|
ref_span: Span,
|
||||||
|
) -> Result<Self, AsgError>
|
||||||
|
where
|
||||||
|
Self: ObjectIndexCrossRelTo<OB>,
|
||||||
|
{
|
||||||
|
asg.add_cross_edge(self, to_oi, ref_span).map(|()| self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a cross edge from `from_oi` to `self` on the provided [`Asg`].
|
||||||
|
///
|
||||||
|
/// For more information,
|
||||||
|
/// see [`Self::add_tree_edge_from`].
|
||||||
|
///
|
||||||
|
/// See also [`Self::add_cross_edge_to`].
|
||||||
|
fn add_cross_edge_from<OA: ObjectIndexCrossRelTo<O>>(
|
||||||
|
self,
|
||||||
|
asg: &mut Asg,
|
||||||
|
from_oi: OA,
|
||||||
|
ref_span: Span,
|
||||||
|
) -> Result<Self, AsgError>
|
||||||
|
where
|
||||||
|
O: ObjectRelatable,
|
||||||
|
{
|
||||||
|
asg.add_cross_edge(from_oi, self, ref_span).map(|()| self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an iterator over the [`ObjectIndex`]es of the outgoing edges
|
/// Create an iterator over the [`ObjectIndex`]es of the outgoing edges
|
||||||
|
@ -813,7 +844,24 @@ impl<O: ObjectKind> ObjectIndex<O> {
|
||||||
.filter(|_| O::rel_ty() == OB::rel_ty())
|
.filter(|_| O::rel_ty() == OB::rel_ty())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Root this object in the ASG's [`Root`] object.
|
/// Root this object in the ASG's [`Root`] object,
|
||||||
|
/// acting as an owner of the object.
|
||||||
|
///
|
||||||
|
/// This is intended for rooting toplevel objects that otherwise have no
|
||||||
|
/// owner for a given compilation unit,
|
||||||
|
/// allowing them to be reachable from the graph root.
|
||||||
|
///
|
||||||
|
/// See also [`Self::root_cross`].
|
||||||
|
pub fn root_tree(self, asg: &mut Asg) -> Result<Self, AsgError>
|
||||||
|
where
|
||||||
|
Root: ObjectTreeRelTo<O>,
|
||||||
|
{
|
||||||
|
asg.root(self.span())
|
||||||
|
.add_tree_edge_to(asg, self)
|
||||||
|
.map(|_| self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Root a reference to this object in the ASG's [`Root`] object.
|
||||||
///
|
///
|
||||||
/// A rooted object is forced to be reachable.
|
/// A rooted object is forced to be reachable.
|
||||||
/// This should only be utilized when necessary for toplevel objects;
|
/// This should only be utilized when necessary for toplevel objects;
|
||||||
|
@ -821,18 +869,21 @@ impl<O: ObjectKind> ObjectIndex<O> {
|
||||||
/// objects.
|
/// objects.
|
||||||
/// Forcing objects to be reachable can prevent them from being
|
/// Forcing objects to be reachable can prevent them from being
|
||||||
/// optimized away if they are not used.
|
/// optimized away if they are not used.
|
||||||
pub fn root(self, asg: &mut Asg) -> Result<Self, AsgError>
|
///
|
||||||
|
/// See also [`Self::root_tree`].
|
||||||
|
pub fn root_cross(self, asg: &mut Asg) -> Result<Self, AsgError>
|
||||||
where
|
where
|
||||||
Root: ObjectRelTo<O>,
|
Root: ObjectCrossRelTo<O>,
|
||||||
{
|
{
|
||||||
asg.root(self.span())
|
asg.root(self.span())
|
||||||
.add_edge_to(asg, self, None)
|
.add_cross_edge_to(asg, self, self.span())
|
||||||
.map(|_| self)
|
.map(|_| self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this object has been rooted in the ASG's [`Root`] object.
|
/// Whether this object has been rooted in the ASG's [`Root`] object.
|
||||||
///
|
///
|
||||||
/// See [`Self::root`] for more information.
|
/// See [`Self::root_tree`] and [`Self::root_cross`] for more
|
||||||
|
/// information.
|
||||||
pub fn is_rooted(&self, asg: &Asg) -> bool
|
pub fn is_rooted(&self, asg: &Asg) -> bool
|
||||||
where
|
where
|
||||||
Root: ObjectRelTo<O>,
|
Root: ObjectRelTo<O>,
|
||||||
|
@ -910,7 +961,7 @@ impl<O: ObjectKind> ObjectIndex<O> {
|
||||||
oi: ObjectIndex<Ident>,
|
oi: ObjectIndex<Ident>,
|
||||||
) -> Result<Self, AsgError>
|
) -> Result<Self, AsgError>
|
||||||
where
|
where
|
||||||
Self: ObjectIndexRelTo<Ident>,
|
Self: ObjectIndexTreeRelTo<Ident>,
|
||||||
{
|
{
|
||||||
oi.defined_by(asg, self).map(|_| self)
|
oi.defined_by(asg, self).map(|_| self)
|
||||||
}
|
}
|
||||||
|
@ -927,10 +978,10 @@ impl<O: ObjectKind> ObjectIndex<O> {
|
||||||
clause: SPair,
|
clause: SPair,
|
||||||
) -> Result<Self, AsgError>
|
) -> Result<Self, AsgError>
|
||||||
where
|
where
|
||||||
O: ObjectRelTo<Doc>,
|
O: ObjectTreeRelTo<Doc>,
|
||||||
{
|
{
|
||||||
let oi_doc = asg.create(Doc::new_indep_clause(clause));
|
let oi_doc = asg.create(Doc::new_indep_clause(clause));
|
||||||
self.add_edge_to(asg, oi_doc, None)
|
self.add_tree_edge_to(asg, oi_doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve a description of this expression using a short independent
|
/// Retrieve a description of this expression using a short independent
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
//! Expressions on the ASG.
|
//! Expressions on the ASG.
|
||||||
|
|
||||||
use super::{prelude::*, Doc, Ident, ObjectIndexTo, Tpl};
|
use super::{prelude::*, Doc, Ident, ObjectIndexToTree, Tpl};
|
||||||
use crate::{f::Map, num::Dim, span::Span};
|
use crate::{f::Map, num::Dim, span::Span};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ impl ObjectIndex<Expr> {
|
||||||
expr: Expr,
|
expr: Expr,
|
||||||
) -> Result<ObjectIndex<Expr>, AsgError> {
|
) -> Result<ObjectIndex<Expr>, AsgError> {
|
||||||
let oi_subexpr = asg.create(expr);
|
let oi_subexpr = asg.create(expr);
|
||||||
oi_subexpr.add_edge_from(asg, self, None)
|
oi_subexpr.add_tree_edge_from(asg, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reference the value of the expression identified by `oi_ident` as if
|
/// Reference the value of the expression identified by `oi_ident` as if
|
||||||
|
@ -245,7 +245,7 @@ impl ObjectIndex<Expr> {
|
||||||
asg: &mut Asg,
|
asg: &mut Asg,
|
||||||
oi_ident: ObjectIndex<Ident>,
|
oi_ident: ObjectIndex<Ident>,
|
||||||
) -> Result<Self, AsgError> {
|
) -> Result<Self, AsgError> {
|
||||||
self.add_edge_to(asg, oi_ident, Some(oi_ident.span()))
|
self.add_cross_edge_to(asg, oi_ident, oi_ident.span())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The expression is held by the container `oi_container`.
|
/// The expression is held by the container `oi_container`.
|
||||||
|
@ -263,8 +263,8 @@ impl ObjectIndex<Expr> {
|
||||||
pub fn held_by(
|
pub fn held_by(
|
||||||
&self,
|
&self,
|
||||||
asg: &mut Asg,
|
asg: &mut Asg,
|
||||||
oi_container: ObjectIndexTo<Expr>,
|
oi_container: ObjectIndexToTree<Expr>,
|
||||||
) -> Result<Self, AsgError> {
|
) -> Result<Self, AsgError> {
|
||||||
self.add_edge_from(asg, oi_container, None)
|
self.add_tree_edge_from(asg, oi_container)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1221,7 +1221,7 @@ impl ObjectIndex<Ident> {
|
||||||
self.try_map_obj(asg, |obj| obj.resolve(name.span(), kind, src))
|
self.try_map_obj(asg, |obj| obj.resolve(name.span(), kind, src))
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.map(|ident| {
|
.map(|ident| {
|
||||||
is_auto_root.then(|| self.root(asg));
|
is_auto_root.then(|| self.root_cross(asg));
|
||||||
ident
|
ident
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1257,7 +1257,7 @@ impl ObjectIndex<Ident> {
|
||||||
definition: ObjectIndex<O>,
|
definition: ObjectIndex<O>,
|
||||||
) -> Result<ObjectIndex<Ident>, AsgError>
|
) -> Result<ObjectIndex<Ident>, AsgError>
|
||||||
where
|
where
|
||||||
Ident: ObjectRelTo<O>,
|
Ident: ObjectTreeRelTo<O>,
|
||||||
ObjectIndex<O>: Into<IdentDefinition>,
|
ObjectIndex<O>: Into<IdentDefinition>,
|
||||||
{
|
{
|
||||||
let my_span = self.into();
|
let my_span = self.into();
|
||||||
|
@ -1314,7 +1314,7 @@ impl ObjectIndex<Ident> {
|
||||||
// and use the newly provided `id` and its span.
|
// and use the newly provided `id` and its span.
|
||||||
Missing(_) => Ok(Transparent(id)),
|
Missing(_) => Ok(Transparent(id)),
|
||||||
})
|
})
|
||||||
.and_then(|ident_oi| ident_oi.add_edge_to(asg, definition, None))
|
.and_then(|ident_oi| ident_oi.add_tree_edge_to(asg, definition))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the fragment associated with a concrete identifier.
|
/// Set the fragment associated with a concrete identifier.
|
||||||
|
@ -1414,9 +1414,9 @@ impl ObjectIndex<Ident> {
|
||||||
pub fn defined_by(
|
pub fn defined_by(
|
||||||
&self,
|
&self,
|
||||||
asg: &mut Asg,
|
asg: &mut Asg,
|
||||||
oi_root: impl ObjectIndexRelTo<Ident>,
|
oi_root: impl ObjectIndexTreeRelTo<Ident>,
|
||||||
) -> Result<Self, AsgError> {
|
) -> Result<Self, AsgError> {
|
||||||
self.add_edge_from(asg, oi_root, None)
|
self.add_tree_edge_from(asg, oi_root)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Declare that `oi_dep` is an opaque dependency of `self`.
|
/// Declare that `oi_dep` is an opaque dependency of `self`.
|
||||||
|
@ -1425,7 +1425,7 @@ impl ObjectIndex<Ident> {
|
||||||
asg: &mut Asg,
|
asg: &mut Asg,
|
||||||
oi_dep: ObjectIndex<Ident>,
|
oi_dep: ObjectIndex<Ident>,
|
||||||
) -> Result<Self, AsgError> {
|
) -> Result<Self, AsgError> {
|
||||||
self.add_edge_to(asg, oi_dep, None)
|
self.add_tree_edge_to(asg, oi_dep)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve either the concrete name of the identifier or the name of
|
/// Retrieve either the concrete name of the identifier or the name of
|
||||||
|
@ -1491,7 +1491,7 @@ impl ObjectIndex<Ident> {
|
||||||
at: Span,
|
at: Span,
|
||||||
) -> Result<ObjectIndex<Ident>, AsgError> {
|
) -> Result<ObjectIndex<Ident>, AsgError> {
|
||||||
asg.create(Ident::new_abstract(at))
|
asg.create(Ident::new_abstract(at))
|
||||||
.add_edge_to(asg, self, Some(at))
|
.add_cross_edge_to(asg, self, at)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -243,7 +243,7 @@ impl ObjectIndex<Meta> {
|
||||||
|
|
||||||
for rel_lexeme in rels {
|
for rel_lexeme in rels {
|
||||||
let oi = asg.create(Meta::Lexeme(rel_lexeme.span(), rel_lexeme));
|
let oi = asg.create(Meta::Lexeme(rel_lexeme.span(), rel_lexeme));
|
||||||
self.add_edge_to(asg, oi, None)?;
|
self.add_tree_edge_to(asg, oi)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
|
@ -297,12 +297,12 @@ impl ObjectIndex<Meta> {
|
||||||
// we must add the edge before appending the ref since
|
// we must add the edge before appending the ref since
|
||||||
// concatenation will occur during expansion in edge order.
|
// concatenation will occur during expansion in edge order.
|
||||||
if let Some(orig) = pre {
|
if let Some(orig) = pre {
|
||||||
asg.create(orig).add_edge_from(asg, self, None)?;
|
asg.create(orig).add_tree_edge_from(asg, self)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Having been guaranteed a `ConcatList` above,
|
// Having been guaranteed a `ConcatList` above,
|
||||||
// we now only need to append an edge that references what to
|
// we now only need to append an edge that references what to
|
||||||
// concatenate.
|
// concatenate.
|
||||||
self.add_edge_to(asg, oi_ref, Some(oi_ref.span()))
|
self.add_cross_edge_to(asg, oi_ref, oi_ref.span())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ impl ObjectIndex<Pkg> {
|
||||||
let parent = self.resolve(asg);
|
let parent = self.resolve(asg);
|
||||||
let oi_import = asg.create(Pkg::new_imported(parent, namespec)?);
|
let oi_import = asg.create(Pkg::new_imported(parent, namespec)?);
|
||||||
|
|
||||||
self.add_edge_to(asg, oi_import, Some(namespec.span()))
|
self.add_cross_edge_to(asg, oi_import, namespec.span())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Arbitrary text serving as documentation in a literate style.
|
/// Arbitrary text serving as documentation in a literate style.
|
||||||
|
@ -144,6 +144,6 @@ impl ObjectIndex<Pkg> {
|
||||||
text: SPair,
|
text: SPair,
|
||||||
) -> Result<Self, AsgError> {
|
) -> Result<Self, AsgError> {
|
||||||
let oi_doc = asg.create(Doc::new_text(text));
|
let oi_doc = asg.create(Doc::new_text(text));
|
||||||
self.add_edge_to(asg, oi_doc, None)
|
self.add_tree_edge_to(asg, oi_doc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,14 +203,17 @@ macro_rules! object_rel {
|
||||||
// Similar to above but providing _static_ information to the type
|
// Similar to above but providing _static_ information to the type
|
||||||
// system.
|
// system.
|
||||||
// The above could be rolled into this at some point.
|
// The above could be rolled into this at some point.
|
||||||
(@impl_rel_to $from:ident cross $kind:ident) => {};
|
(@impl_rel_to $from:ident cross $kind:ident) => {
|
||||||
|
impl ObjectCrossRelTo<$kind> for $from {}
|
||||||
|
};
|
||||||
(@impl_rel_to $from:ident tree $kind:ident) => {
|
(@impl_rel_to $from:ident tree $kind:ident) => {
|
||||||
impl ObjectTreeRelTo<$kind> for $from {}
|
impl ObjectTreeRelTo<$kind> for $from {}
|
||||||
};
|
};
|
||||||
(@impl_rel_to $from:ident dyn $kind:ident) => {
|
(@impl_rel_to $from:ident dyn $kind:ident) => {
|
||||||
// It _could_ be a tree edge;
|
// It _could_ be either a tree or cross edge;
|
||||||
// we can't know statically.
|
// we can't know statically.
|
||||||
impl ObjectTreeRelTo<$kind> for $from {}
|
impl ObjectTreeRelTo<$kind> for $from {}
|
||||||
|
impl ObjectCrossRelTo<$kind> for $from {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,11 +539,31 @@ pub trait ObjectRelFrom<OA: ObjectKind + ObjectRelatable> =
|
||||||
/// see that trait for more information.
|
/// see that trait for more information.
|
||||||
/// This trait is intended to be used in contexts where the distinction
|
/// This trait is intended to be used in contexts where the distinction
|
||||||
/// between reference and ownership is important.
|
/// between reference and ownership is important.
|
||||||
|
///
|
||||||
|
/// For cross edges,
|
||||||
|
/// see [`ObjectCrossRelTo`];
|
||||||
|
/// dynamic edges will implement both this trait and that one.
|
||||||
pub trait ObjectTreeRelTo<OB: ObjectKind + ObjectRelatable>:
|
pub trait ObjectTreeRelTo<OB: ObjectKind + ObjectRelatable>:
|
||||||
ObjectRelTo<OB>
|
ObjectRelTo<OB>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Indicate that an [`ObjectKind`] `Self` _could possibly be a reference
|
||||||
|
/// to_ an [`ObjectKind`] `OB`.
|
||||||
|
///
|
||||||
|
/// This is a stronger assertion than [`ObjectRelTo`];
|
||||||
|
/// see that trait for more information.
|
||||||
|
/// This trait is intended to be used in contexts where the distinction
|
||||||
|
/// between reference and ownership is important.
|
||||||
|
///
|
||||||
|
/// For tree edges,
|
||||||
|
/// see [`ObjectTreeRelTo`];
|
||||||
|
/// dynamic edges will implement both this trait and that one.
|
||||||
|
pub trait ObjectCrossRelTo<OB: ObjectKind + ObjectRelatable>:
|
||||||
|
ObjectRelTo<OB>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// Identify [`Self::Rel`] as a sum type consisting of the subset of
|
/// Identify [`Self::Rel`] as a sum type consisting of the subset of
|
||||||
/// [`Object`] variants representing the valid _target_ edges of
|
/// [`Object`] variants representing the valid _target_ edges of
|
||||||
/// [`Self`].
|
/// [`Self`].
|
||||||
|
@ -1036,6 +1059,32 @@ impl<OB: ObjectRelatable> ObjectIndexRelTo<OB> for ObjectIndexToTree<OB> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<OB: ObjectRelatable> ObjectIndexRelTo<OB> for ObjectIndexToCross<OB> {
|
||||||
|
fn src_rel_ty(&self) -> ObjectRelTy {
|
||||||
|
match self {
|
||||||
|
Self(oito) => oito.src_rel_ty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn widen(&self) -> ObjectIndex<Object> {
|
||||||
|
match self {
|
||||||
|
Self(oito) => oito.widen(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pre_add_edge(
|
||||||
|
&self,
|
||||||
|
asg: &mut Asg,
|
||||||
|
to_oi: ObjectIndex<OB>,
|
||||||
|
ref_span: Option<Span>,
|
||||||
|
commit: impl FnOnce(&mut Asg),
|
||||||
|
) -> Result<(), AsgError> {
|
||||||
|
match self {
|
||||||
|
Self(oito) => oito.pre_add_edge(asg, to_oi, ref_span, commit),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<OB: ObjectRelatable> From<ObjectIndexTo<OB>> for ObjectIndex<Object> {
|
impl<OB: ObjectRelatable> From<ObjectIndexTo<OB>> for ObjectIndex<Object> {
|
||||||
fn from(oi_rel: ObjectIndexTo<OB>) -> Self {
|
fn from(oi_rel: ObjectIndexTo<OB>) -> Self {
|
||||||
oi_rel.widen()
|
oi_rel.widen()
|
||||||
|
@ -1072,7 +1121,29 @@ where
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use private::{ObjectIndexTo, ObjectIndexToTree};
|
/// An [`ObjectIndex`]-like object that is able to create a _cross_ edge to
|
||||||
|
/// [`ObjectKind`] `OB`.
|
||||||
|
///
|
||||||
|
/// This allows for generic graph operations that operate on ownership
|
||||||
|
/// relationships without having to know the type of the source
|
||||||
|
/// object (`Self`).
|
||||||
|
///
|
||||||
|
/// This is a specialization of [`ObjectIndexRelTo`].
|
||||||
|
pub trait ObjectIndexCrossRelTo<OB: ObjectRelatable>:
|
||||||
|
ObjectIndexRelTo<OB> + Into<ObjectIndexToCross<OB>>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<OB: ObjectRelatable> ObjectIndexCrossRelTo<OB> for ObjectIndexToCross<OB> {}
|
||||||
|
|
||||||
|
impl<O: ObjectRelatable, OB: ObjectRelatable> ObjectIndexCrossRelTo<OB>
|
||||||
|
for ObjectIndex<O>
|
||||||
|
where
|
||||||
|
O: ObjectCrossRelTo<OB>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use private::{ObjectIndexTo, ObjectIndexToCross, ObjectIndexToTree};
|
||||||
|
|
||||||
/// Private inner module to ensure that nothing is able to bypass invariants
|
/// Private inner module to ensure that nothing is able to bypass invariants
|
||||||
/// by constructing [`ObjectIndexTo`] manually.
|
/// by constructing [`ObjectIndexTo`] manually.
|
||||||
|
@ -1204,6 +1275,14 @@ mod private {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<OB: ObjectRelatable> From<ObjectIndexToCross<OB>> for ObjectIndexTo<OB> {
|
||||||
|
fn from(value: ObjectIndexToCross<OB>) -> Self {
|
||||||
|
match value {
|
||||||
|
ObjectIndexToCross(oit) => oit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Some [`ObjectIndex`] that can create a _tree_ edge to `OB`.
|
/// Some [`ObjectIndex`] that can create a _tree_ edge to `OB`.
|
||||||
///
|
///
|
||||||
/// This is a specialization of
|
/// This is a specialization of
|
||||||
|
@ -1260,4 +1339,61 @@ mod private {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Some [`ObjectIndex`] that can create a _cross_ edge to `OB`.
|
||||||
|
///
|
||||||
|
/// This is a specialization of
|
||||||
|
/// (and contains)
|
||||||
|
/// [`ObjectIndexTo`];
|
||||||
|
/// see that for more information.
|
||||||
|
///
|
||||||
|
/// See also [`ObjectIndexTreeRelTo`].
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ObjectIndexToCross<OB: ObjectRelatable>(ObjectIndexTo<OB>);
|
||||||
|
|
||||||
|
impl<OB: ObjectRelatable, O: ObjectRelatable> From<ObjectIndex<O>>
|
||||||
|
for ObjectIndexToCross<OB>
|
||||||
|
where
|
||||||
|
O: ObjectCrossRelTo<OB>,
|
||||||
|
{
|
||||||
|
fn from(oi: ObjectIndex<O>) -> Self {
|
||||||
|
Self(oi.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deriving any of the below were introducing trait bounds on `OB`.
|
||||||
|
|
||||||
|
impl<OB: ObjectRelatable> PartialEq for ObjectIndexToCross<OB> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Self(oi), Self(oi_other)) => oi == oi_other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<OB: ObjectRelatable> Eq for ObjectIndexToCross<OB> {}
|
||||||
|
|
||||||
|
impl<OB: ObjectRelatable> Hash for ObjectIndexToCross<OB> {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
match self {
|
||||||
|
Self(oi) => oi.hash(state),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<OB: ObjectRelatable> Clone for ObjectIndexToCross<OB> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<OB: ObjectRelatable> Copy for ObjectIndexToCross<OB> {}
|
||||||
|
|
||||||
|
impl<OB: ObjectRelatable> From<ObjectIndexToCross<OB>> for Span {
|
||||||
|
fn from(oi: ObjectIndexToCross<OB>) -> Self {
|
||||||
|
match oi {
|
||||||
|
ObjectIndexToCross(inner) => inner.span(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ impl ObjectIndex<Root> {
|
||||||
asg: &mut Asg,
|
asg: &mut Asg,
|
||||||
oi: ObjectIndex<Ident>,
|
oi: ObjectIndex<Ident>,
|
||||||
) -> Result<ObjectIndex<Ident>, AsgError> {
|
) -> Result<ObjectIndex<Ident>, AsgError> {
|
||||||
oi.add_edge_from(asg, *self, None)
|
// TODO: Is this a valid span?
|
||||||
|
oi.add_cross_edge_from(asg, *self, oi.span())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,6 +232,10 @@ impl Display for TplShape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Inlining code into this otherwise-declarative abstraction has
|
||||||
|
// tainted it.
|
||||||
|
// This can be refactored into a better abstraction over time as
|
||||||
|
// requirements are explored though implementation.
|
||||||
object_rel! {
|
object_rel! {
|
||||||
/// Templates may expand into nearly any context,
|
/// Templates may expand into nearly any context,
|
||||||
/// and must therefore be able to contain just about anything.
|
/// and must therefore be able to contain just about anything.
|
||||||
|
@ -303,8 +307,6 @@ object_rel! {
|
||||||
// be hoisted into the rooting context of the
|
// be hoisted into the rooting context of the
|
||||||
// application site,
|
// application site,
|
||||||
// which does not impact template shape.
|
// which does not impact template shape.
|
||||||
// TODO: Let's make that span assumption explicit in the
|
|
||||||
// `ProposeRel` abstraction.
|
|
||||||
(None, _) => Ok(()),
|
(None, _) => Ok(()),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
@ -393,7 +395,7 @@ impl ObjectIndex<Tpl> {
|
||||||
oi_apply: ObjectIndex<Ident>,
|
oi_apply: ObjectIndex<Ident>,
|
||||||
ref_span: Span,
|
ref_span: Span,
|
||||||
) -> Result<Self, AsgError> {
|
) -> Result<Self, AsgError> {
|
||||||
self.add_edge_to(asg, oi_apply, Some(ref_span))
|
self.add_cross_edge_to(asg, oi_apply, ref_span)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Directly reference this template from another object
|
/// Directly reference this template from another object
|
||||||
|
@ -406,12 +408,12 @@ impl ObjectIndex<Tpl> {
|
||||||
/// template.
|
/// template.
|
||||||
/// If this template is _not_ closed,
|
/// If this template is _not_ closed,
|
||||||
/// it will result in an error during evaluation.
|
/// it will result in an error during evaluation.
|
||||||
pub fn expand_into<OP: ObjectIndexRelTo<Tpl>>(
|
pub fn expand_into<OP: ObjectIndexTreeRelTo<Tpl>>(
|
||||||
self,
|
self,
|
||||||
asg: &mut Asg,
|
asg: &mut Asg,
|
||||||
oi_target_parent: OP,
|
oi_target_parent: OP,
|
||||||
) -> Result<Self, AsgError> {
|
) -> Result<Self, AsgError> {
|
||||||
self.add_edge_from(asg, oi_target_parent, None)
|
self.add_tree_edge_from(asg, oi_target_parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Arbitrary text serving as documentation in a literate style,
|
/// Arbitrary text serving as documentation in a literate style,
|
||||||
|
@ -422,6 +424,6 @@ impl ObjectIndex<Tpl> {
|
||||||
text: SPair,
|
text: SPair,
|
||||||
) -> Result<Self, AsgError> {
|
) -> Result<Self, AsgError> {
|
||||||
let oi_doc = asg.create(Doc::new_text(text));
|
let oi_doc = asg.create(Doc::new_text(text));
|
||||||
self.add_edge_to(asg, oi_doc, None)
|
self.add_tree_edge_to(asg, oi_doc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue