diff --git a/tamer/src/asg/air.rs b/tamer/src/asg/air.rs index ccf0f37c..15c33ac6 100644 --- a/tamer/src/asg/air.rs +++ b/tamer/src/asg/air.rs @@ -929,19 +929,81 @@ impl AirAggregateCtx { }) } - /// Root an identifier using the [`Self::rooting_oi`] atop of the stack. - fn defines(&mut self, name: SPair) -> Result, AsgError> { + /// Root a concrete identifier using the [`Self::rooting_oi`] atop of + /// the stack. + /// + /// This definition will index the identifier into the proper + /// environments, + /// giving it scope. + /// If the identifier is abstract, + /// it is important to use [`Self::defines_abstract`] instead so that + /// the metavariable that the identifier references will not be + /// indexed as the binding `name`. + fn defines_concrete( + &mut self, + binding_name: SPair, + ) -> Result, AsgError> { let oi_root = self .rooting_oi() - .ok_or(AsgError::InvalidBindContext(name))?; + .ok_or(AsgError::InvalidBindContext(binding_name))?; - Ok(self.lookup_lexical_or_missing(name).add_edge_from( + Ok(self.lookup_lexical_or_missing(binding_name).add_edge_from( self.asg_mut(), oi_root, None, )) } + /// Define an abstract identifier within the context of a container that + /// is able to hold dangling objects. + /// + /// If the identifier is concrete, + /// then it is important to use [`Self::defines_concrete`] instead to + /// ensure that the identifier has its scope computed and indexed. + /// + /// TODO: This is about to evolve; + /// document further. + fn defines_abstract( + &mut self, + meta_name: SPair, + ) -> Result, AsgError> { + // To help mitigate potentially cryptic errors down the line, + // let's try to be helpful and notify the user when + // they're trying to do something that almost certainly + // will not succeed. + match self.dangling_expr_oi() { + // The container does not support dangling expressions + // and so there is no chance that this expression will + // be expanded in the future. + None => { + let rooting_span = self + .rooting_oi() + .map(|oi| oi.widen().resolve(self.asg_ref()).span()); + + // Note that we _discard_ the attempted bind token + // and so remain in a dangling state. + Err(AsgError::InvalidAbstractBindContext( + meta_name, + rooting_span, + )) + } + + // We don't care what our container is, + // only that the above check passed. + // That is: + // the above check is entirely optional and intended + // only as a debugging aid for users. + Some(_) => { + let oi_meta_ident = self.lookup_lexical_or_missing(meta_name); + + let oi_abstract = oi_meta_ident + .new_abstract_ident(self.asg_mut(), meta_name.span()); + + Ok(oi_abstract) + } + } + } + /// Attempt to retrieve an identifier and its scope information from the /// graph by name relative to the environment `env`. /// diff --git a/tamer/src/asg/air/expr.rs b/tamer/src/asg/air/expr.rs index a187c1ba..a9715f22 100644 --- a/tamer/src/asg/air/expr.rs +++ b/tamer/src/asg/air/expr.rs @@ -123,7 +123,7 @@ impl ParseState for AirExprAggregate { } (BuildingExpr(es, oi), AirBind(BindIdent(id))) => { - let result = ctx.defines(id).and_then(|oi_ident| { + let result = ctx.defines_concrete(id).and_then(|oi_ident| { oi_ident.bind_definition(ctx.asg_mut(), id, oi) }); @@ -139,53 +139,15 @@ impl ParseState for AirExprAggregate { } (BuildingExpr(es, oi), AirBind(BindIdentAbstract(meta_name))) => { - // To help mitigate potentially cryptic errors down the line, - // let's try to be helpful and notify the user when - // they're trying to do something that almost certainly - // will not succeed. - match ctx.dangling_expr_oi() { - // The container does not support dangling expressions - // and so there is no chance that this expression will - // be expanded in the future. - None => { - let rooting_span = ctx - .rooting_oi() - .map(|oi| oi.widen().resolve(ctx.asg_ref()).span()); - - // Note that we _discard_ the attempted bind token - // and so remain in a dangling state. - Transition(BuildingExpr(es, oi)).err( - AsgError::InvalidAbstractBindContext( - meta_name, - rooting_span, - ), - ) - } - - // We don't care what our container is, - // only that the above check passed. - // That is: - // the above check is entirely optional and intended - // only as a debugging aid for users. - Some(_) => { - let oi_meta_ident = - ctx.lookup_lexical_or_missing(meta_name); - - let oi_abstract = oi_meta_ident.new_abstract_ident( - ctx.asg_mut(), - meta_name.span(), - ); - - // Note that we are still dangling, - // since the identifier is abstract and is - // therefore not yet reachable via its - // yet-to-be-determined identifier. - oi_abstract - .bind_definition(ctx.asg_mut(), meta_name, oi) - .map(|_| ()) - .transition(BuildingExpr(es, oi)) - } - } + // Note that we are still dangling, + // since the identifier is abstract and is therefore not + // yet reachable via its yet-to-be-determined identifier. + ctx.defines_abstract(meta_name) + .and_then(|oi_ident| { + oi_ident.bind_definition(ctx.asg_mut(), meta_name, oi) + }) + .map(|_| ()) + .transition(BuildingExpr(es, oi)) } (BuildingExpr(es, oi), AirBind(RefIdent(name))) => { diff --git a/tamer/src/asg/air/meta.rs b/tamer/src/asg/air/meta.rs index f32fa321..e9a7c990 100644 --- a/tamer/src/asg/air/meta.rs +++ b/tamer/src/asg/air/meta.rs @@ -81,7 +81,7 @@ impl ParseState for AirMetaAggregate { .incomplete(), (TplMeta(oi_meta), AirBind(BindIdent(name))) => ctx - .defines(name) + .defines_concrete(name) .and_then(|oi_ident| { oi_ident.bind_definition(ctx.asg_mut(), name, oi_meta) }) diff --git a/tamer/src/asg/air/tpl.rs b/tamer/src/asg/air/tpl.rs index 2aa3fadd..5792f515 100644 --- a/tamer/src/asg/air/tpl.rs +++ b/tamer/src/asg/air/tpl.rs @@ -175,7 +175,7 @@ impl ParseState for AirTplAggregate { } (Toplevel(tpl), AirBind(BindIdent(id))) => ctx - .defines(id) + .defines_concrete(id) .and_then(|oi_ident| { oi_ident.bind_definition(ctx.asg_mut(), id, tpl.oi()) })