Skip to content

Commit

Permalink
Merge branch 'sa/dialyzer-bitstring-fixes/OTP-11027' into maint
Browse files Browse the repository at this point in the history
* sa/dialyzer-bitstring-fixes/OTP-11027:
  Minor refactorings
  Fix minor error in natively compiled module list
  Fix notification for duplicate modules
  Fix an error in the type inference of bitstring data
  • Loading branch information
rimmius committed Apr 10, 2013
2 parents 92727b2 + 071bffb commit c55f2ca
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 27 deletions.
9 changes: 6 additions & 3 deletions lib/dialyzer/src/dialyzer_analysis_callgraph.erl
Expand Up @@ -255,10 +255,13 @@ compile_and_store(Files, #analysis_state{codeserver = CServer,
CServer2 = dialyzer_codeserver:set_next_core_label(NextLabel, CServer),
case Failed =:= [] of
true ->
NewFiles = lists:zip(lists:reverse(Modules), Files),
ModDict =
lists:foldl(fun({Mod, F}, Dict) -> dict:append(Mod, F, Dict) end,
dict:new(), NewFiles),
lists:foldl(fun(F, Dict) ->
ModFile = lists:last(filename:split(F)),
Mod = filename:basename(ModFile, ".beam"),
dict:append(Mod, F, Dict)
end,
dict:new(), Files),
check_for_duplicate_modules(ModDict);
false ->
Msg = io_lib:format("Could not scan the following file(s):~n~s",
Expand Down
2 changes: 1 addition & 1 deletion lib/dialyzer/src/dialyzer_cl.erl
Expand Up @@ -509,7 +509,7 @@ hipe_compile(Files, #options{erlang_mode = ErlangMode} = Options) ->
dialyzer_codeserver, dialyzer_contracts,
dialyzer_coordinator, dialyzer_dataflow, dialyzer_dep,
dialyzer_plt, dialyzer_succ_typings, dialyzer_typesig,
dialyzer_typesig, dialyzer_worker],
dialyzer_worker],
report_native_comp(Options),
{T1, _} = statistics(wall_clock),
native_compile(Mods),
Expand Down
57 changes: 34 additions & 23 deletions lib/dialyzer/src/dialyzer_typesig.erl
Expand Up @@ -246,18 +246,27 @@ traverse(Tree, DefinedVars, State) ->
Val = cerl:bitstr_val(Tree),
{State1, [SizeType, ValType]} =
traverse_list([Size, Val], DefinedVars, State),
{State2, TypeConstr} =
{State2, TypeConstr, BinValTypeConstr} =
case cerl:bitstr_bitsize(Tree) of
all -> {State1, t_bitstr(UnitVal, 0)};
utf -> {State1, t_binary()}; % contains an integer number of bytes
N when is_integer(N) -> {State1, t_bitstr(0, N)};
all ->
T = t_bitstr(UnitVal, 0),
{State1, T, T};
utf ->
%% contains an integer number of bytes
T = t_binary(),
{State1, T, T};
N when is_integer(N) ->
{State1, t_bitstr(0, N), t_bitstr(1, N)};
any -> % Size is not a literal
T1 = ?mk_fun_var(bitstr_constr(SizeType, UnitVal), [SizeType]),
T2 =
?mk_fun_var(bitstr_constr(SizeType, UnitVal, match), [SizeType]),
{state__store_conj(SizeType, sub, t_non_neg_integer(), State1),
?mk_fun_var(bitstr_constr(SizeType, UnitVal), [SizeType])}
T1, T2}
end,
ValTypeConstr =
case cerl:concrete(cerl:bitstr_type(Tree)) of
binary -> TypeConstr;
binary -> BinValTypeConstr;
float ->
case state__is_in_match(State1) of
true -> t_float();
Expand Down Expand Up @@ -947,12 +956,20 @@ get_type_test({erlang, is_tuple, 1}) -> {ok, t_tuple()};
get_type_test({M, F, A}) when is_atom(M), is_atom(F), is_integer(A) -> error.

bitstr_constr(SizeType, UnitVal) ->
bitstr_constr(SizeType, UnitVal, construct).

