fix(lower): closure literals compose with bare function-type slots (issue 0060)
A closure's underlying function carries a hidden env arg that a bare (T)->U slot
doesn't pass, so a closure flowing into a bare function-type slot dropped the
env — the first user arg landed in the env slot and the rest read garbage
(apply(closure((x)->s64 { x*2 })) returned 192 instead of 10; non-failable too).
- createClosureToBareFnAdapter: a capture-free closure into a bare (T)->U slot is
bridged by a generated adapter carrying the bare ABI (forwards a null env);
lowerLambda returns its func_ref. Rejected (no silent miscompile): a capturing
closure into a bare slot (env has nowhere to live) and a failable closure into
a non-failable slot (the ERR E5.1 FFI-boundary rule).
- Arrow-body failable closures (-> (T,!) => expr) now wrap the bare success value
into {value, 0} via lowerFailableSuccessReturn (the implicit return previously
returned a malformed tuple → caught value read as 0).
The isLambda .bang parser fix (failable closure literals parse) already landed in
485b4fa. Regressions: examples/0309-closures-literal-as-bare-fn-param (non-
failable, block + arrow, called in callee) + 1039-errors-failable-closure-literal
(failable, block + arrow, direct + Closure(...) param). Resolves issue 0060
(remaining E5.1 follow-ups noted in the .md). Suite: 328 passed.
This commit is contained in:
17
examples/0309-closures-literal-as-bare-fn-param.sx
Normal file
17
examples/0309-closures-literal-as-bare-fn-param.sx
Normal file
@@ -0,0 +1,17 @@
|
||||
// Regression (issue 0060): a closure LITERAL passed directly as a bare
|
||||
// function-type argument `(T) -> U` and then called inside the callee. The
|
||||
// closure's underlying function takes a hidden env arg that a bare fn-ptr slot
|
||||
// doesn't pass, so the compiler bridges a capture-free closure to the bare ABI
|
||||
// with a generated adapter. Both block and arrow bodies. (The working contrast
|
||||
// where the param is a `Closure(...)` type is examples/0302.)
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
apply :: (f: (s64) -> s64) -> s64 { return f(5); }
|
||||
twice :: (f: (s64) -> s64, x: s64) -> s64 { return f(f(x)); }
|
||||
|
||||
main :: () {
|
||||
print("block={}\n", apply(closure((x: s64) -> s64 { return x * 2; }))); // 10
|
||||
print("arrow={}\n", apply(closure((x: s64) -> s64 => x * 2))); // 10
|
||||
print("twice={}\n", twice(closure((x: s64) -> s64 => x + 3), 1)); // ((1+3)+3) = 7
|
||||
}
|
||||
24
examples/1039-errors-failable-closure-literal.sx
Normal file
24
examples/1039-errors-failable-closure-literal.sx
Normal file
@@ -0,0 +1,24 @@
|
||||
// Failable closure literals (ERR E5.1): a `closure(...)` literal may declare a
|
||||
// failable return type — `-> (T, !)` / `-> !Named` — in both block and arrow
|
||||
// body forms, and `raise` inside. Called directly through the bound local, the
|
||||
// error channel is consumed by `catch` / `or`; passed as a `Closure(...)`
|
||||
// parameter, it composes through the callee (here absorbed with `catch`).
|
||||
// (A capturing closure into a bare `(T)->U` slot, and a failable closure into a
|
||||
// non-failable slot, are rejected — see issue 0060 / the FFI-boundary rule.)
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
E :: error { Neg }
|
||||
|
||||
runwith :: (cb: Closure(s64) -> (s64, !E), n: s64) -> s64 { return cb(n) catch e -1; }
|
||||
|
||||
main :: () -> s32 {
|
||||
// block-body and arrow-body failable closures, called directly
|
||||
m := closure((x: s64) -> (s64, !E) { if x < 0 { raise error.Neg; } return x * 2; });
|
||||
n := closure((x: s64) -> (s64, !E) => x + 1);
|
||||
print("{} {} {} {}\n", m(5) catch e 0, m(-1) catch e 99, m(-1) or 7, n(40) catch e 0); // 10 99 7 41
|
||||
|
||||
// failable closure passed as a Closure(...) parameter
|
||||
print("param ok={} err={}\n", runwith(m, 5), runwith(m, -1)); // 10 -1
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
block=10
|
||||
arrow=10
|
||||
twice=7
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
10 99 7 41
|
||||
param ok=10 err=-1
|
||||
Reference in New Issue
Block a user