tamer: asg::graph::object::ident::definition{=>_narrow} and new `definition`

This renames the previous operation to `definition_narrow` and creates a new
`definition` that does not attempt to narrow.  This is important for
distinguishing between a missing defintion and a definition of a given type,
and will be important now that we're beginning to reason about identifiers
that were resolved during parsing.

DEV-13163
main
Mike Gerwitz 2023-07-30 23:15:03 -04:00
parent 1c06605188
commit 087ef45153
6 changed files with 42 additions and 13 deletions

View File

@ -1105,7 +1105,7 @@ impl AirAggregateCtx {
Ident: ObjectRelTo<O>,
{
self.env_scope_lookup::<Ident>(env, name)
.and_then(|oi| oi.definition(self.asg_ref()))
.and_then(|oi| oi.definition_narrow(self.asg_ref()))
}
/// Attempt to retrieve an identifier from the graph by name relative to

View File

@ -298,7 +298,7 @@ fn assert_concat_list<'a, IT, IE: 'a>(
.edges(asg)
.filter_map(|rel| match rel {
MetaRel::Meta(oi) => Some(oi),
MetaRel::Ident(oi) => oi.definition::<Meta>(asg),
MetaRel::Ident(oi) => oi.definition_narrow::<Meta>(asg),
MetaRel::Doc(_) => None,
})
.map(ObjectIndex::cresolve(asg))
@ -362,7 +362,7 @@ where
"could not locate stub template (did you call \
air_ctx_from_tpl_body_toks without parse_as_tpl_body?)",
)
.definition(ctx.asg_ref())
.definition_narrow(ctx.asg_ref())
.expect("missing stub template definition (test setup bug?)");
(ctx, oi_tpl)

View File

@ -592,7 +592,7 @@ fn tpl_nested() {
let oi_tpl_inner_ident =
oi_tpl_outer.lookup_local_linear(&asg, id_tpl_inner);
let tpl_inner = oi_tpl_inner_ident
.and_then(|oi| oi.definition::<Tpl>(&asg))
.and_then(|oi| oi.definition_narrow::<Tpl>(&asg))
.map(ObjectIndex::cresolve(&asg));
assert_eq!(S3.merge(S5), tpl_inner.map(Tpl::span));
@ -699,7 +699,7 @@ fn metavars_within_exprs_hoisted_to_parent_tpl() {
let span_outer = ctx
.env_scope_lookup::<Ident>(oi_outer, id_param_outer)
.expect("missing id_param_outer Ident")
.definition::<Meta>(asg)
.definition_narrow::<Meta>(asg)
.expect("missing id_param_outer definition")
.resolve(asg)
.span();
@ -709,13 +709,13 @@ fn metavars_within_exprs_hoisted_to_parent_tpl() {
let oi_inner = ctx
.env_scope_lookup::<Ident>(oi_outer, id_tpl_inner)
.expect("could not locate inner Tpl's Ident")
.definition::<Tpl>(asg)
.definition_narrow::<Tpl>(asg)
.expect("missing inner Tpl");
let span_inner = ctx
.env_scope_lookup::<Ident>(oi_inner, id_param_inner)
.expect("missing id_param_inner Ident")
.definition::<Meta>(asg)
.definition_narrow::<Meta>(asg)
.expect("missing id_param_inner definition")
.resolve(asg)
.span();
@ -780,7 +780,7 @@ fn expr_abstract_bind_produces_cross_edge_from_ident_to_meta() {
// The identifier should be bound to the expression.
let oi_expr = oi_ident
.definition::<Expr>(asg)
.definition_narrow::<Expr>(asg)
.expect("abstract identifier did not bind to Expr");
assert_eq!(S3.merge(S5).unwrap(), oi_expr.resolve(asg).span());

View File

@ -185,7 +185,7 @@ fn tpl_apply_nested_missing() {
let oi_tpl_inner = oi_tpl_outer
.lookup_local_linear(&asg, id_tpl_inner)
.expect("could not locate inner template as a local")
.definition::<Tpl>(&asg)
.definition_narrow::<Tpl>(&asg)
.expect("could not resolve inner template ref to Tpl");
// We should have two inner template applications.
@ -206,7 +206,7 @@ fn tpl_apply_nested_missing() {
inners
.iter()
.flat_map(|oi| oi.edges_filtered::<Ident>(&asg))
.filter_map(|oi| oi.definition(&asg))
.filter_map(|oi| oi.definition_narrow(&asg))
.collect::<Vec<_>>(),
);
}

View File

@ -1282,8 +1282,35 @@ impl ObjectIndex<Ident> {
/// Look up the definition that this identifier binds to,
/// if any.
///
/// See [`Self::bind_definition`].
pub fn definition<O: ObjectRelFrom<Ident> + ObjectRelatable>(
/// _It is assumed that an identifier has only a single definition_.
/// If this invariant is not upheld,
/// 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> {
self.edges(asg).next()
}
/// Look up the definition that this identifier binds to,
/// if any,
/// and attempt to narrow its type.
///
/// This can be read as "attempt to find a definition of this
/// [`ObjectKind`]".
/// It cannot distinguish between the absence of a definition,
/// and one that does not meet the provided criterion.
/// If this distinction is important,
/// see [`Self::definition`].
///
/// _It is assumed that an identifier has only a single definition_.
/// If this invariant is not upheld,
/// then the definition that is returned is undefined.
///
/// See also [`Self::bind_definition`].
pub fn definition_narrow<O: ObjectRelFrom<Ident> + ObjectRelatable>(
&self,
asg: &Asg,
) -> Option<ObjectIndex<O>> {

View File

@ -492,7 +492,9 @@ mod order {
Ident(oi_ident) => {
// This is the (comparatively) expensive lookup,
// requiring a small graph traversal.
match oi_ident.definition::<object::Meta>(asg) {
match oi_ident
.definition_narrow::<object::Meta>(asg)
{
Some(_) => TplOrder::Param,
None => TplOrder::Body,
}