ffi M5.A.next.2b.fu2.A: generic \$R pack-fn — lock in silent-zero return

Follow-up #2 from step 2b: pack-fns with a generic return type
(`(..\$args) -> \$R`). Today's `monomorphizePackFn` calls
`resolveReturnType` which sees `\$R` as a generic name and
returns an opaque struct TypeId. The mono's ret_ty is wrong
and the value silently coerces to 0.

`examples/159-pack-generic-ret.sx` pins this: `first(42)` and
`first(99)` both return `0` instead of the call arg. The lock-in
captures the wrong output as the snapshot to flip.

Next commit infers the ret type from the body's tail expression
(arrow form) or the first explicit `return X;` (block form),
then builds the mono signature against that concrete type.

198/198 example tests + \`zig build test\` green.
This commit is contained in:
agra
2026-05-27 16:22:49 +03:00
parent a39437261d
commit e44ba4b240
3 changed files with 25 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
// Variadic heterogeneous type packs — follow-up #2 (generic $R
// return type).
//
// A pack-fn's return type can be a generic name (`$R`) — bound at
// the call site to match the body's natural type or the caller's
// target. Today's `monomorphizePackFn` calls `resolveReturnType`
// which treats `$R` as an opaque struct, so the mono's signature
// gets a wrong ret_ty and the value is silently zero / garbage.
//
// `first(42)` should return 42; the lock-in pins today's `0`.
// Next commit infers the ret type from the body's tail expression
// (or first `return X;`) and rebuilds the mono signature.
#import "modules/std.sx";
first :: (..$args) -> $R => args[0];
main :: () -> s32 {
a : s64 = first(42);
b : s64 = first(99);
print("{} {}\n", a, b);
return 0;
}

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1 @@
0 0