issues: file 0059 — expr-bodied lambda inferred return type panics LLVM emission
An expression-bodied lambda `f :: (x: s32) => x * 2;` without an explicit return type reaches emit_llvm declareFunction with func.ret = .unresolved and trips the emission guard panic. Explicit `-> s32` works; the same lambda inside a large module (the old 50-smoke.sx) resolves fine — so inferred-return resolution for => lambdas runs only conditionally. Repro co-located. Surfaced while splitting 50-smoke.sx (test-layout migration); the functions section uses this exact construct, so the split is paused per the impassable rule (no workaround).
This commit is contained in:
88
issues/0059-expr-lambda-inferred-return-unresolved-type.md
Normal file
88
issues/0059-expr-lambda-inferred-return-unresolved-type.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# 0059 — expression-bodied lambda with inferred return type reaches LLVM emission unresolved
|
||||
|
||||
## Symptom
|
||||
|
||||
An expression-bodied lambda (`name :: (params) => expr;`) **without** an explicit
|
||||
return-type annotation aborts the compiler with:
|
||||
|
||||
```
|
||||
thread … panic: unresolved type reached LLVM emission — a type resolution failure was not diagnosed/aborted
|
||||
src/ir/emit_llvm.zig:4594 toLLVMTypeInfo (.unresolved => @panic(...))
|
||||
src/ir/emit_llvm.zig:4457 toLLVMType
|
||||
src/ir/emit_llvm.zig:1658 declareFunction ← const raw_ret_ty = self.toLLVMType(func.ret);
|
||||
src/ir/emit_llvm.zig:322 emit
|
||||
```
|
||||
|
||||
- **Observed:** the lambda's `func.ret` is `.unresolved` when `declareFunction`
|
||||
runs, so emission panics (SIGABRT, exit 134).
|
||||
- **Expected:** the inferred return type (`s32` here) is resolved before
|
||||
emission; the program prints `14` and exits 0.
|
||||
|
||||
## Reproduction
|
||||
|
||||
`issues/0059-expr-lambda-inferred-return-unresolved-type.sx` (standalone):
|
||||
|
||||
```sx
|
||||
#import "modules/std.sx";
|
||||
|
||||
f :: (x: s32) => x * 2; // inferred return type
|
||||
|
||||
main :: () {
|
||||
print("{}\n", f(7)); // want: 14
|
||||
}
|
||||
```
|
||||
|
||||
`./zig-out/bin/sx run issues/0059-expr-lambda-inferred-return-unresolved-type.sx`
|
||||
→ panic above.
|
||||
|
||||
### Key contrasts (narrowing clues)
|
||||
|
||||
- **Explicit return type works:** `f :: (x: s32) -> s32 => x * 2;` → prints `14`,
|
||||
exit 0.
|
||||
- **The same lambda inside a large program works:** the old monolithic
|
||||
`50-smoke.sx` contained `double :: (x: s32) => x * 2;` as a local const and ran
|
||||
clean (exit 0). The panic only appears when the expr-bodied inferred-return
|
||||
lambda is compiled in a *small* module (minimal file, or as the first/only such
|
||||
function). This strongly suggests the return-type inference for `=>` lambdas is
|
||||
triggered as a side effect of some other pass that the large file happens to run
|
||||
and the minimal file does not — rather than being driven unconditionally for
|
||||
every expr-bodied lambda.
|
||||
- Both the **top-level** form (`f :: (x: s32) => x * 2;`) and the **local-const**
|
||||
form (inside `main`) panic identically.
|
||||
|
||||
## Investigation prompt (paste into a fresh session)
|
||||
|
||||
> An expression-bodied lambda `f :: (x: s32) => x * 2;` with an inferred return
|
||||
> type panics at `src/ir/emit_llvm.zig:4594` ("unresolved type reached LLVM
|
||||
> emission") because `func.ret` is still `.unresolved` when `declareFunction`
|
||||
> (emit_llvm.zig:1658) emits it. Adding an explicit `-> s32` fixes it, and the
|
||||
> same lambda compiled inside a large module (the old 50-smoke.sx) resolves fine
|
||||
> — so the inferred-return resolution for `=>` lambdas is running only
|
||||
> conditionally.
|
||||
>
|
||||
> Suspected area: the return-type inference for expression-bodied (`=>`) lambdas
|
||||
> in `src/ir/lower.zig` (lambda lowering / `inferExprType` of the lambda body) or
|
||||
> the sema lambda path — the inferred return type is computed lazily / on-demand
|
||||
> and the demand isn't created for a lambda that is only *called* (not, e.g.,
|
||||
> involved in whatever the big file does). Compare the block-bodied lambda path
|
||||
> (`(x) { ... }`) and the explicit-`->`-return path, both of which resolve.
|
||||
>
|
||||
> Fix likely needs to: force the expr-bodied lambda's return type to be inferred
|
||||
> and resolved during lowering of the lambda literal itself (so `func.ret` is
|
||||
> concrete before emission), independent of call sites; OR, if a body genuinely
|
||||
> can't be inferred, emit a real diagnostic instead of leaving `.unresolved` to
|
||||
> trip the emission guard.
|
||||
>
|
||||
> Verification: `./zig-out/bin/sx run issues/0059-expr-lambda-inferred-return-unresolved-type.sx`
|
||||
> should print `14` and exit 0. Then confirm the existing lambda/inference tests
|
||||
> still pass: `0203-generics-infer-return-type`, `0300-closures-lambda`,
|
||||
> `0021-basic-expression-bodied-fn`, plus `bash tests/run_examples.sh`.
|
||||
|
||||
## Impact on current work
|
||||
|
||||
Blocks the `50-smoke.sx` split (test-layout migration, Phase 2): the
|
||||
**functions** section exercises exactly this construct
|
||||
(`double :: (x: s32) => x * 2;`), so it cannot be extracted into a standalone
|
||||
example until this is fixed. Working around it (adding an explicit return type)
|
||||
would stop testing inferred-return lambdas and hide the bug, so per the project's
|
||||
impassable rule the split is paused here.
|
||||
15
issues/0059-expr-lambda-inferred-return-unresolved-type.sx
Normal file
15
issues/0059-expr-lambda-inferred-return-unresolved-type.sx
Normal file
@@ -0,0 +1,15 @@
|
||||
// Repro for issue 0059: an expression-bodied `=>` lambda with an INFERRED
|
||||
// return type reaches LLVM emission with an unresolved return type and panics.
|
||||
// Adding an explicit `-> s32` makes it work; so does burying the same lambda
|
||||
// inside a large program (examples/.../50-smoke had it and ran fine).
|
||||
//
|
||||
// Expected: prints `14`, exit 0.
|
||||
// Actual: panic "unresolved type reached LLVM emission" (SIGABRT, exit 134).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
f :: (x: s32) => x * 2;
|
||||
|
||||
main :: () {
|
||||
print("{}\n", f(7));
|
||||
}
|
||||
Reference in New Issue
Block a user