From 7d04d8262fdccea0ef290e71d12e5c7f39ac83c7 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sun, 11 Jan 2026 16:37:17 +0800 Subject: [PATCH] fix: duplicate definition check in let-in --- nix-js/src/ir/utils.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/nix-js/src/ir/utils.rs b/nix-js/src/ir/utils.rs index 67e1c76..c0553c3 100644 --- a/nix-js/src/ir/utils.rs +++ b/nix-js/src/ir/utils.rs @@ -414,15 +414,25 @@ where } ast::Entry::AttrpathValue(value) => { let attrpath = value.attrpath().unwrap(); - if let Some(first_attr) = attrpath.attrs().next() - && let ast::Attr::Ident(ident) = first_attr - { - let sym = ctx.new_sym(ident.to_string()); - if !binding_syms.insert(sym) { - return Err(Error::downgrade_error(format!( - "attribute '{}' already defined", - format_symbol(ctx.get_sym(sym)) - ))); + let attrs_vec: Vec<_> = attrpath.attrs().collect(); + + // Only check for duplicate definitions if this is a top-level binding (path length == 1) + // For nested paths (e.g., types.a, types.b), they will be merged into the same attrset + if attrs_vec.len() == 1 { + if let Some(ast::Attr::Ident(ident)) = attrs_vec.first() { + let sym = ctx.new_sym(ident.to_string()); + if !binding_syms.insert(sym) { + return Err(Error::downgrade_error(format!( + "attribute '{}' already defined", + format_symbol(ctx.get_sym(sym)) + ))); + } + } + } else if attrs_vec.len() > 1 { + // For nested paths, just record the first-level name without checking duplicates + if let Some(ast::Attr::Ident(ident)) = attrs_vec.first() { + let sym = ctx.new_sym(ident.to_string()); + binding_syms.insert(sym); } } }