Skip to content

Commit f4e95cb

Browse files
author
Francois Brodeur
authored
Bit syntax integer signedness (#283)
Respect default unsignedness for integer bit-string matching.
1 parent dd02b45 commit f4e95cb

File tree

3 files changed

+59
-11
lines changed

3 files changed

+59
-11
lines changed

src/typechecker.erl

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,7 +1336,7 @@ do_type_check_expr(Env, {bin, _, BinElements} = BinExpr) ->
13361336
VarBindAndCsList =
13371337
lists:map(fun ({bin_element, _P, Expr, _Size, _Specif} = BinElem) ->
13381338
%% Treat bin type specifier as type annotation
1339-
Ty = type_of_bin_element(BinElem),
1339+
Ty = type_of_bin_element(BinElem, expr),
13401340
type_check_expr_in(Env, Ty, Expr)
13411341
end,
13421342
BinElements),
@@ -3693,7 +3693,7 @@ add_type_pat({bin, _P, BinElements} = Bin, Ty, TEnv, VEnv) ->
36933693
lists:foldl(fun ({bin_element, _, Pat, _Size, _Specifiers} = BinElem,
36943694
{VEnvAcc, CsAcc}) ->
36953695
%% Check Pat against the bit syntax type specifiers
3696-
ElemTy = type_of_bin_element(BinElem),
3696+
ElemTy = type_of_bin_element(BinElem, pattern),
36973697
{_PatTy, _UBound, VEnv2, Cs2} =
36983698
add_type_pat(Pat, ElemTy, TEnv, VEnvAcc),
36993699
{VEnv2, constraints:combine(CsAcc, Cs2)}
@@ -3957,15 +3957,21 @@ count_var_occurrences(Exprs) ->
39573957
Size :: non_neg_integer() |
39583958
default,
39593959
Specifiers :: [atom() | {unit, pos_integer()}] |
3960-
default}) -> type().
3961-
type_of_bin_element({bin_element, Anno, Expr, Size, default}) ->
3962-
type_of_bin_element({bin_element, Anno, Expr, Size, []});
3963-
type_of_bin_element({bin_element, _P, Expr, _Size, Specifiers}) ->
3960+
default},
3961+
OccursAs :: pattern | expr) -> type().
3962+
type_of_bin_element({bin_element, Anno, Expr, Size, default}, OccursAs) ->
3963+
type_of_bin_element({bin_element, Anno, Expr, Size, []}, OccursAs);
3964+
type_of_bin_element({bin_element, _P, Expr, _Size, Specifiers}, OccursAs) ->
39643965
%% String literal is syntactic sugar for multiple char literals,
39653966
IsStringLiteral = case Expr of
39663967
{string, _, _} -> true;
39673968
_ -> false
39683969
end,
3970+
IsSigned =
3971+
case OccursAs of
3972+
pattern -> lists:member(signed, Specifiers);
3973+
expr -> true
3974+
end,
39693975
Types =
39703976
lists:filtermap(fun
39713977
(S) when S == integer;
@@ -3976,8 +3982,10 @@ type_of_bin_element({bin_element, _P, Expr, _Size, Specifiers}) ->
39763982
IsStringLiteral ->
39773983
%% <<"ab"/utf8>> == <<$a/utf8, $b/utf8>>.
39783984
{true, type(string)};
3979-
not IsStringLiteral ->
3980-
{true, type(integer)}
3985+
IsSigned ->
3986+
{true, type(integer)};
3987+
true ->
3988+
{true, type(non_neg_integer)}
39813989
end;
39823990
(float) when IsStringLiteral ->
39833991
%% <<"abc"/float>> is integers to floats conversion
@@ -4003,9 +4011,13 @@ type_of_bin_element({bin_element, _P, Expr, _Size, Specifiers}) ->
40034011
[] when IsStringLiteral ->
40044012
%% <<"abc">>
40054013
type(string);
4006-
[] ->
4007-
%% <<X>>
4014+
[] when IsSigned ->
4015+
%% As expr: <<X>>
4016+
%% As pattern: <<X/signed>>
40084017
type(integer);
4018+
[] when not IsSigned ->
4019+
%% As pattern: <<X>> or <<X/unsigned>>
4020+
type(non_neg_integer);
40094021
[T] ->
40104022
T
40114023
end.

test/should_fail/bc.erl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
-module(bc).
2-
-export([f/0, non_bin_expr/0]).
2+
-export([f/0, non_bin_expr/0, integer_signed_wrong/1]).
33

44
-spec f() -> binary().
55
f() ->
66
<< X || <<X/integer>> <= <<"abc">> >>.
77

88
non_bin_expr() ->
99
<< (list_to_integer(X)) || X <- ["42"] >>.
10+
11+
-spec integer_signed_wrong(binary()) -> non_neg_integer().
12+
integer_signed_wrong(B) ->
13+
<<A/signed>> = B,
14+
A.
15+

test/should_pass/bc.erl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,33 @@ union_of_bitstrings(false) -> <<"xyz"/utf16-little>>.
5858
union_of_lists(N) when N > 42 -> [<<>>, <<N/utf16>>];
5959
union_of_lists(N) -> [<<42:3>>, <<N:9>>].
6060

61+
-spec integer_default(binary()) -> non_neg_integer().
62+
integer_default(B) ->
63+
<<A>> = B,
64+
A.
65+
66+
-spec integer_unsigned(binary()) -> non_neg_integer().
67+
integer_unsigned(B) ->
68+
<<A/unsigned>> = B,
69+
A.
70+
71+
-spec integer_signed(binary()) -> integer().
72+
integer_signed(B) ->
73+
<<A/signed>> = B,
74+
A.
75+
76+
-spec expr_vs_pat_default() -> non_neg_integer().
77+
expr_vs_pat_default() ->
78+
<<A>> = <<-1>>,
79+
A.
80+
81+
-spec expr_vs_pat_unsigned() -> non_neg_integer().
82+
expr_vs_pat_unsigned() ->
83+
<<A/unsigned>> = <<-1>>,
84+
A.
85+
86+
-spec expr_vs_pat_signed() -> integer().
87+
expr_vs_pat_signed() ->
88+
<<A/signed>> = <<-1>>,
89+
A.
90+

0 commit comments

Comments
 (0)