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.
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 Tpl,
tree Meta,
} 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> {
/// Declare a concrete identifier.
///
@ -1207,6 +1258,7 @@ impl ObjectIndex<Ident> {
) -> Result<ObjectIndex<Ident>, AsgError>
where
Ident: ObjectRelTo<O>,
ObjectIndex<O>: Into<IdentDefinition>,
{
let my_span = self.into();
@ -1287,13 +1339,21 @@ impl ObjectIndex<Ident> {
/// then the definition that is returned is undefined.
///
/// See also [`Self::bind_definition`] and [`Self::definition_narrow`].
pub fn definition(
&self,
asg: &Asg,
) -> Option<<Ident as ObjectRelatable>::Rel> {
// XXX: This could return an abstract binding metavar reference
// depending on undefined edge ordering!
self.edges(asg).next()
pub fn definition(&self, asg: &Asg) -> Option<IdentDefinition> {
// `find_map` is still important because,
// even though we should have only one definition,
// we _may_ have multiple edges,
// e.g. in the case of an abstract binding.
self.edges(asg).find_map(|rel| match rel {
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,
@ -1316,7 +1376,7 @@ impl ObjectIndex<Ident> {
&self,
asg: &Asg,
) -> 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`.

View File

@ -21,13 +21,8 @@
use std::fmt::Display;
use super::{ident::IdentRel, prelude::*, Doc, Expr, Ident};
use crate::{
asg::graph::ProposedRel,
f::Map,
parse::{prelude::Annotate, util::SPair},
span::Span,
};
use super::{ident::IdentDefinition, prelude::*, Doc, Expr, Ident};
use crate::{asg::graph::ProposedRel, f::Map, parse::util::SPair, span::Span};
/// Template with associated name.
#[derive(Debug, PartialEq, Eq)]
@ -285,7 +280,7 @@ object_rel! {
// TAME is referentally transparent,
// so a reference to an Expr is no different than
// inlining that Expr.
(Some(ref_span), Some(IdentRel::Expr(_))) => {
(Some(ref_span), Some(IdentDefinition::Expr(_))) => {
rel.from_oi.try_map_obj_inner(
asg,
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,
// 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
// `Tpl->Tpl` edge below.
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
// 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,
// and so not a reference;