diff --git a/nix-js/src/ir/utils.rs b/nix-js/src/ir/utils.rs index 48312bb..e970982 100644 --- a/nix-js/src/ir/utils.rs +++ b/nix-js/src/ir/utils.rs @@ -398,6 +398,25 @@ where } } + // IMPORTANT: For `inherit x` (without `from`), we must look up `x` in the OUTER scope + // BEFORE adding the rec's slots to the scope. Otherwise, `x` would resolve to its own + // slot, causing infinite recursion. + let mut inherit_lookups: HashMap = HashMap::new(); + for entry in &entries { + if let ast::Entry::Inherit(inherit) = entry + && inherit.from().is_none() + { + for attr in inherit.attrs() { + if let ast::Attr::Ident(ident) = attr { + let span = ident.syntax().text_range(); + let sym = ctx.new_sym(ident.to_string()); + let expr = ctx.lookup(sym, span)?; + inherit_lookups.insert(sym, (expr, span)); + } + } + } + } + let binding_keys: Vec<_> = binding_syms.into_iter().collect(); let slots: Vec<_> = ctx.reserve_slots(binding_keys.len()).collect(); let let_bindings: HashMap<_, _> = binding_keys @@ -421,7 +440,20 @@ where for entry in entries { match entry { ast::Entry::Inherit(inherit) => { - downgrade_inherit(inherit, &mut temp_attrs.stcs, ctx)?; + if inherit.from().is_some() { + // `inherit (from) x` - process normally, `from` may reference current scope + downgrade_inherit(inherit, &mut temp_attrs.stcs, ctx)?; + } else { + // `inherit x` - use pre-looked-up expressions from outer scope + for attr in inherit.attrs() { + if let ast::Attr::Ident(ident) = attr { + let sym = ctx.new_sym(ident.to_string()); + if let Some(&(expr, span)) = inherit_lookups.get(&sym) { + temp_attrs.stcs.insert(sym, (expr, span)); + } + } + } + } } ast::Entry::AttrpathValue(value) => { downgrade_static_attrpathvalue(value, &mut temp_attrs, ctx)?; diff --git a/nix-js/tests/basic_eval.rs b/nix-js/tests/basic_eval.rs index af85462..ff3b682 100644 --- a/nix-js/tests/basic_eval.rs +++ b/nix-js/tests/basic_eval.rs @@ -3,6 +3,8 @@ mod utils; use nix_js::value::Value; use utils::eval; +use crate::utils::eval_result; + #[test] fn arithmetic() { assert_eq!(eval("1 + 1"), Value::Int(2)); @@ -63,3 +65,8 @@ fn nested_let() { Value::Int(3) ); } + +#[test] +fn rec_inherit_fails() { + assert!(eval_result("{ inherit x; }").is_err()); +}