Skip to content

Commit 9af0261

Browse files
Stevengreclaudedkcumming
authored
fix(rt): handle zero-sized function types in decode and ZST recognition (#813)
## Summary Fix two issues preventing correct handling of zero-sized function item types (e.g., non-capturing closures): 1. **`#zeroSizedType` did not recognize `typeInfoFunType`** (`types.md`) — Function items are inherently zero-sized (`#elemSize` already returns 0), but `#zeroSizedType` returned `false`, preventing `rvalueRef` from materializing uninitialized closure locals. 2. **`#decodeConstant` had no rule for `typeInfoFunType`** (`data.md`) — Zero-sized function constants fell through to the `thunk` wrapper instead of decoding to `Aggregate(variantIdx(0), .List)`. ## Evidence `closure-staged.rs` with `terminate-on-thunk`: | | Steps | Result | |---|---|---| | Before | 44 | `thunk(#decodeConstant(constantKindZeroSized, _, typeInfoFunType(_)))` | | After | 266 | `#EndProgram` | --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Daniel Cumming <124537596+dkcumming@users.noreply.github.com>
1 parent eafe909 commit 9af0261

3 files changed

Lines changed: 11 additions & 3 deletions

File tree

kmir/src/kmir/kdist/mir-semantics/rt/data.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,6 +1921,9 @@ Zero-sized types can be decoded trivially into their respective representation.
19211921
// zero-sized array
19221922
rule <k> #decodeConstant(constantKindZeroSized, _TY, typeInfoArrayType(_, _))
19231923
=> Range(.List) ... </k>
1924+
// zero-sized function item (e.g., closures without captures)
1925+
rule <k> #decodeConstant(constantKindZeroSized, _TY, typeInfoFunType(_))
1926+
=> Aggregate(variantIdx(0), .List) ... </k>
19241927
```
19251928

19261929
Allocated constants of reference type with a single provenance map entry are decoded as references

kmir/src/kmir/kdist/mir-semantics/rt/types.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,9 @@ Slices, `str`s and dynamic types require it, and any `Ty` that `is_sized` does
348348
rule #zeroSizedType(typeInfoTupleType(.Tys, _)) => true
349349
rule #zeroSizedType(typeInfoStructType(_, _, .Tys, _)) => true
350350
rule #zeroSizedType(typeInfoVoidType) => true
351-
// FIXME: Only unit tuples, empty structs, and void are recognized here; other
352-
// zero-sized types (e.g. single-variant enums, function or closure items,
351+
rule #zeroSizedType(typeInfoFunType(_)) => true
352+
// FIXME: Only unit tuples, empty structs, void, and function items are
353+
// recognized here; other zero-sized types (e.g. single-variant enums,
353354
// newtype wrappers around ZSTs) still fall through because we do not consult
354355
// the layout metadata yet. Update once we rely on machineSize(0).
355356
rule #zeroSizedType(_) => false [owise]

kmir/src/tests/integration/test_integration.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
'iter-eq-copied-take-dereftruncate': ['repro'],
4242
'spl-multisig-iter-eq-copied-next': ['repro'],
4343
}
44+
PROVE_TERMINATE_ON_THUNK = [
45+
'closure-staged',
46+
]
4447
PROVE_SHOW_SPECS = [
4548
'local-raw-fail',
4649
'interior-mut-fail',
@@ -87,7 +90,8 @@ def test_prove(rs_file: Path, kmir: KMIR, update_expected_output: bool) -> None:
8790
if update_expected_output and not should_show:
8891
pytest.skip()
8992

90-
prove_opts = ProveOpts(rs_file, smir=is_smir)
93+
should_terminate_on_thunk = rs_file.stem in PROVE_TERMINATE_ON_THUNK
94+
prove_opts = ProveOpts(rs_file, smir=is_smir, terminate_on_thunk=should_terminate_on_thunk)
9195
printer = PrettyPrinter(kmir.definition)
9296
cterm_show = CTermShow(printer.print)
9397

0 commit comments

Comments
 (0)