I was looking through the docs for the basic-cli rc and saw the following invalid syntax as an annotation:
parser_for : encoding -> state -> Try({ value : Url, rest : state }, err)
and
encoder_for : encoding -> Url, state -> Try(state, err)
The parentheses seem to have been dropped that group the returned functions. The correct annotations (as in the source) would be
parser_for : encoding -> (state -> Try({ value : Url, rest : state }, err))
and
encoder_for : encoding -> (Url, state -> Try(state, err))
I would have put a PR in for this except that I became a bit confused about the binding of commas in bare parens vs in tags. E.g.
Foo(a, a -> a) is parsed to two payload types, a and a unary function a -> a, whereas : (a, a -> a) and : ((a, a -> a), ) parse to a plain binary function. Meanwhile, if you write
p3 : (I32, (I32 -> I32))
p3 = |a, b| a + b
The compiler will (correctly) tell you that the body doesn't match the annotation type, but will tell you in the error:
But the annotation says it should be:
(I32, I32 -> I32)
As written, that suggestion will parse to a binary function that p3's body satisfies.
Anyhow, that is to say
- The rendering of types in roc docs and some compiler error messages fails to parenthesize functions in tuples and in the return values of functions (although there may be a more general problem?)
Yes, the rule should be any function type gets parenthesized in every position except a top-level annotation slot, and neither printer (docs or error) implements that fully.
neither printer (docs or error)
Maybe these need to share code :thinking:
- Is it expected that in a tag's argument list, commas separate the tag's payloads (an arrow binds only within one slot), whereas in bare parens an arrow captures preceding commas as function parameters? The corollary of this is that you can't have a tuple containing an unparenthesised function.
This seems reasonable as is for me
This seems reasonable as is for me
Yeh I think it was surprising until I realised that was the overall rule, and that it was consistent within tags and within bare parens.
Yes, the rule should be any function type gets parenthesized in every position except a top-level annotation slot, and neither printer (docs or error) implements that fully.
I think the fix for docs' render_type.zig is fairly simple at least, just flip needs_parens to true by default except at the top level, and except for within .parens.
Last updated: Jul 23 2026 at 13:15 UTC