Folds the coupled 0106 fix into Phase B. attempt-1 tightened the bare-name
visibility adapters (isNameVisible/isCImportVisible) to the flat_import_graph
edge set via the unified isVisible(.user_bare_flat/.c_import_bare) predicate;
that surfaced issue 0106 — std.print / log.* expand `#insert build_format(fmt)`
(comptime call) and `#insert "out(result);"` (inserted stmt) in the CONSUMER's
current_source_file, so their library-internal bare names were policed against
the consumer's imports and errored (run_examples 471 -> 467).
Fix: a precise, named exemption. Lowering.in_insert_expansion is set across
lowerInsertExprValue (the comptime eval + the parsed-back statements); the two
visibility adapters fall open while it is set — mirroring the existing
UFCS-alias / mangled-local "compiler indirection" exemptions. NOT a blanket
skip: scoped to #insert-expanded code, ordinary bare references stay policed.
Library-internal call bodies (build_format's concat/substr) already resolve in
the defining module — lowerFunctionBodyInto pins their current_source_file.
The flat tightening stays: a bare reference to a namespaced-only import's
internal name now correctly errors ('<name>' is not visible). This is the
Agra-ratified user-visible semantics change.
- face #1 pinned: examples/0736-modules-namespaced-only-bare-not-visible.sx
(+ a.sx) — exit 1 + stderr; fail-before (import_graph compiled it, exit 0) /
pass-after (flat set errors, exit 1).
- face #2 restored: examples 0015 / 0700 / 0718 / 1030 pass again.
- run_examples 471 -> 472 (the new regression).
- issues/0106 marked RESOLVED; readme.md documents namespaced-only visibility.
Collectors + unified predicate from attempt-1 (resolver.zig) unchanged; nothing
routes resolution AUTHOR-SELECTION through them yet (that is Phase C).
7.3 KiB
0106 — namespaced-import internal names are silently bare-visible (over-permissive isNameVisible)
RESOLVED (flow stdlib/B attempt-2). Two coupled changes:
- Tightened bare visibility to the flat edge set.
isNameVisible/isCImportVisiblenow route through the unifiedisVisiblepredicate overuser_bare_flat/c_import_bare(both join overflat_import_graph, notimport_graph). A namespaced-only import's internal name is no longer bare-visible — face #1 now errors'<name>' is not visible; #import the module that declares it.#insert-expansion visibility exemption. The flat tightening alone brokestd.print/log.*: a library metaprogram's#insert build_format(fmt)(comptime call) and#insert "out(result);"(inserted statement) expand in the CALL SITE'scurrent_source_file, so their bare names (build_format,out,emit) were policed against the consumer's imports. Fix: a precise, named exemption —Lowering.in_insert_expansionis set acrosslowerInsertExprValue(the comptime eval + the parsed-back statements), andisNameVisible/isCImportVisiblefall open while it is set. This mirrors the existing UFCS-alias / mangled-local "compiler indirection" exemptions; it is NOT a blanket skip (it scopes to#insert-expanded code; ordinary bare references are still policed). Library-internal call bodies (e.g.build_format'sconcat/substr) already resolve correctly — they lower vialowerFunctionBodyInto, which pinscurrent_source_fileto the defining module.Root cause:
isNameVisiblewalkedimport_graph(flat AND namespaced edges) where a bare name should join only overflat_import_graph. Regression:examples/0736-modules-namespaced-only-bare-not-visible.sx(+0736-…/a.sx) — face #1 pinned (exit 1 + the stderr). Face #2 restored:examples/0015 / 0700 / 0718 / 1030pass again (run_examples471 → 472). Fix insrc/ir/lower.zig(in_insert_expansion+ the two adapters) +src/ir/resolver.zig(VisibilityModemodes, landed in attempt-1).
Symptom. A bare reference to a top-level name authored in a module that the
consumer imports only namespaced (ns :: #import "m.sx") is silently
visible from the consumer. Observed: it compiles + runs. Expected: an error —
the name is reachable only as ns.name. Root: Lowering.isNameVisible walks
program_index.import_graph, which records BOTH flat (#import) and namespaced
(ns :: #import) edges; bare-name visibility should join only over FLAT edges
(flat_import_graph). This is the latent 0102-family visibility bug the Phase B
caller-mode audit (unified-resolver R5) was told to surface.
This directly gates flow stdlib/B: that step requires migrating
isNameVisible/isCImportVisible to the resolver's user_bare_flat/
c_import_bare modes (which walk flat_import_graph) byte-identically.
Switching the edge set drops run_examples from 471 → 467 (see face #2), so the
byte-identical requirement cannot hold until this bug is fixed.
Reproduction — face #1 (user-facing over-permissiveness)
// m.sx
secret :: () -> s64 { 7 }
// main.sx
m :: #import "m.sx";
main :: () -> s32 {
x := secret(); // bare; `secret` is only namespaced-imported as `m.secret`
0
}
- Observed (current master): compiles, runs, exit
0— baresecretwrongly resolves tom's author. - Expected:
error: 'secret' is not visible; #import the module that declares it(it is reachable only asm.secret).
(With the Phase-B edge-set change applied — isNameVisible over
flat_import_graph — this repro correctly errors, confirming the diagnosis.)
Reproduction — face #2 (library comptime entanglement: why a naive fix breaks std)
// main.sx
std :: #import "modules/std.sx";
main :: () -> s32 {
std.print("hello\n"); // legit qualified call
0
}
print in std.sx is a comptime metaprogram:
print :: ($fmt: string, ..$args) {
#insert build_format(fmt); // comptime call to a std-internal fn
#insert "out(result);"; // inserts a bare call to a std-internal fn
}
The comptime call to build_format and the inserted out(result) are bare
names authored in std.sx, but they are visibility-checked in the
consumer's current_source_file context (comptime / #insert expansion
happens at the call site). Today they pass only because import_graph[consumer]
contains the namespaced std edge. Tightening bare visibility to
flat_import_graph makes them error
('build_format' / 'out' is not visible). The same shape breaks log (emit).
Affected examples when the edge set is switched to flat:
0015-basic-demo, 0700-modules-import, 0718-modules-cli-exit-json,
1030-errors-log-and-comptime (467/471).
Root cause (suspected area)
Lowering.isNameVisible/isCImportVisible—src/ir/lower.zig(~1768-1840 after the Phase-B refactor;visibleOverEdges/nameVisibleOverEdges). The cross-module join usesimport_graph(flat and namespaced edges) where it should useflat_import_graphfor a bare name.- Comptime /
#insertexpansion context: the inserted/comptime-evaluated bare calls of a namespaced module's function are policed against the consumer's imports, not the defining module's own scope. The existing visibility check already exempts UFCS-alias rewrites and mangled local names as "compiler indirections" (lower.zigcall site ~7284, identifier site ~3237); inserted / comptime-generated bare calls are the same kind of indirection and are not yet exempt — or, equivalently, the expansion should restore the defining module'scurrent_source_file.
Investigation prompt (paste into a fresh session)
Fix issue 0106:
isNameVisibleover-permits bare references to a namespaced-only import's internal names. Two coupled changes, in this order:
- Library-internal context. Ensure a namespaced/comptime-expanded function's body — including
#inserted statements and comptime calls likebuild_formatinsidestd.print— is visibility-checked in its defining module's context, OR exempt compiler-generated /#inserted bare calls from the visibility check (mirror the UFCS-alias / mangled-name exemptions atsrc/ir/lower.zig~7284 and ~3237). Verify with the face-#2 repro and examples0015 / 0700 / 0718 / 1030.- Tighten bare visibility to flat. Change
isNameVisible(and thec_import_barefall-through ofisCImportVisible) to join overflat_import_graphinstead ofimport_graph— i.e. route them through the resolver'suser_bare_flat/c_import_baremodes (this is exactly Phase B of the unified-resolver R5 plan;src/ir/resolver.zigalready defines the modes andLowering.visibleOverEdgesalready takes a.flat/.allselector). Verify the face-#1 repro now errors.Acceptance: the face-#1 repro errors ("not visible");
bash tests/run_examples.shis back to 471okwith bare visibility on the flat edge set; add the face-#1 repro as a pinned regression (issues/0106-…with anexpected/marker, or promote toexamples/07xx-modules-…). Suspected files:src/ir/lower.zig(visibility + comptime/#insert expansion context),src/ir/resolver.zig(user_bare_flat/c_import_bare).