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 binding_keys: Vec<_> = binding_syms.into_iter().collect();
|
||||||
let slots: Vec<_> = ctx.reserve_slots(binding_keys.len()).collect();
|
let slots: Vec<_> = ctx.reserve_slots(binding_keys.len()).collect();
|
||||||
let let_bindings: HashMap<_, _> = binding_keys
|
let let_bindings: HashMap<_, _> = binding_keys
|
||||||
@@ -421,7 +440,20 @@ where
|
|||||||
for entry in entries {
|
for entry in entries {
|
||||||
match entry {
|
match entry {
|
||||||
ast::Entry::Inherit(inherit) => {
|
ast::Entry::Inherit(inherit) => {
|
||||||
|
if inherit.from().is_some() {
|
||||||
|
// `inherit (from) x` - process normally, `from` may reference current scope
|
||||||
downgrade_inherit(inherit, &mut temp_attrs.stcs, ctx)?;
|
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) => {
|
ast::Entry::AttrpathValue(value) => {
|
||||||
downgrade_static_attrpathvalue(value, &mut temp_attrs, ctx)?;
|
downgrade_static_attrpathvalue(value, &mut temp_attrs, ctx)?;
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ mod utils;
|
|||||||
use nix_js::value::Value;
|
use nix_js::value::Value;
|
||||||
use utils::eval;
|
use utils::eval;
|
||||||
|
|
||||||
|
use crate::utils::eval_result;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn arithmetic() {
|
fn arithmetic() {
|
||||||
assert_eq!(eval("1 + 1"), Value::Int(2));
|
assert_eq!(eval("1 + 1"), Value::Int(2));
|
||||||
@@ -63,3 +65,8 @@ fn nested_let() {
|
|||||||
Value::Int(3)
|
Value::Int(3)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rec_inherit_fails() {
|
||||||
|
assert!(eval_result("{ inherit x; }").is_err());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user