tamer: asg::graph::object::ident::IdentDefinition: New sum type

This allows removing the `diagnostic_panic!` from the `Ident` edge handling
for `Tpl`.

I do need to create a generic sum type macro at some point, considering how
extensively these are used.

DEV-13163
main
Mike Gerwitz 2023-07-31 14:27:36 -04:00
parent deede5ff21
commit 17589939dd
2 changed files with 73 additions and 26 deletions

View File

@ -1121,12 +1121,63 @@ object_rel! {
// metavariable reference. // metavariable reference.
dyn Ident, dyn Ident,
// Be sure to update `IdentDefinition` below if necessary
// (the compiler will remind you if you try to use such an object
// in a definition without doing so).
tree Expr, tree Expr,
tree Tpl, tree Tpl,
tree Meta, tree Meta,
} can_recurse(ident) if matches!(ident.kind(), Some(IdentKind::Func(..))) } can_recurse(ident) if matches!(ident.kind(), Some(IdentKind::Func(..)))
} }
/// An [`ObjectKind`] that may serve as a definition of an [`Ident`].
///
/// This is a more refined [`IdentRel`],
/// which is defined by the [`object_rel!`] macro.
///
/// See [`ObjectIndex<Ident>::definition`].
#[derive(Debug, PartialEq, Eq)]
pub enum IdentDefinition {
Expr(ObjectIndex<Expr>),
Tpl(ObjectIndex<Tpl>),
Meta(ObjectIndex<Meta>),
}
impl IdentDefinition {
/// Attempt to narrow the definition into the requested type `O`,
/// returning [`None`] if the types do not match.
fn narrow<O: ObjectRelatable>(self) -> Option<ObjectIndex<O>>
where
O: ObjectRelFrom<Ident>,
{
use IdentDefinition::*;
match self {
Expr(oi) => oi.filter_rel(),
Tpl(oi) => oi.filter_rel(),
Meta(oi) => oi.filter_rel(),
}
}
}
impl From<ObjectIndex<Expr>> for IdentDefinition {
fn from(oi: ObjectIndex<Expr>) -> Self {
Self::Expr(oi)
}
}
impl From<ObjectIndex<Tpl>> for IdentDefinition {
fn from(oi: ObjectIndex<Tpl>) -> Self {
Self::Tpl(oi)
}
}
impl From<ObjectIndex<Meta>> for IdentDefinition {
fn from(oi: ObjectIndex<Meta>) -> Self {
Self::Meta(oi)
}
}
impl ObjectIndex<Ident> { impl ObjectIndex<Ident> {
/// Declare a concrete identifier. /// Declare a concrete identifier.
/// ///
@ -1207,6 +1258,7 @@ impl ObjectIndex<Ident> {
) -> Result<ObjectIndex<Ident>, AsgError> ) -> Result<ObjectIndex<Ident>, AsgError>
where where
Ident: ObjectRelTo<O>, Ident: ObjectRelTo<O>,
ObjectIndex<O>: Into<IdentDefinition>,
{ {
let my_span = self.into(); let my_span = self.into();
@ -1287,13 +1339,21 @@ impl ObjectIndex<Ident> {
/// then the definition that is returned is undefined. /// then the definition that is returned is undefined.
/// ///
/// See also [`Self::bind_definition`] and [`Self::definition_narrow`]. /// See also [`Self::bind_definition`] and [`Self::definition_narrow`].
pub fn definition( pub fn definition(&self, asg: &Asg) -> Option<IdentDefinition> {
&self, // `find_map` is still important because,
asg: &Asg, // even though we should have only one definition,
) -> Option<<Ident as ObjectRelatable>::Rel> { // we _may_ have multiple edges,
// XXX: This could return an abstract binding metavar reference // e.g. in the case of an abstract binding.
// depending on undefined edge ordering! self.edges(asg).find_map(|rel| match rel {
self.edges(asg).next() IdentRel::Expr(oi) => Some(IdentDefinition::Expr(oi)),
IdentRel::Tpl(oi) => Some(IdentDefinition::Tpl(oi)),
IdentRel::Meta(oi) => Some(IdentDefinition::Meta(oi)),
// Could be an abstract binding or an opaque dependency.
// In either case,
// it's no definition.
IdentRel::Ident(_) => None,
})
} }
/// Look up the definition that this identifier binds to, /// Look up the definition that this identifier binds to,
@ -1316,7 +1376,7 @@ impl ObjectIndex<Ident> {
&self, &self,
asg: &Asg, asg: &Asg,
) -> Option<ObjectIndex<O>> { ) -> Option<ObjectIndex<O>> {
self.edges(asg).find_map(ObjectRel::narrow) self.definition(asg).and_then(IdentDefinition::narrow)
} }
/// Whether this identifier is bound to the object represented by `oi`. /// Whether this identifier is bound to the object represented by `oi`.

View File

@ -21,13 +21,8 @@
use std::fmt::Display; use std::fmt::Display;
use super::{ident::IdentRel, prelude::*, Doc, Expr, Ident}; use super::{ident::IdentDefinition, prelude::*, Doc, Expr, Ident};
use crate::{ use crate::{asg::graph::ProposedRel, f::Map, parse::util::SPair, span::Span};
asg::graph::ProposedRel,
f::Map,
parse::{prelude::Annotate, util::SPair},
span::Span,
};
/// Template with associated name. /// Template with associated name.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
@ -285,7 +280,7 @@ object_rel! {
// TAME is referentally transparent, // TAME is referentally transparent,
// so a reference to an Expr is no different than // so a reference to an Expr is no different than
// inlining that Expr. // inlining that Expr.
(Some(ref_span), Some(IdentRel::Expr(_))) => { (Some(ref_span), Some(IdentDefinition::Expr(_))) => {
rel.from_oi.try_map_obj_inner( rel.from_oi.try_map_obj_inner(
asg, asg,
try_adapt_to(TplShape::Expr(ref_span), tpl_name), try_adapt_to(TplShape::Expr(ref_span), tpl_name),
@ -294,7 +289,7 @@ object_rel! {
// This is the same as the `Tpl` tree edge below, // This is the same as the `Tpl` tree edge below,
// but a named template instead of an anonymous one. // but a named template instead of an anonymous one.
(Some(ref_span), Some(IdentRel::Tpl(to_oi))) => { (Some(ref_span), Some(IdentDefinition::Tpl(to_oi))) => {
// TODO: Factor common logic between this and the // TODO: Factor common logic between this and the
// `Tpl->Tpl` edge below. // `Tpl->Tpl` edge below.
let tpl_name = to_oi.name(asg); let tpl_name = to_oi.name(asg);
@ -309,17 +304,9 @@ object_rel! {
)?; )?;
} }
// TODO: Filter this out (Ident -> Ident)
(Some(span), Some(IdentRel::Ident(_))) => {
diagnostic_todo!(
vec![span.internal_error("while parsing this reference")],
"opaque identifier or abstract binding"
)
}
// The mere _existence_ of metavariables (template // The mere _existence_ of metavariables (template
// params) do not influence the expansion shape. // params) do not influence the expansion shape.
(Some(_), Some(IdentRel::Meta(_))) => (), (Some(_), Some(IdentDefinition::Meta(_))) => (),
// Lack of span means that this is not a cross edge, // Lack of span means that this is not a cross edge,
// and so not a reference; // and so not a reference;