Open and answer this issue on GitHub.
ready · opened 2026-11-01 · updated 2026-11-01 · 0 comments
The fix for #1120 (brief docs/briefs/bugs/b28-1120-fn-type-fn-param.md) lowers a function type inside the parameters of another function type, fn(i64, fn() -> i64 sync) -> i64 sync, to nikaia_std::func::Kept<dyn Fn() -> i64>, an Arc. Each call of the outer function then allocates on the heap for an inner function that lives only for that call. Owner, 2026-11-01: the simple form first, then this issue to make it right.
The inner function is only run during the call: it is not kept, crosses no thread and outlives nothing. Rust says that with &dyn Fn() -> i64 (or &dyn for<'call> Fn(..) with views). No allocation, no reference count.
Probe (after #1120 is fixed): the lowered Rust of
fn twice(scoped: fn(i64, fn() -> i64 sync) -> i64 sync) -> i64 sync { return scoped(1, fn() { return 2 }) + 1 }
fn main() { println(f"{twice(fn(at, run) { return at + run() })}") }
shows Kept(std::sync::Arc::new(..)) at scoped(1, ..); expected: &|| 2 / &dyn Fn() -> i64.
emit_core_types.nika, an inner code type in a code parameter’s parameter list that is only run (not stored, not returned, not sent) lowers to &dyn Fn(..) -> R (+ Send + Sync only where it crosses); the argument side lends &|..| .. instead of Kept(Arc::new(..)).Kept.tests/compiler/tests/ checking the lowered form (no Arc::new at the call) and the output.docs/measuring.md) on a loop that calls such a function often.