otp
otp copied to clipboard
"binary patterns cannot be matched in parallel using =" on an assignment
foo(X) ->
<<>> = (<<>> = 42).
is rejected by erlc with test.erl:5:3: binary patterns cannot be matched in parallel using '='.
This surprised me because I expected it to be parsed as follows:
foo(X) ->
X = (<<>> = 42),
<<>> = X.
Which is accepted.
Even weirder, the following is accepted:
foo(X) ->
<<>> = begin <<>> = 42 end.
Showing that (Expr)
and begin Expr end
are not treated equivalently by the compiler.
Looking at the documentation in
- https://www.erlang.org/doc/reference_manual/expressions.html#parenthesized-expressions
- https://www.erlang.org/doc/reference_manual/expressions.html#bit-syntax-expressions
- https://www.erlang.org/doc/programming_examples/bit_syntax.html#segments
I could not find anything warning of this rather surprising behavior.
So I don't know whether this is a bug in erlc or just a missing piece of documentation (or maybe it is documented somewhere else?).
You have encountered an undocumented limitation in the pattern matching compilation.
Pattern matching of multiple patterns is done in parallel. So if we have:
Pat1 = Pat2 = Pat3 ... PatN = Expr
all the patterns will be consolidated into a single pattern:
Pat = Expr
For example:
{Tag, Value} = E = {ok, N} = Expr
will be consolidated like so:
{ok=Tag, Value=N}=E = Expr
Parentheses in the source code are not explicitly represented in the parse tree (abstract code). Parentheses used in patterns will only change in which order multiple patterns are consolidated. The end result will always be the same.
begin
... end
, on the other hand, has an explicit representation in the parse tree, and when used in patterns will force the pattern matching to be evaluated sequentially.
The consolidation of patterns breaks down for binary patterns in parallel. When the binary syntax was first introduced in Erlang/OTP R7, there was no way to express the consolidation of parallel binary patterns in Core Erlang for patterns such as the one in this example:
bar(Bin) ->
<<A:8,B:24>> = <<C:16,D:16>> = Bin,
{A, B, C, D}.
I will have to think about what do. I see two possibilities:
- Document the limitation.
- Make parallel matching work for binary patterns (and map patterns). Changes made to the compiler in #2521 has probably made that feasible without too much effort.
I have lifted the restrictions on binary and map patterns in the linked pull request.