@@ -35,7 +35,12 @@ expand(BitstrMeta, Fun, [{'::', Meta, [Left, Right]} | T], Acc, S, E, Alignment,
3535
3636 MatchOrRequireSize = RequireSize or is_match_size (T , EL ),
3737 EType = expr_type (ELeft ),
38- {ERight , EAlignment , SS , ES } = expand_specs (EType , Meta , Right , SL , OriginalS , EL , MatchOrRequireSize ),
38+ ExpectSize = case ELeft of
39+ {'^' , _ , [{_ , _ , _ }]} -> {infer , ELeft };
40+ _ when MatchOrRequireSize -> required ;
41+ _ -> optional
42+ end ,
43+ {ERight , EAlignment , SS , ES } = expand_specs (EType , Meta , Right , SL , OriginalS , EL , ExpectSize ),
3944
4045 EAcc = concat_or_prepend_bitstring (Meta , ELeft , ERight , Acc , ES , MatchOrRequireSize ),
4146 expand (BitstrMeta , Fun , T , EAcc , {SS , OriginalS }, ES , alignment (Alignment , EAlignment ), RequireSize );
@@ -147,7 +152,7 @@ expand_expr(Meta, Component, Fun, S, E) ->
147152
148153% % Expands and normalizes types of a bitstring.
149154
150- expand_specs (ExprType , Meta , Info , S , OriginalS , E , RequireSize ) ->
155+ expand_specs (ExprType , Meta , Info , S , OriginalS , E , ExpectSize ) ->
151156 Default =
152157 #{size => default ,
153158 unit => default ,
@@ -158,11 +163,17 @@ expand_specs(ExprType, Meta, Info, S, OriginalS, E, RequireSize) ->
158163 expand_each_spec (Meta , unpack_specs (Info , []), Default , S , OriginalS , E ),
159164
160165 MergedType = type (Meta , ExprType , Type , E ),
161- validate_size_required (Meta , RequireSize , ExprType , MergedType , Size , ES ),
166+ validate_size_required (Meta , ExpectSize , ExprType , MergedType , Size , ES ),
162167 SizeAndUnit = size_and_unit (Meta , ExprType , Size , Unit , ES ),
163168 Alignment = compute_alignment (MergedType , Size , Unit ),
164169
165- [H | T ] = build_spec (Meta , Size , Unit , MergedType , Endianness , Sign , SizeAndUnit , ES ),
170+ MaybeInferredSize = case {ExpectSize , MergedType , SizeAndUnit } of
171+ {{infer , PinnedVar }, binary , []} -> [{size , Meta , [{{'.' , Meta , [erlang , byte_size ]}, Meta , [PinnedVar ]}]}];
172+ {{infer , PinnedVar }, bitstring , []} -> [{size , Meta , [{{'.' , Meta , [erlang , bit_size ]}, Meta , [PinnedVar ]}]}];
173+ _ -> SizeAndUnit
174+ end ,
175+
176+ [H | T ] = build_spec (Meta , Size , Unit , MergedType , Endianness , Sign , MaybeInferredSize , ES ),
166177 {lists :foldl (fun (I , Acc ) -> {'-' , Meta , [Acc , I ]} end , H , T ), Alignment , SS , ES }.
167178
168179type (_ , default , default , _ ) ->
@@ -276,7 +287,7 @@ validate_spec_arg(Meta, unit, Value, _S, _OriginalS, E) when not is_integer(Valu
276287validate_spec_arg (_Meta , _Key , _Value , _S , _OriginalS , _E ) ->
277288 ok .
278289
279- validate_size_required (Meta , true , default , Type , default , E ) when Type == binary ; Type == bitstring ->
290+ validate_size_required (Meta , required , default , Type , default , E ) when Type == binary ; Type == bitstring ->
280291 function_error (Meta , E , ? MODULE , unsized_binary ),
281292 ok ;
282293validate_size_required (_ , _ , _ , _ , _ , _ ) ->
0 commit comments