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.
|
// 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`.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue