From 982d6706df475dc28535d0fe7922573c618bbc36 Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Fri, 16 Mar 2012 18:33:05 +0100 Subject: Fix bug related with infinitely looping functions Depending of the ordering of the functions during dataflow, a function with an infinite loop might be identified as one that always crashes. This is fixed now, by allowing restoration of the infinitely-looping status. --- lib/dialyzer/src/dialyzer_dataflow.erl | 14 ++++++++-- .../test/small_SUITE_data/src/maybe_servers.erl | 31 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 lib/dialyzer/test/small_SUITE_data/src/maybe_servers.erl (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index aba13278ff..d1dd7e1c34 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -761,7 +761,13 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left], true -> AccArgTypes; false -> [t_sup(X, Y) || {X, Y} <- lists:zip(NewArgTypes, AccArgTypes)] end, - NewAccRet = t_sup(AccRet, t_inf(RetWithoutLocal, LocalRet, opaque)), + TotalRet = + case t_is_none(LocalRet) andalso t_is_unit(RetWithoutLocal) of + true -> RetWithoutLocal; + false -> t_inf(RetWithoutLocal, LocalRet, opaque) + end, + NewAccRet = t_sup(AccRet, TotalRet), + ?debug("NewAccRet: ~s\n", [t_to_string(NewAccRet)]), handle_apply_or_call(Left, Args, ArgTypes, Map, Tree, State3, NewAccArgTypes, NewAccRet); handle_apply_or_call([], Args, _ArgTypes, Map, _Tree, State, @@ -3109,6 +3115,7 @@ init_fun_tab([Fun|Left], Dict, TreeMap, Callgraph, Plt, Opaques) -> NewDict = dict:store(Fun, FunEntry, Dict), init_fun_tab(Left, NewDict, TreeMap, Callgraph, Plt, Opaques); init_fun_tab([], Dict, _TreeMap, _Callgraph, _Plt, _Opaques) -> + ?debug("DICT:~p\n",[dict:to_list(Dict)]), Dict. state__update_fun_env(Tree, Map, #state{envs = Envs} = State) -> @@ -3140,7 +3147,9 @@ state__fun_type(Fun, #state{fun_tab = FunTab}) -> if is_integer(Fun) -> Fun; true -> get_label(Fun) end, - case dict:find(Label, FunTab) of + Entry = dict:find(Label, FunTab), + ?debug("FunType ~p:~p\n",[Label, Entry]), + case Entry of {ok, {not_handled, {A, R}}} -> t_fun(A, R); {ok, {A, R}} -> @@ -3248,6 +3257,7 @@ state__fun_info(Fun, #state{callgraph = CG, fun_tab = FunTab, plt = PLT}) -> {not_handled, {_Args, Ret}} -> Ret; {_Args, Ret} -> Ret end, + ?debug("LocalRet: ~s\n", [t_to_string(LocalRet)]), {Fun, Sig, Contract, LocalRet}. state__find_apply_return(Tree, #state{callgraph = Callgraph} = State) -> diff --git a/lib/dialyzer/test/small_SUITE_data/src/maybe_servers.erl b/lib/dialyzer/test/small_SUITE_data/src/maybe_servers.erl new file mode 100644 index 0000000000..237f43b1a6 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/maybe_servers.erl @@ -0,0 +1,31 @@ +-module(maybe_servers). + +-export([maybe_server/2, mirror_maybe_server/2]). + +maybe_server(O, I) -> + case O of + no -> + maybe_loop(fun(_) -> fin end, I); + yes -> + maybe_loop(fun(X) -> {ok, X} end, I) + end. + +maybe_loop(F, X)-> + case F(X) of + {ok, Y} -> maybe_loop(F, Y); + fin -> exit(n) + end. + +mirror_maybe_loop(F, X)-> + case F(X) of + {ok, Y} -> mirror_maybe_loop(F, Y); + fin -> exit(n) + end. + +mirror_maybe_server(O, I) -> + case O of + no -> + mirror_maybe_loop(fun(_) -> fin end, I); + yes -> + mirror_maybe_loop(fun(X) -> {ok, X} end, I) + end. -- cgit v1.2.3