I’ve been lurking on the closure threads (Mojo Closures 2026, When should thin or unified be used?) and wanted to share something that came up while building a YANG parser.
I was trying to store function pointers in a dispatch table:
Dict[String, fn(mut DummyParser, String) raises -> YangType]
After an initial compiler crash, I eventually got this:
error: 'Dict' parameter 'V' has 'Copyable & ImplicitlyDestructible' type,
but value has type 'AnyTrait[def(mut DummyParser, String) raises -> YangType]'
The fix was adding thin:
Dict[String, def(mut DummyParser, String) thin raises -> YangType]
The error message isn’t wrong. But it also didn’t get me there. I had to already know that thin changes the closure representation, that capturing closures aren’t Copyable in this context, and that thin is the fix when you don’t need capture semantics. None of that is in the diagnostic.
Compare to something like:
Function values stored in Dict require 'thin' function pointers.
Capturing closures are not 'Copyable & ImplicitlyDestructible' in this context.
If you don't need closure capture, add the 'thin' qualifier.
That’s not just friendlier — it’s structurally different. It surfaces the constraint, names the trade-off, and points at the repair. The compiler already knows all of this when it generates the error. It just doesn’t say it.
I realize this is partly a general compiler UX question, but I think it’s particularly relevant for Mojo given where it’s headed. A few things make this more than a quality-of-life issue:
AI coding agents. The standard AI loop right now is: generate → compile → parse error text → guess repair → retry. It works surprisingly well, but it’s wasteful. The compiler did the hard semantic work already; it just discarded the structure before printing. Repair-oriented diagnostics would let agents narrow the valid program space directly instead of guessing.
The thin/closure design space is genuinely subtle. Looking at the open closure threads, it’s clear this isn’t a documentation problem — the semantics are still being worked out. That makes it even more important that the compiler surfaces why a type fails a constraint, not just that it did.
It compounds with MLIR leakage. There’s a recent thread on errors dropping into MLIR. Repair-oriented diagnostics and better MLIR abstraction feel like two sides of the same problem: the compiler has rich internal structure that isn’t making it out to the user.
A few questions for the community:
-
Has anyone found patterns for working around opaque diagnostics in the short term, beyond just knowing the type system well enough to infer the fix?
-
Is there a tracking issue for structured/machine-readable diagnostic output, or is this something worth proposing formally?
-
For the Modular team: is there appetite for a structured diagnostic API alongside the human-readable output? Even unstable JSON output would help tooling significantly.
The thin case was a small thing, but it pointed at something bigger. The compiler is doing semantic work that it’s not exposing. That gap matters more as both humans and AI agents rely on it for recovery, not just rejection.