diff --git a/oal-compiler/src/eval.rs b/oal-compiler/src/eval.rs index 32ac755..b76f4f6 100644 --- a/oal-compiler/src/eval.rs +++ b/oal-compiler/src/eval.rs @@ -128,11 +128,15 @@ impl<'a> Context<'a> { .cloned() } - /// Returns a unique identifier for the given node within the current scope. - fn node_identifier(&self, node: NRef) -> atom::Ident { - let scope_id = self.scopes.last().map_or(0, |(id, _)| *id); + /// Returns a unique identifier for the given node. + /// + /// If `scoped` is true, the identifier is unique per evaluation scope. + fn node_identifier(&self, node: NRef, scoped: bool) -> atom::Ident { let mut hash = Sha256::new(); - hash.update(scope_id.to_be_bytes()); + if scoped { + let scope_id = self.scopes.last().map_or(0, |(id, _)| *id); + hash.update(scope_id.to_be_bytes()); + } node.digest(&mut hash); atom::Ident::from(format!("hash-{:x}", hash.finalize())) } @@ -437,7 +441,9 @@ pub fn eval_declaration<'a>( if ident.is_reference() || decl.node().syntax().core_ref().is_recursive { if !ident.is_reference() { - ident = ctx.node_identifier(decl.node()); + // As declarations only appear at the global scope, + // The identifier does not depend on the scope of evaluation. + ident = ctx.node_identifier(decl.node(), false); } // Make sure we evaluate the reference or recursive declaration only once. let expr = if !ctx.refs.contains_key(&ident) { @@ -755,7 +761,7 @@ pub fn eval_recursion<'a>( rec: syn::Recursion<'a, Core>, ann: AnnRef, ) -> Result<(Expr<'a>, AnnRef)> { - let ident = ctx.node_identifier(rec.node()); + let ident = ctx.node_identifier(rec.node(), true); let mut scope = HashMap::new(); let recursion = (Expr::Recursion(ident.clone()), AnnRef::default()); scope.insert(rec.binding().ident(), recursion); diff --git a/oal-compiler/src/eval_tests.rs b/oal-compiler/src/eval_tests.rs index 95d1bb4..229a1d4 100644 --- a/oal-compiler/src/eval_tests.rs +++ b/oal-compiler/src/eval_tests.rs @@ -814,6 +814,20 @@ fn eval_recursive_content() -> anyhow::Result<()> { Ok(()) } +#[test] +fn eval_recursive_content_function() -> anyhow::Result<()> { + let s = eval_check( + r#" + let c s = ; + let r = / on get -> c 200; + res r; + "#, + )?; + assert_eq!(s.rels.len(), 1); + assert_eq!(s.refs.len(), 1); + Ok(()) +} + #[test] fn eval_inner_recursive_lambda() -> anyhow::Result<()> { let s = eval_check(