# 0056 — parameterised-protocol impl not deduped across a diamond import **FIXED** (`examples/issue-0056-diamond-param-impl.sx`, helpers in `examples/issue-0056/`). The flat decl list in [src/imports.zig](../src/imports.zig) now dedups by **node identity** as well as by name. `ResolvedModule.mergeFlat` and the directory-import merge loop each carry a `seen_nodes: std.AutoHashMap(*Node, void)` alongside the existing `seen_in_list` name set, and skip a decl whose pointer was already appended. ## Symptom A module containing a parameterised-protocol impl (`impl Into(T) for S`) could not be imported through more than one path. Under a diamond — ``` main ─┬─ mid_a ─┐ └─ mid_b ─┴─ common (holds `impl Into(Wrapped) for s64`) ``` — compilation failed with: ``` error: duplicate impl 'Into' for source 's64' in .../common.sx ``` This bit the moment `modules/std/objc.sx` (imported by `main.sx`, `platform/uikit.sx`, and `gpu/metal.sx` — a diamond) gained an `impl Into(*NSString) for string`. ## Root cause `mergeFlat`/`addOwnDecl` dedup the global flat decl list by `decl.data.declName()`. Named decls (structs, fns, foreign classes) dedup fine across diamonds. But `impl_block` is anonymous — `declName()` returns `null` (see [src/ast.zig](../src/ast.zig) `Data.declName`) — so the dedup guard was skipped and the **same cached** impl node (modules are cached in `ModuleCache`, so both paths share one node pointer) was appended once per path. `registerParamImpl` in [src/ir/lower.zig](../src/ir/lower.zig) then saw two entries with the same `defining_module` and raised the same-file "duplicate impl" diagnostic. The pre-existing `impl Into(Block) for Closure(...)` in `modules/std/objc_block.sx` never tripped this because that module is not imported through any diamond. ## Reproduction `examples/issue-0056/common.sx`: ```sx Wrapped :: struct { v: s64; } impl Into(Wrapped) for s64 { convert :: (self: s64) -> Wrapped { return .{ v = self }; } } ``` `mid_a.sx` / `mid_b.sx` each `#import "common.sx";`. The diamond main: ```sx #import "modules/std.sx"; #import "issue-0056/mid_a.sx"; #import "issue-0056/mid_b.sx"; main :: () -> s32 { w : Wrapped = xx 7; // pre-fix: duplicate impl 'Into' for source 's64' print("{}\n", w.v); // post-fix: prints 7 0; } ``` ## Fix Dedup the flat decl list by node identity in addition to name — a physical AST node must be lowered once regardless of how many import paths reach it. Named-decl first-wins behaviour is unchanged. Regression test: `examples/issue-0056-diamond-param-impl.sx` (in `tests/run_examples.sh`).