From 087ef4515341bd241bb9e56e9838a5756dbebdb5 Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Sun, 30 Jul 2023 23:15:03 -0400 Subject: [PATCH] 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 --- tamer/src/asg/air.rs | 2 +- tamer/src/asg/air/meta/test.rs | 4 ++-- tamer/src/asg/air/tpl/test.rs | 10 +++++----- tamer/src/asg/air/tpl/test/apply.rs | 4 ++-- tamer/src/asg/graph/object/ident.rs | 31 +++++++++++++++++++++++++++-- tamer/src/asg/graph/visit/ontree.rs | 4 +++- 6 files changed, 42 insertions(+), 13 deletions(-) diff --git a/tamer/src/asg/air.rs b/tamer/src/asg/air.rs index 7373a362..ee567b8e 100644 --- a/tamer/src/asg/air.rs +++ b/tamer/src/asg/air.rs @@ -1105,7 +1105,7 @@ impl AirAggregateCtx { Ident: ObjectRelTo, { self.env_scope_lookup::(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 diff --git a/tamer/src/asg/air/meta/test.rs b/tamer/src/asg/air/meta/test.rs index 5b857b25..fbc18855 100644 --- a/tamer/src/asg/air/meta/test.rs +++ b/tamer/src/asg/air/meta/test.rs @@ -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::(asg), + MetaRel::Ident(oi) => oi.definition_narrow::(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) diff --git a/tamer/src/asg/air/tpl/test.rs b/tamer/src/asg/air/tpl/test.rs index c6c74f1b..6f0742a6 100644 --- a/tamer/src/asg/air/tpl/test.rs +++ b/tamer/src/asg/air/tpl/test.rs @@ -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::(&asg)) + .and_then(|oi| oi.definition_narrow::(&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::(oi_outer, id_param_outer) .expect("missing id_param_outer Ident") - .definition::(asg) + .definition_narrow::(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::(oi_outer, id_tpl_inner) .expect("could not locate inner Tpl's Ident") - .definition::(asg) + .definition_narrow::(asg) .expect("missing inner Tpl"); let span_inner = ctx .env_scope_lookup::(oi_inner, id_param_inner) .expect("missing id_param_inner Ident") - .definition::(asg) + .definition_narrow::(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::(asg) + .definition_narrow::(asg) .expect("abstract identifier did not bind to Expr"); assert_eq!(S3.merge(S5).unwrap(), oi_expr.resolve(asg).span()); diff --git a/tamer/src/asg/air/tpl/test/apply.rs b/tamer/src/asg/air/tpl/test/apply.rs index 3b9c5db8..6ccf9ee1 100644 --- a/tamer/src/asg/air/tpl/test/apply.rs +++ b/tamer/src/asg/air/tpl/test/apply.rs @@ -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::(&asg) + .definition_narrow::(&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::(&asg)) - .filter_map(|oi| oi.definition(&asg)) + .filter_map(|oi| oi.definition_narrow(&asg)) .collect::>(), ); } diff --git a/tamer/src/asg/graph/object/ident.rs b/tamer/src/asg/graph/object/ident.rs index bc4270a9..95249a4f 100644 --- a/tamer/src/asg/graph/object/ident.rs +++ b/tamer/src/asg/graph/object/ident.rs @@ -1282,8 +1282,35 @@ impl ObjectIndex { /// Look up the definition that this identifier binds to, /// if any. /// - /// See [`Self::bind_definition`]. - pub fn definition + 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<::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 + ObjectRelatable>( &self, asg: &Asg, ) -> Option> { diff --git a/tamer/src/asg/graph/visit/ontree.rs b/tamer/src/asg/graph/visit/ontree.rs index e8eddba5..e6d6517b 100644 --- a/tamer/src/asg/graph/visit/ontree.rs +++ b/tamer/src/asg/graph/visit/ontree.rs @@ -492,7 +492,9 @@ mod order { Ident(oi_ident) => { // This is the (comparatively) expensive lookup, // requiring a small graph traversal. - match oi_ident.definition::(asg) { + match oi_ident + .definition_narrow::(asg) + { Some(_) => TplOrder::Param, None => TplOrder::Body, }