Open and answer this issue on GitHub.
ready · opened 2026-10-29 · updated 2026-10-29 · 1 comment
Found while changing the converter (crates/rs2nika/convert): todo in tr_core.nika started calling expr in tr_expr.nika, which already called todo. rustc then refused the lowered code. Once todo was moved into tr_expr.nika, the same code compiled.
Probe (a project; nikaia run):
src/main.nika
use std::fs
fn down(n: i64) -> i64 {
if n == 99 {
let s = fs::read_to_string("x", fs::Root::Anywhere) catch { "" }
return s.len()
}
if n <= 0 {
return 0
}
return up(n - 1) + 1
}
fn main() {
println(f"{down(5)}")
}
src/other.nika
fn up(n: i64) -> i64 {
if n <= 0 {
return 0
}
return down(n - 1) + 1
}
What happens:
error: Recursion in an async fn requires boxing.
--> src/main.nika:3:1
What should happen: it prints 5.
The variations narrow it down:
5.fs::read_to_string): prints 5.impl T split over the two files): fails the same way as free functions.So the lowering finds the recursion cycle of pausing functions, and boxes their futures, only within one file. A cycle that crosses files is missed.
tests/compiler/ with the two-file probe above, printing 5.Triage (#982), class B: waits for the rest of emit/mod.rs (E11 / E13, with_contracts’ analyses). emit/mod.rs:826 computes pausing_reach from one file’s items. Still reproduces at de0bb82.
Generated by Claude Code