In OTP 23, all variables used in a segment size expression must be already
bound in the enclosing environment. The previous example must be rewritten
like this using nested cases:
'foo'/1 =
fun (_0) ->
case _0 of
<#{#<Sz>(16,1,'integer',['unsigned'|['big']]),
#<_2>('all',1,'binary',['unsigned'|['big']])}#> when 'true' ->
case _2 of
<#{#<X>(Sz,1,'integer',['unsigned'|['big']])}#> when 'true' ->
X
<_3> when 'true' ->
%% Raise function_clause exception.
.
.
.
end
<_4> when 'true' ->
%% Raise function_clause exception.
.
.
.
end
However, as can be seen from the example, the code for raising the function_clause
exception has been duplicated. The code duplication is no big deal in this simple
example, but it would be in a function where the binary matching clause was followed
by many other clauses. To avoid the code duplication, we must use letrec
with
the letrec_goto
annotation:
'foo'/1 =
fun (_0) ->
( letrec
'label^0'/0 =
fun () ->
case _0 of
<_1> when 'true' ->
%% Raise function_clause exception.
.
.
.
end
in case _0 of
<#{#<Sz>(16,1,'integer',['unsigned'|['big']]),
#<_2>('all',1,'binary',['unsigned'|['big']])}#> when 'true' ->
case _2 of
<#{#<X>(Sz,1,'integer',['unsigned'|['big']])}#> when 'true' ->
X
<_3> when 'true' ->
apply 'label^0'/0()
end
<_4> when 'true' ->
apply 'label^0'/0()
end
-| ['letrec_goto'] )