fix(lower): pin defining-module context for pack/comptime metaprograms; drop #insert exemption [stdlib B attempt-3]
ROOT FIX for issue 0106's library-metaprogram half — no exemption.
attempt-2 masked the 0106 fallout with an `in_insert_expansion` flag that
made the visibility adapters fall open during ANY `#insert` expansion,
including a USER's `#insert <expr>` — so a bare reach into a namespaced-only
import from user `#insert` code wrongly compiled (Adi's blocker). The flag
was the wrong shape. This removes it and fixes the real cause.
Root cause: a metaprogram's body (`std.print` / `std.format` / `log.*`,
whose `#insert build_format(fmt)` + `#insert "out(result);"` reference
std-internal bare names) was lowered under the CALL SITE's
`current_source_file`, so those names were policed against the consumer's
imports. Normal functions get this right via `lowerFunctionBodyInto`, which
pins `func.source_file`; the two monomorphizers don't:
- `monomorphizePackFn` — bare `print(...)` / `format(...)` (pack path).
- `lowerComptimeCall` — namespaced `std.print` / `log.warn` (reached via
the field-access `hasComptimeParams` branch).
Fix: both paths now save/set/restore `current_source_file` to the body's
DEFINING module around the BODY lowering only (call-site args stay in the
caller's context). The defining path is stamped onto each function body node
by `resolveImports` (`stampFnBodySource`), mirroring `Function.source_file`.
So library internals resolve in std.sx/log.sx naturally, while a USER's
`#insert <expr>` is still checked in the user's context.
- Exemption GONE: `in_insert_expansion` flag + both adapter fall-open checks
deleted; `isNameVisible`/`isCImportVisible` are byte-identical adapters.
- New pinned regression: examples/0737-modules-insert-bare-not-visible.sx
(+ a.sx) — a USER `#insert secret()` into a namespaced-only import errors
('secret' is not visible). fail-before exit 0 on the attempt-2 binary /
pass-after exit 1.
- face #1 (0736) still errors; face #2 (0015/0700/0718/1030) pass again WITH
NO exemption — the metaprogram body resolves in its own module.
- run_examples 472 -> 473; zig build test 412/412; m3te ios-sim build exit 0.
- issues/0106 RESOLVED banner updated (root cause + no-exemption fix).
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
# 0106 — namespaced-import internal names are silently bare-visible (over-permissive `isNameVisible`)
|
||||
|
||||
> **RESOLVED** (flow stdlib/B attempt-2). Two coupled changes:
|
||||
> **RESOLVED** (flow stdlib/B attempt-3 — root fix, no exemption). Two coupled
|
||||
> changes:
|
||||
>
|
||||
> 1. **Tightened bare visibility to the flat edge set.** `isNameVisible` /
|
||||
> `isCImportVisible` now route through the unified `isVisible` predicate over
|
||||
@@ -8,28 +9,41 @@
|
||||
> `import_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`.
|
||||
> 2. **`#insert`-expansion visibility exemption.** The flat tightening alone broke
|
||||
> `std.print` / `log.*`: a library metaprogram's `#insert build_format(fmt)`
|
||||
> (comptime call) and `#insert "out(result);"` (inserted statement) expand in
|
||||
> the CALL SITE's `current_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_expansion` is set across
|
||||
> `lowerInsertExprValue` (the comptime eval + the parsed-back statements), and
|
||||
> `isNameVisible` / `isCImportVisible` fall 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`'s `concat` / `substr`) already resolve correctly — they lower
|
||||
> via `lowerFunctionBodyInto`, which pins `current_source_file` to the defining
|
||||
> module.
|
||||
> 2. **Pin the defining-module context during pack/comptime monomorphization.**
|
||||
> The flat tightening alone broke `std.print` / `log.*`: a library metaprogram's
|
||||
> body (`#insert build_format(fmt)` comptime call + the `#insert "out(result);"`
|
||||
> inserted statement) was lowered under the CALL SITE's `current_source_file`,
|
||||
> so its bare names (`build_format`, `out`, `emit`) were policed against the
|
||||
> consumer's imports. **Root cause:** `monomorphizePackFn` (bare `print` /
|
||||
> `format`) and `lowerComptimeCall` (namespaced `std.print` / `log.*`, reached
|
||||
> via the field-access `hasComptimeParams` branch) lower the metaprogram body
|
||||
> without pinning the source context — unlike a normal function, which lowers
|
||||
> via `lowerFunctionBodyInto` pinning `func.source_file`. **Fix:** both paths
|
||||
> now save/set/restore `current_source_file` to the body's DEFINING module
|
||||
> before lowering the body (the call-site ARGS are lowered first, in the
|
||||
> caller's context, which is correct). The defining path is stamped onto each
|
||||
> function body node by `resolveImports` (`stampFnBodySource`, mirroring how a
|
||||
> declared function carries `Function.source_file`). So the metaprogram's bare
|
||||
> `build_format` / `out` / `emit` resolve in `std.sx` / `log.sx` naturally —
|
||||
> and a USER's `#insert <expr>` is still checked in the USER's context, so a
|
||||
> bare reach into a namespaced-only import there errors. **No `#insert`
|
||||
> exemption** (attempt-2's `in_insert_expansion` flag is deleted): the fix is
|
||||
> the absence of an exemption, not a narrower one.
|
||||
>
|
||||
> Root cause: `isNameVisible` walked `import_graph` (flat AND namespaced edges)
|
||||
> where a bare name should join only over `flat_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 / 1030` pass again (`run_examples` 471 → 472).
|
||||
> Fix in `src/ir/lower.zig` (`in_insert_expansion` + the two adapters) +
|
||||
> `src/ir/resolver.zig` (`VisibilityMode` modes, landed in attempt-1).
|
||||
> where a bare name should join only over `flat_import_graph`; and the pack /
|
||||
> comptime monomorphizers lowered the metaprogram body under the wrong source
|
||||
> context.
|
||||
> Regressions: `examples/0736-modules-namespaced-only-bare-not-visible.sx` (+
|
||||
> `0736-…/a.sx`) — face #1 pinned (exit 1 + the stderr);
|
||||
> `examples/0737-modules-insert-bare-not-visible.sx` (+ `0737-…/a.sx`) — a USER
|
||||
> `#insert secret()` into a namespaced-only import errors (fail-before exit 0 on
|
||||
> the attempt-2 exemption / pass-after exit 1). Face #2 restored WITHOUT an
|
||||
> exemption: `examples/0015 / 0700 / 0718 / 1030` pass again (`run_examples`
|
||||
> 471 → 473). Fix in `src/ir/lower.zig` (`monomorphizePackFn` +
|
||||
> `lowerComptimeCall` source-context pin; exemption removed) + `src/imports.zig`
|
||||
> (`stampFnBodySource`) + `src/ir/resolver.zig` (`VisibilityMode` modes, 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
|
||||
|
||||
Reference in New Issue
Block a user