Removes the S2.x pre-pass and its 10 NodeRefTable maps — 1934 net lines
deleted. The Resolver gains two lazy functions: resolveBare(name, from,
domain) and resolveQualified(target, name), each returning ResolvedAuthors
(verdict + author set). verdictOver and authoredAsDomainAnywhere move from
ResolvePass to Resolver as private methods. All domain-predicate helpers
(eligibleKind, structDeclOf, fnDeclOf, etc.) are promoted to pub.
Test file trimmed from 1352 to 396 lines; old pre-pass population tests
replaced by focused resolveBare / resolveQualified verdict tests.
540/540 regression tests pass. Zero behavior change.
Move the author-SELECTION SEMANTICS (the verdicts) into the resolver. Every
`.authors` ResolvedRef now carries the verdict the resolver COMPUTES above the
collector — own-wins / single-flat-visible / ≥2-ambiguous / not-visible /
type-vs-value domain-filtered — evaluated over the DOMAIN-ELIGIBLE subset of the
collected author set (`eligibleKind`). This folds the per-kind selection the old
lower-side selectors carried (selectNominalLeaf / flatTypeAuthorCount /
selectModuleConst / selectPlainCallableAuthor / selectGenericStructHead /
headTypeGate / headFnLeak) into ONE uniform computation, closing the
protocol / error-set / foreign per-kind surfaces (E6c/d/e) as resolver behavior.
Template/pack grammar stays carried as `.template` / `.pack` refs — NO
`sig_registration_mode`.
ADDITIVE / PARALLEL / UNCONSUMED: lowering still reads the old selectors, so the
verdict changes no generated byte. No file outside resolver.zig reads
ResolvedRef, so byte-identity is structural. ResolvedRef.authors is wrapped into
{ set, verdict } (the RAW set is preserved; the verdict filters).
Resolver unit tests prove the verdicts on real Phase A facts: the five bare-type
outcomes incl. the type-vs-value filter, and the resolver-target classes the old
selectors get WRONG — 0811 error-set / 0821 protocol-head / 0829 generic-struct
all → ambiguous (two flat authors, none own) and → own-wins (own author present).
The resolver-target corpus stays xfail in run_examples (unconsumed until S3.9);
verdicts asserted via the harness, not by flipping goldens.
Gate: zig build && zig build test (430) && tests/run_examples.sh (540 byte-identical),
all exit 0; tests/resolver-target 18 xfail unchanged.
On the S2.1a owning traversal, populate the last three ResolvedProgram side
tables, closing planspec S2.1's full-population acceptance (all ten domains):
- foreign_class_refs: a bare reference whose collected author is a
foreign_class_decl is routed here (its own domain) instead of the bare
type/value/callable table.
- struct_const_refs: a Type.CONST field access whose base resolves to a
struct author carrying that const member (mirrors lowering's struct_const_map).
- ufcs_refs: a ufcs_alias decl (alias -> target author) plus its UFCS-rewrite
call sites (alias(args), incl. pipe-desugared), via a global traversal-ordered
alias map mirroring lowering's flat ufcs_alias_map.
Still PARALLEL / UNCONSUMED / RAW: lowering reads the OLD selectors, no consumer
cut over, ResolvedRef stays raw. Byte-identical vs baseline (540 examples).
Population proof extended: a new resolver.test fixture exercises all ten domains
at once and asserts each side table non-empty + node-keyed for the three new ones.
On the S2.1a exhaustive traversal, populate four more ResolvedProgram side
tables, still RAW / PARALLEL / UNCONSUMED:
- namespace-qualified references: an `alias.member` field_access whose base
alias is a NamespaceEdges[ambient_source] target resolves via
collectNamespaceAuthors into namespace_refs, keyed by the access node.
- the three HEAD domains at parameterized_type_expr heads, binned by the
resolved author's decl kind: a struct with type params -> generic_struct_heads,
a fn/const-wrapped fn with type params -> type_fn_heads, a protocol ->
protocol_heads. RAW: the whole author set is recorded with no winner picked;
a name authored as >1 head kind lands a distinct entry in every matching table.
Lowering still reads the old selectors and resolved_program has no consumer, so
generated output is byte-identical. ResolvedRef stays RAW (selection is S2.2);
generics stay symbolic. S2.1c (foreign-class / struct-const / UFCS) owns the
remaining three tables.
Extends the population proof: a resolver unit test asserting all four tables are
non-empty + node-keyed with the expected RAW authors.
Gate (all exit 0): zig build; zig build test (All 427 mod + exe + LSP sweep 574);
tests/run_examples.sh (540 passed, byte-identical); tests/resolver-target
(18 xfail, 0 leaked); m3te ios-sim via the main sx binary.
Turn src/ir/resolver.zig from a raw author-collection facade into the OWNING
resolution pass: one exhaustive recursive AST walk (exhaustive switch over
ast.Node.Data with NO else arm, so a new node kind is a compile error here
rather than a silently unvisited subtree) populating a ResolvedProgram.
- ResolvedProgram: all 10 node-keyed side tables declared as
AutoHashMap(*const ast.Node, ResolvedRef) + symbolic TemplateParamId/
PackParamId registries. ResolvedRef is the S2.1 RAW form — collected author
identity (AuthorSet, own ∪ flat), NO verdict (own-wins/ambiguity is S2.2).
- Populate the 3 bare-name domains (type / value-const / callable heads) via
collectVisibleAuthors(.user_bare_flat); record $T / ..$Ts / $pack[i] as
SYMBOLIC template/pack refs, never TypeIds. The 7 head/qualified/foreign
domains stay declared-but-empty (S2.1b/c own them).
- Slot via Compilation.resolveProgram() after the program_index facts are
wired and before lowerRoot; ResolvedProgram owned on Compilation, borrowed
*ResolvedProgram lent to ProgramIndex (lowerToIR signature unchanged).
- Population proof unit test over real Phase A facts: the 3 tables are
non-empty, keyed by node identity, and carry symbolic template/pack refs.
ADDITIVE / PARALLEL / UNCONSUMED: lowering still reads the OLD selectors, so
single-author output is byte-identical. Gate green: zig build; zig build test
(425/425, LSP smoke 574 files no crash); run_examples (540 passed, 0 failed,
byte-identical incl. FFI 12xx-14xx + 1615 ios-sim); resolver-target (18 xfail
unchanged).
Delete module_fns as a separate function-author fact source. Its authors
already live in the module_decls raw facts, so lowerRetainedSameNameAuthors now
reads function authors straight out of module_decls (filtered to *FnDecl via
fnDeclOfRaw) — the same path → name → RawDeclRef store, fn-filtered. Remove
imports.ModuleFns / FnIndex / indexModuleFns / buildModuleFns / fnDeclOf, the
Compilation.module_fns field + its build + wiring, and ProgramIndex.module_fns.
Remove VisibilityMode.legacy_direct_any (the quarantined own-scope-plus-full-
import_graph mode): no production caller passed it, so the collectVisibleAuthors
and isVisible switch arms that handled it are dead and go too, collapsing
VisEdgeSet to the single flat-import walk. No semantic fallback is introduced;
import_graph stays the transitive-visibility source for findVisibleImpls.
Additive: the old maps stay active and lowering still consumes them — no
lowering consumer is cut over to the DeclTable (that is S3), and no resolution
behavior changes. Tests that drove the removed symbols are rerouted through
module_decls / the flat-edge walk.
Gate over the baseline-green corpus: zig build, zig build test (424/424),
bash tests/run_examples.sh (540 passed) — all exit 0; single-author output
byte-identical; multi-author 0722–0740 stdout/exit unchanged.