I want to ask about the possibility of changing the parsing flow. In short, can we consider each line with the same indentation either a separate expression or statement (except pipes, if/when patterns, and the other comprehendible cases)? So the parser doesn't assume what the author meant but asks for clarification via parsing error.
I admit I could be naive and not recognize a larger problem behind this proposal.
Let's talk about the expectations behind this snippet:
main =
c = a
b
c
Right now it's parsed as if c is the continuation of b expression
main =
c = a
b
c
But it may have been meant that b is the continuation of a:
main =
c = a
b
c
There is also a third option now! It might be the await bang was missed:
main =
c = a
b!
c
(I will omit further explorations of parser behavior after the bang is added. But for example, since the parser now implies the last two lines in my first snippet as b a, it makes sense to expect the last two lines in the bang example are b! a. It's not like this now)
So the original snippet is very ambiguous at least for me. I would expect a parsing error to be thrown instead. Smth like
main =
c = a
b
c <-- unexpected expression, might be caused by missed indentation or lack of await bang
Or even
main =
c = a
b <-- unused expression. maybe you meant await bang or application?
c
Because my gut feeling says each line on the same indentation level is either a statement or a separate expression.
+1 to the general idea
@Joshua Warner brought up a similar idea awhile ago, although I'm not sure if it's written down anywhere? :sweat_smile:
Yep, I think that's here: https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/Design.3A.20Indents.20and.20Blocks
But yeah, I think especially with the new ! syntax this makes more sense than ever
Took another swing at this: https://github.com/roc-lang/roc/pull/6809 (wip; not quite ready for review)
A notable change here is that this used to parse, but no longer does:
when b is 3->4
9
|8->9
In particular, the issue is that when we enter the ->4 block, we set the min_indent to be the indent of the current line plus one (i.e. min_indent=1), which leads to the rest of the input being parsed as part of the expression (which of course doesn't work!)
It's unclear to me whether that's an important case to have parse + reformat :thinking:
That used to parse? I'm kinda stunned
I would assume a new line is required before the 3
Haha, yeah - it's with_multiline_pattern_indentation from test_fmt :)
My suspicion is that this is left over from some point in the past when when branches were required to line up exactly in column number, as I've seen be the style in some other languages.
Or at least this is a test that tries to make sure we can accept that style and do something sensible
Last updated: Jun 16 2026 at 16:19 UTC