fix: inherit in recursive attribute sets
This commit is contained in:
@@ -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<SymId, (ExprId, TextRange)> = 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)?;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user