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-13163main
parent
deede5ff21
commit
17589939dd
|
@ -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`.
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue