issue 0153 RESOLVED: pin generic return-type resolution to the fn's defining module

inferGenericReturnType resolved a generic call's return-type AST ($R, !E) in
the CALL-SITE module context. For a re-exported fn the error-set name (LE /
IoErr, re-exported as LE :: lib.LE) resolved through the call-site alias to a
TypeId NOT tagged .error_set, so the planned result was a tuple whose last
field wasn't an error set — errorChannelOf saw a plain tuple and the value-
failable's ! channel was lost (try/or rejected it / built a malformed i1 PHI).

monomorphizeFunction already pins the source to the fn's defining module
before resolving the return type; inferGenericReturnType did not, so the
planned call-result type disagreed with the instance's real signature. Fix:
pin the source to fd.body.source_file around the return-type resolution
(binding-build stays in the call-site context — its args are typed there).

Regression test examples/1058-errors-reexport-value-failable-channel.sx
(+ companion lib.sx). Suite green 732/0.
This commit is contained in:
agra
2026-06-21 05:54:52 +03:00
parent a7499d5f51
commit 68c1991e11
8 changed files with 67 additions and 20 deletions

View File

@@ -0,0 +1,23 @@
// A generic value-failable fn `($R, !E)` reached through a RE-EXPORT alias
// keeps its `!` error channel at the call site — the result types as a
// value-failable, so `or` / `try` accept it. Mirrors std.sx's
// `await :: io_mod.await` (+ `IoErr :: io_mod.IoErr`) re-export.
// Regression (issue 0153): the planned call-result type was resolved in the
// CALL-SITE module (where `LE` is a re-export alias → a non-`.error_set`
// TypeId), so `errorChannelOf` saw a plain tuple and `b.get() or {…}` built a
// malformed i1 PHI. The fix pins return-type resolution to the fn's defining
// module, matching `monomorphizeFunction`. Needs BOTH generic + re-export.
#import "modules/std.sx";
lib :: #import "examples/1058-errors-reexport-value-failable-channel/lib.sx";
// Re-export the generic fn AND its error set (the std.sx facade pattern).
Box :: lib.Box;
get :: lib.get;
LE :: lib.LE;
main :: () -> i32 {
b : Box(i64) = .{ v = 42 };
r := b.get() or { -1 }; // value-failable channel preserved → r=42
print("r={}\n", r);
return 0;
}

View File

@@ -0,0 +1,8 @@
// Implementation module: a generic value-failable `ufcs` fn + its error set.
#import "modules/std.sx";
LE :: error { Bad }
Box :: struct ($R: Type) { v: R; }
// Returns `($R, !LE)` — a value-failable. `$R` is inferred from the arg.
get :: ufcs (b: *Box($R)) -> ($R, !LE) { return b.v; }

View File

@@ -0,0 +1 @@
r=42