Issue #833: Decision basis: should let g = fn(k) { ... } infer k from later calls, instead of NK1245?

Open and answer this issue on GitHub.

decision · opened 2026-10-25 · updated 2026-10-25 · 0 comments

From zero

A lambda’s parameters take their types from what receives the lambda. In xs.map(fn(n) { n + 1 }), n is an i64 because map over a Vec[i64] says so. A lambda bound to a local with no type has no receiver:

let g = fn(k) { "x" }
println(g(1))

Today this is refused with NK1245 (a type the compiler cannot tell), at g’s binding. Written let g: fn(i64) -> String = fn(k) { "x" }, it is accepted.

Where the question comes from

The #831 builder (52874392) met it while fixing a sync-inference defect and asked whether k should be inferred from the later call g(1). No program needs it. Writing the type is the workaround, and it is also the documented form.

What is already decided

ADR-286 D41: an expression whose type the compiler cannot tell is NK1245; a name is asked where it is bound and not where it is read. The list of exemptions (number literals, open numbers, integer comptime) does not include a lambda typed by its later calls. Part III’s NK1245 text and Part I 10 (line 863) say the same. So the behaviour is decided and correct as specified. The question would be whether to extend D41.

Options

How other languages do it: Rust infers a closure’s parameter types from its first use; Swift and Kotlin need the type when there is no context; TypeScript gives any or an error under noImplicitAny; Haskell and OCaml infer everything.

Recommendation

A. Nothing needs B, and B weakens D41’s rule that a name’s type is known at its binding. If the owner agrees, close this issue as answered.

Back to Open Issues