fix(0057): clear target_type when lowering variadic pack args

An `xx <int>` argument to a variadic `format`/`print` (a comptime `..$args`
pack) segfaulted when the call was inside an imported-module function. Root
cause: lowerPackCall lowered each pack arg with whatever self.target_type was
set to from the surrounding context. A bare arg is unaffected (inferExprType
ignores target_type), but `xx <expr>`'s result type IS target_type — so
`format("…", xx i)` inside a `-> string` fn cast the int to `string`,
monomorphized __pack_string, and ABI-coerced the 4-byte int as a 16-byte string
fat pointer → corruption. Inline it worked only because target_type was null
there; the imported-module path left it set.

Fix: save/clear/restore self.target_type around the pack-arg lowering loop. A
pack arg is independently typed — comptime `..$args` auto-boxes to Any; a value
pack takes its declared element/protocol type — never a leftover outer target.

examples/242-xx-any-pack-cross-module.sx (+ companion fmt.sx) is the regression.
issues/0057 marked resolved. Unblocks ERR E3.3 (the trace.sx formatter formats
frames with `xx frame`).

Gates: zig build, zig build test, bash tests/run_examples.sh (279 passed; lone
failure is the user's uncommitted 213-canonical-map pack WIP).
This commit is contained in:
agra
2026-06-01 08:51:44 +03:00
parent ea40724b61
commit a694d91bca
6 changed files with 157 additions and 0 deletions

View File

@@ -9591,6 +9591,16 @@ pub const Lowering = struct {
// lambda arg types its params from the projected closure signature.
// (A comptime `..$args` pack keeps `inferExprType` — its args may be
// type-position.)
// A pack arg is independently typed — it takes its natural type and
// (for a comptime `..$args` pack) auto-boxes to `Any` at the call
// boundary. It is NEVER coerced to a leftover outer `target_type`, so
// clear it: otherwise an `xx <expr>` pack arg (whose result type IS
// `target_type`) would cast to the stale target — e.g. `format("…", xx i)`
// inside a `-> string` fn mis-typed the arg as `string`, monomorphizing
// `__pack_string` and ABI-coercing the 4-byte int as a 16-byte fat
// pointer → memory corruption (issue 0057).
const saved_pack_tt = self.target_type;
self.target_type = null;
var pack_refs = std.ArrayList(Ref).empty;
defer pack_refs.deinit(self.alloc);
for (call_node.args[pack_start..]) |a| {
@@ -9603,6 +9613,7 @@ pub const Lowering = struct {
pack_arg_types.append(self.alloc, self.builder.getRefType(r)) catch return self.builder.constInt(0, .void);
}
}
self.target_type = saved_pack_tt;
// Install the pack's element types + constraint so prefix-arg param
// types like `Closure(..sources.T)` resolve while lowering the prefix.