tamer::asg::graph::object::ident::Ident::name: Produce Option
This prepares to make the name of an `Ident` optional to support abstract identifiers derived from metavariables. This is an unfortunate change to have to prepare for, since it complicates how Idents are interpreted, but the alternative (a new object type) is not good either. We'll see how this evolves. DEV-13163main
parent
6b54eafd70
commit
828d8918a3
|
@ -810,13 +810,11 @@ impl<O: ObjectKind> ObjectIndex<O> {
|
|||
/// on the graph,
|
||||
/// like common subexpression elimination,
|
||||
/// in which case it's best not to rely on following edges in reverse.
|
||||
pub fn ident<'a>(&self, asg: &'a Asg) -> Option<&'a Ident>
|
||||
pub fn ident<'a>(&self, asg: &'a Asg) -> Option<ObjectIndex<Ident>>
|
||||
where
|
||||
O: ObjectRelFrom<Ident>,
|
||||
{
|
||||
self.incoming_edges_filtered(asg)
|
||||
.map(ObjectIndex::cresolve(asg))
|
||||
.next()
|
||||
self.incoming_edges_filtered(asg).next()
|
||||
}
|
||||
|
||||
/// Describe this expression using a short independent clause.
|
||||
|
|
|
@ -170,14 +170,18 @@ impl Display for Ident {
|
|||
}
|
||||
|
||||
impl Ident {
|
||||
/// Identifier name.
|
||||
pub fn name(&self) -> SPair {
|
||||
/// Concrete identifier name.
|
||||
///
|
||||
/// Note: This [`Option`] is in preparation for identifiers that may not
|
||||
/// yet have names,
|
||||
/// awaiting expansion of a metavariable.
|
||||
pub fn name(&self) -> Option<SPair> {
|
||||
match self {
|
||||
Missing(name)
|
||||
| Opaque(name, ..)
|
||||
| Extern(name, ..)
|
||||
| IdentFragment(name, ..)
|
||||
| Transparent(name) => *name,
|
||||
| Transparent(name) => Some(*name),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -357,10 +361,11 @@ impl Ident {
|
|||
|
||||
Missing(name) => Ok(Opaque(name.overwrite(span), kind, src)),
|
||||
|
||||
// TODO: Remove guards and catch-all for exhaustiveness check.
|
||||
_ => {
|
||||
let err = TransitionError::Redeclare(self.name(), span);
|
||||
|
||||
// TODO: Remove guards for better exhaustiveness check
|
||||
Opaque(name, _, _)
|
||||
| IdentFragment(name, _, _, _)
|
||||
| Transparent(name) => {
|
||||
let err = TransitionError::Redeclare(name, span);
|
||||
Err((self, err))
|
||||
}
|
||||
}
|
||||
|
@ -381,7 +386,7 @@ impl Ident {
|
|||
/// At present,
|
||||
/// both [`Ident::Missing`] and [`Ident::Extern`] are
|
||||
/// considered to be unresolved.
|
||||
pub fn resolved(&self) -> Result<&Ident, UnresolvedError> {
|
||||
pub fn resolved(&self) -> Result<(&Ident, SPair), UnresolvedError> {
|
||||
match self {
|
||||
Missing(name) => Err(UnresolvedError::Missing(*name)),
|
||||
|
||||
|
@ -389,7 +394,9 @@ impl Ident {
|
|||
Err(UnresolvedError::Extern(*name, kind.clone()))
|
||||
}
|
||||
|
||||
Opaque(..) | IdentFragment(..) | Transparent(..) => Ok(self),
|
||||
Opaque(name, ..)
|
||||
| IdentFragment(name, ..)
|
||||
| Transparent(name, ..) => Ok((self, *name)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -414,21 +421,26 @@ impl Ident {
|
|||
kind: IdentKind,
|
||||
src: Source,
|
||||
) -> TransitionResult<Ident> {
|
||||
match self.kind() {
|
||||
None => Ok(Extern(self.name().overwrite(span), kind, src)),
|
||||
Some(cur_kind) => {
|
||||
match self {
|
||||
Missing(name) | Transparent(name) => {
|
||||
Ok(Extern(name.overwrite(span), kind, src))
|
||||
}
|
||||
|
||||
Opaque(name, ref cur_kind, _)
|
||||
| Extern(name, ref cur_kind, _)
|
||||
| IdentFragment(name, ref cur_kind, _, _) => {
|
||||
if cur_kind != &kind {
|
||||
let err = TransitionError::ExternResolution(
|
||||
self.name(),
|
||||
name,
|
||||
cur_kind.clone(),
|
||||
(kind, span),
|
||||
);
|
||||
|
||||
return Err((self, err));
|
||||
Err((self, err))
|
||||
} else {
|
||||
// Resolved successfully, so keep what we already have.
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
// Resolved successfully, so keep what we already have.
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -457,6 +469,9 @@ impl Ident {
|
|||
IdentFragment(_, _, ref src, ..) if src.override_ => Ok(self),
|
||||
|
||||
// These represent the prologue and epilogue of maps.
|
||||
//
|
||||
// TODO: Is this arm still needed after having eliminated their
|
||||
// fragments from xmlo files?
|
||||
IdentFragment(
|
||||
_,
|
||||
IdentKind::MapHead
|
||||
|
@ -466,8 +481,10 @@ impl Ident {
|
|||
..,
|
||||
) => Ok(self),
|
||||
|
||||
_ => {
|
||||
let name = self.name();
|
||||
Missing(name)
|
||||
| Extern(name, _, _)
|
||||
| IdentFragment(name, _, _, _)
|
||||
| Transparent(name) => {
|
||||
Err((self, TransitionError::BadFragmentDest(name)))
|
||||
}
|
||||
}
|
||||
|
@ -1167,6 +1184,19 @@ impl ObjectIndex<Ident> {
|
|||
) -> Self {
|
||||
self.add_edge_to(asg, oi_dep, None)
|
||||
}
|
||||
|
||||
/// Retrieve either the concrete name of the identifier or the name of
|
||||
/// the metavariable that will be used to produce it.
|
||||
pub fn name_or_meta(&self, asg: &Asg) -> SPair {
|
||||
let ident = self.resolve(asg);
|
||||
|
||||
ident.name().unwrap_or_else(|| {
|
||||
diagnostic_todo!(
|
||||
vec![ident.span().internal_error("for this abstract ident")],
|
||||
"metavariable lookup not yet supported",
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -30,20 +30,20 @@ fn ident_name() {
|
|||
let name = "name".into();
|
||||
let spair = SPair(name, S1);
|
||||
|
||||
assert_eq!(spair, Ident::Missing(spair).name());
|
||||
assert_eq!(Some(spair), Ident::Missing(spair).name());
|
||||
|
||||
assert_eq!(
|
||||
spair,
|
||||
Some(spair),
|
||||
Ident::Opaque(spair, IdentKind::Meta, Source::default()).name()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
spair,
|
||||
Some(spair),
|
||||
Ident::Extern(spair, IdentKind::Meta, Source::default()).name()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
spair,
|
||||
Some(spair),
|
||||
Ident::IdentFragment(
|
||||
spair,
|
||||
IdentKind::Meta,
|
||||
|
@ -182,7 +182,10 @@ fn resolved_on_ident() {
|
|||
.unwrap()
|
||||
.resolved()
|
||||
.unwrap(),
|
||||
&Ident::Opaque(SPair(sym, S2), kind.clone(), src.clone()),
|
||||
(
|
||||
&Ident::Opaque(SPair(sym, S2), kind.clone(), src.clone()),
|
||||
SPair(sym, S2)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -403,7 +406,10 @@ fn resolved_on_fragment() {
|
|||
|
||||
assert_eq!(
|
||||
ident.set_fragment(text.clone()).unwrap().resolved(),
|
||||
Ok(&Ident::IdentFragment(SPair(sym, S2), kind, src, text)),
|
||||
Ok((
|
||||
&Ident::IdentFragment(SPair(sym, S2), kind, src, text),
|
||||
SPair(sym, S2),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -875,8 +875,10 @@ pub trait ObjectIndexRelTo<OB: ObjectRelatable>: Sized + Clone + Copy {
|
|||
Self: ObjectIndexRelTo<Ident>,
|
||||
{
|
||||
// Rust fails to infer OB with `self.edges_rel_to` as of 2023-03
|
||||
ObjectIndexRelTo::<Ident>::edges_rel_to(self, asg)
|
||||
.find(|oi| oi.resolve(asg).name().symbol() == name.symbol())
|
||||
ObjectIndexRelTo::<Ident>::edges_rel_to(self, asg).find(|oi| {
|
||||
oi.resolve(asg).name().map(|name| name.symbol())
|
||||
== Some(name.symbol())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -282,8 +282,8 @@ impl<'a> TreeContext<'a> {
|
|||
depth: Depth,
|
||||
) -> Option<Xirf> {
|
||||
match src {
|
||||
Object::Ident((ident, _)) => {
|
||||
self.emit_expr_ident(expr, ident, depth)
|
||||
Object::Ident((ident, oi_ident)) => {
|
||||
self.emit_expr_ident(expr, *oi_ident, ident, depth)
|
||||
}
|
||||
Object::Expr((pexpr, _)) => match (pexpr.op(), expr.op()) {
|
||||
(ExprOp::Conj | ExprOp::Disj, ExprOp::Eq) => {
|
||||
|
@ -315,6 +315,7 @@ impl<'a> TreeContext<'a> {
|
|||
fn emit_expr_ident(
|
||||
&mut self,
|
||||
expr: &Expr,
|
||||
oi_ident: ObjectIndex<Ident>,
|
||||
ident: &Ident,
|
||||
depth: Depth,
|
||||
) -> Option<Xirf> {
|
||||
|
@ -331,8 +332,9 @@ impl<'a> TreeContext<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
let name = oi_ident.name_or_meta(self.asg);
|
||||
let ispan = ident.span();
|
||||
self.push(Xirf::attr(ident_qname, ident.name(), (ispan, ispan)));
|
||||
self.push(Xirf::attr(ident_qname, name, (ispan, ispan)));
|
||||
|
||||
Some(Xirf::open(
|
||||
qname,
|
||||
|
@ -353,21 +355,15 @@ impl<'a> TreeContext<'a> {
|
|||
let mut edges = oi_expr.edges_filtered::<Ident>(self.asg);
|
||||
|
||||
// note: the edges are reversed (TODO?)
|
||||
let value = edges
|
||||
.next()
|
||||
.diagnostic_expect(
|
||||
|| vec![oi_expr.note("for this match")],
|
||||
"missing @value ref",
|
||||
)
|
||||
.resolve(self.asg);
|
||||
let value = edges.next().diagnostic_expect(
|
||||
|| vec![oi_expr.note("for this match")],
|
||||
"missing @value ref",
|
||||
);
|
||||
|
||||
let on = edges
|
||||
.next()
|
||||
.diagnostic_expect(
|
||||
|| vec![oi_expr.note("for this match")],
|
||||
"missing @on ref",
|
||||
)
|
||||
.resolve(self.asg);
|
||||
let on = edges.next().diagnostic_expect(
|
||||
|| vec![oi_expr.note("for this match")],
|
||||
"missing @on ref",
|
||||
);
|
||||
|
||||
if let Some(unexpected) = edges.next() {
|
||||
diagnostic_panic!(
|
||||
|
@ -376,8 +372,8 @@ impl<'a> TreeContext<'a> {
|
|||
);
|
||||
}
|
||||
|
||||
self.push(attr_value(value.name()));
|
||||
self.push(attr_on(on.name()));
|
||||
self.push(attr_value(value.name_or_meta(self.asg)));
|
||||
self.push(attr_on(on.name_or_meta(self.asg)));
|
||||
|
||||
Xirf::open(QN_MATCH, OpenSpan::without_name_span(expr.span()), depth)
|
||||
}
|
||||
|
@ -391,9 +387,9 @@ impl<'a> TreeContext<'a> {
|
|||
depth: Depth,
|
||||
) -> Option<Xirf> {
|
||||
match src {
|
||||
Object::Ident((ident, _)) => {
|
||||
Object::Ident((_, oi_ident)) => {
|
||||
self.tpl_apply = None;
|
||||
self.push(attr_name(ident.name()));
|
||||
self.push(attr_name(oi_ident.name_or_meta(self.asg)));
|
||||
|
||||
Some(Xirf::open(
|
||||
QN_TEMPLATE,
|
||||
|
@ -438,7 +434,7 @@ impl<'a> TreeContext<'a> {
|
|||
"cannot derive name of template for application",
|
||||
);
|
||||
|
||||
self.push(attr_name(apply_tpl.resolve(self.asg).name()));
|
||||
self.push(attr_name(apply_tpl.name_or_meta(self.asg)));
|
||||
|
||||
Some(Xirf::open(
|
||||
QN_APPLY_TEMPLATE,
|
||||
|
@ -466,13 +462,12 @@ impl<'a> TreeContext<'a> {
|
|||
oi_meta: ObjectIndex<Meta>,
|
||||
depth: Depth,
|
||||
) -> Option<Xirf> {
|
||||
let pname =
|
||||
oi_meta
|
||||
.ident(self.asg)
|
||||
.map(Ident::name)
|
||||
.diagnostic_unwrap(|| {
|
||||
vec![meta.internal_error("missing param name")]
|
||||
});
|
||||
let pname = oi_meta
|
||||
.ident(self.asg)
|
||||
.map(|oi| oi.name_or_meta(self.asg))
|
||||
.diagnostic_unwrap(|| {
|
||||
vec![meta.internal_error("missing param name")]
|
||||
});
|
||||
|
||||
self.push(attr_name(pname));
|
||||
|
||||
|
@ -493,7 +488,7 @@ impl<'a> TreeContext<'a> {
|
|||
oi_meta: ObjectIndex<Meta>,
|
||||
depth: Depth,
|
||||
) -> Option<Xirf> {
|
||||
let pname = oi_meta.ident(self.asg).map(Ident::name)
|
||||
let pname = oi_meta.ident(self.asg).map(|oi| oi.name_or_meta(self.asg))
|
||||
.diagnostic_unwrap(|| vec![meta.internal_error(
|
||||
"anonymous metavariables are not supported as template arguments"
|
||||
)]);
|
||||
|
|
|
@ -105,12 +105,13 @@ fn graph_sort() -> SortResult<()> {
|
|||
let asg = asg_from_toks(toks);
|
||||
let sections = sort(&asg, StubSections { pushed: Vec::new() })?;
|
||||
|
||||
let expected = vec![
|
||||
let expected = [
|
||||
// Post-order
|
||||
name_a_dep_dep,
|
||||
name_a_dep,
|
||||
name_a,
|
||||
]
|
||||
.map(Some)
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
|
|
@ -113,10 +113,10 @@ impl<'a> XmleSections<'a> for Sections<'a> {
|
|||
fn push(&mut self, ident: &'a Ident) -> PushResult {
|
||||
self.deps.push(ident);
|
||||
|
||||
let name = ident.name();
|
||||
let frag = ident.fragment();
|
||||
let (resolved, name) = ident.resolved()?;
|
||||
|
||||
match ident.resolved()?.kind() {
|
||||
match resolved.kind() {
|
||||
Some(kind) => match kind {
|
||||
IdentKind::Cgen(..)
|
||||
| IdentKind::Gen(..)
|
||||
|
@ -156,7 +156,7 @@ impl<'a> XmleSections<'a> for Sections<'a> {
|
|||
// compiler bug and there is no use in trying to be nice
|
||||
// about a situation where something went terribly, horribly
|
||||
// wrong.
|
||||
return Err(SectionsError::MissingObjectKind(ident.name()));
|
||||
return Err(SectionsError::MissingObjectKind(name));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -256,7 +256,7 @@ fn test_writes_deps() -> TestResult {
|
|||
|
||||
assert_eq!(
|
||||
attrs.find(QN_NAME).map(|a| a.value()),
|
||||
Some(ident.name().symbol()),
|
||||
ident.name().map(|name| name.symbol()),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
|
|
Loading…
Reference in New Issue