Two defects from the Phase A attempt-1 review.
F1 — duplicate-name diagnostic missed NAMESPACE ALIASES (silent first-win).
`addNamespace` unconditionally put the alias into scope/own_decls, so a
same-module collision between an authored decl and a `dup :: #import "…"`
alias compiled clean in the fn-then-alias order (the scalar
ModuleRawDeclIndex silently first-won). Now `addNamespace` returns a bool
and refuses a same-module duplicate (mirroring addOwnDecl); the call site
surfaces it via the new `reportDuplicateName` (the import_decl node has no
declName, so the alias name is passed explicitly). The C-import namespace
site gets the same guard. Both orders now emit "duplicate top-level
declaration 'X'" and exit nonzero (alias-then-fn was already caught by
addOwnDecl seeing the alias in scope).
F2 — buildImportFacts errors were swallowed by `else |_| {}` in core.zig
(REJECTED-PATTERN catch-all leaving the borrowed store silently empty).
`resolveImports` returns !void, so the call is now a plain `try` and a
build failure propagates instead of producing a stale/empty store.
Tests: extend the dup-name regression with fn-vs-namespace-alias
collisions in both orders. No resolution behavior change (no lower.zig
edits; run_examples 471 byte-identical); m3te ios-sim builds via the
worktree binary.
Phase A of the unified resolver (R5 locked design). Additive infrastructure
with NO behavior change — builds the import-side raw-fact store; nothing
consumes it yet.
- imports.zig: add RawDeclRef / RawAuthor / ModuleRawDeclIndex / ModuleDecls /
NamespaceTarget / NamespaceEdges, plus buildImportFacts (mirrors
buildModuleFns) producing a scalar per-module name→RawDeclRef index + the
namespace edges. Callable without IR lowering (LSP reuses it later).
- ast.zig: NamespaceDecl gains target_module_path, captured at resolution time
(the resolved_path otherwise lost on the node) so the namespace edge records
the alias target.
- imports.zig: same-module duplicate top-level name is now DIAGNOSED
("duplicate top-level declaration 'X'") where addOwnDecl would silently drop
the second author — replaces the discarded `_ =` at the three call sites.
- program_index.zig: borrowed views module_decls / namespace_edges (like
module_fns); deinit does not free them.
- core.zig: build the facts alongside buildModuleFns and point the borrowed
views at them.
- imports.test.zig: index unit tests (flat / directory / namespaced file /
namespaced directory / C-import namespace / same-name fn / same-name struct /
value-vs-type same spelling / raw const_decl) + the duplicate-name diagnostic
regression (fails pre-fix, passes after).
Gate (worktree): zig build, zig build test (incl. LSP corpus sweep), and
run_examples (471, byte-identical) all green; m3te ios-sim build exits 0.
Attempt-1 retained a same-name cross-module FUNCTION author in the merged
decl list (mergeFlat + the directory merge), which is the list the existing
first-wins resolver consumes. That changed the data feeding resolution
(`mod.decls` carried two `greet`), violating this step's purpose: additive
indexes with ZERO resolution change.
Revert both merge sites to byte-for-byte first-wins, exactly as on
wt-fix-0102-base. The dropped same-name author is still retained — but only
in the SEPARATE `module_fns` index, which is built from each module's
`own_decls` (un-deduped, per-path) and which nothing reads yet. The
`flat_import_graph` side data is likewise untouched. Both are foundation
for fix-0102c's bare-name disambiguation; current resolution is unchanged.
Drop the now-unused `declAuthorsFn` helper (its only callers were the two
merge sites). `fnDeclOf` stays — it feeds the index.
Tests: the existing unit test now asserts the merged scope stays first-wins
(one `greet`, a.sx's author) while `module_fns` still retains BOTH authors
and `flat_import_graph` excludes the namespaced edge. Add a mixed non-fn/fn
collision test asserting the merged scope keeps a.sx's struct (first-wins),
unchanged by the function author.
First of four fix-0102 sub-steps. Purely additive: retains data that the
flat/directory merge currently first-wins-drops and builds two identity
indexes for later bare-name disambiguation (fix-0102c). No resolution
change — the existing first-wins bare path still wins; suite unchanged.
- mergeFlat + directory merge: stop dropping a same-name FUNCTION authored
by a different module/file. Non-function decls keep first-wins dedup; node
identity dedup is untouched.
- flat_import_graph: a flat-only subset of import_graph, recording an edge
only for a bare `#import` (imp.name == null), never a namespaced
`ns :: #import`. Threaded through resolveImports/resolveDirectoryImport
and into ProgramIndex.
- module_fns (path -> name -> *const FnDecl): per-module authored-function
index mirroring module_scopes, built in core.zig from the main module +
cache. Same-name cross-module authors stay distinct under their own paths.
- imports.test.zig: asserts both a.sx/b.sx greet authors are retained in
module_fns and in the global flat list, and that flat_import_graph
excludes the namespaced edge while import_graph includes it.
Gate (this worktree): zig build, zig build test (398/398),
bash tests/run_examples.sh (457 passed) all green.