bitstr_constr(SizeType, UnitVal, ConstructOrMatch) ->
Unit =
case ConstructOrMatch of
construct -> 0;
match -> 1
end,
fun(Map) ->
TmpSizeType = lookup_type(SizeType, Map),
case t_is_subtype(TmpSizeType, t_non_neg_integer()) of
true ->
case t_number_vals(TmpSizeType) of
[OneSize] -> t_bitstr(0, OneSize * UnitVal);
[OneSize] -> t_bitstr(Unit, OneSize * UnitVal);
_ ->
MinSize = erl_types:number_min(TmpSizeType),
t_bitstr(UnitVal, MinSize * UnitVal)
Expand Down Expand Up @@ -1770,8 +1787,9 @@ minimize_state(#state{
opaques = Opaques,
solvers = Solvers
}) ->
ETSCMap = ets:new(cmap,[{read_concurrency, true}]),
ETSPropTypes = ets:new(prop_types,[{read_concurrency, true}]),
Opts = [{read_concurrency, true}],
ETSCMap = ets:new(cmap, Opts),
ETSPropTypes = ets:new(prop_types, Opts),
true = ets:insert(ETSCMap, dict:to_list(CMap)),
true = ets:insert(ETSPropTypes, dict:to_list(PropTypes)),
#state
Expand Down Expand Up @@ -2111,11 +2129,11 @@ restore_local_map(#v2_state{constr_data = ConData}, Id, Map0) ->
{ok, failed} -> Map0;
{ok, {[],_}} -> Map0;
{ok, {Part0,U}} ->
Part = [{K,V} || {K,V} <- Part0, not lists:member(K, U)],
Part = [KV || {K,_V} = KV <- Part0, not lists:member(K, U)],
?debug("restore local map Id=~w U=~w\n", [Id, U]),
pp_map("Part", dict:from_list(Part)),
pp_map("Map0", Map0),
Map = lists:foldl(fun({K,V}, D) -> dict:store(K, V, D)end, Map0, Part),
Map = lists:foldl(fun({K,V}, D) -> dict:store(K, V, D) end, Map0, Part),
pp_map("Map", Map),
Map
end.
Expand Down Expand Up @@ -3374,16 +3392,6 @@ pp_constraints([#constraint{}=C], Level, MaxDepth, _State) ->
pp_constraints([#constraint{}=C|Tail], Level, MaxDepth, State) ->
pp_op(C, Level),
pp_constraints(Tail, Level, MaxDepth, State);
pp_constraints([#constraint_list{type = Type, list = List, id = Id}],
Level, MaxDepth, State) ->
pp_indent(Level),
case Type of
conj -> io:format("Conj ~w (", [Id]);
disj -> io:format("Disj ~w (", [Id])
end,
NewMaxDepth = pp_constraints(List, Level + 1, MaxDepth, State),
io:format(")", []),
NewMaxDepth;
pp_constraints([#constraint_list{type = Type, list = List, id = Id}|Tail],
Level, MaxDepth, State) ->
pp_indent(Level),
Expand All @@ -3392,8 +3400,11 @@ pp_constraints([#constraint_list{type = Type, list = List, id = Id}|Tail],
disj -> io:format("Disj ~w (", [Id])
end,
NewMaxDepth = pp_constraints(List, Level+1, MaxDepth, State),
io:format(")", []),
pp_constraints(Tail, Level, NewMaxDepth, State).
io:format(")"),
case Tail =:= [] of
true -> NewMaxDepth + 1;
false -> pp_constraints(Tail, Level, NewMaxDepth, State)
end.

pp_op(#constraint{lhs = Lhs, op = Op, rhs = Rhs}, Level) ->
pp_indent(Level),
Expand Down
32 changes: 32 additions & 0 deletions lib/dialyzer/test/small_SUITE_data/src/bs_constraints.erl
@@ -0,0 +1,32 @@
%% Program which shows that the handling of binaries was not correct.
%% The success typing inferred was:
%% -spec bits1(<<_:3>>) -> <<_:3>>.
%% while it should be:
%% -spec bits1(<<_:3,_:_*1>>) -> <<_:3>>.
%% because the only constraint which exists for the head variable is
%% that it must be a bitstring of bit size at least 3, not a bitstring
%% of bit size 3.
-module(bs_constraints).

-export([bits1/1, bits2/1, bits3/1, bins/1, test/0]).

bits1(B) ->
<<B:3/bits>>.

bits2(B) ->
<<B:4/bits>>.

bits3(B) ->
{bits1(B), bits2(B)}.

%% Same problem with the one below. The success typing should be:
%% -spec bins(<<_:16,_:_*1>>) -> <<_:16>>.
bins(B) ->
<<B:2/binary>>.

%% Same problem, when unit size is a variable:
test() ->
foo(8, 0, <<42>>).

foo(N, S, A) ->
<<A:S/binary-unit:1, A:(N-S)/binary-unit:1>>.

0 comments on commit c55f2ca

Please sign in to comment.