From b8ab5bc3211fdee28000e2fd35a47dafa2a4316c Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Sun, 19 Feb 2012 22:05:47 +0100 Subject: Fix types and specs in Dialyzer --- lib/dialyzer/src/dialyzer_analysis_callgraph.erl | 19 ++- lib/dialyzer/src/dialyzer_callgraph.erl | 29 +++-- lib/dialyzer/src/dialyzer_coordinator.erl | 63 +++++---- lib/dialyzer/src/dialyzer_dataflow.erl | 159 +---------------------- lib/dialyzer/src/dialyzer_succ_typings.erl | 148 ++------------------- lib/dialyzer/src/dialyzer_worker.erl | 45 ++++--- 6 files changed, 107 insertions(+), 356 deletions(-) (limited to 'lib/dialyzer') diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl index e009b8f43f..febaf56e40 100644 --- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl @@ -35,6 +35,10 @@ start_compilation/2, continue_compilation/2]). +-export_type([compilation_data/0, + result/0, + servers/0]). + -include("dialyzer.hrl"). -record(analysis_state, @@ -247,10 +251,10 @@ compile_and_store(Files, #analysis_state{codeserver = CServer, send_log(Parent, Msg2), {Callgraph, sets:from_list(NoWarn), CServer2}. --type servers() :: term(). --type result() :: term(). --type file_result() :: term(). --type data() :: term(). +-type servers() :: term(). %%opaque +-type result() :: term(). %%opaque +-type file_result() :: term(). %%opaque +-type compilation_data() :: term(). %%opaque -spec compile_coordinator_init() -> result(). @@ -266,7 +270,8 @@ add_to_result(File, NewData, {V, E, Failed, NoWarn, Mods}) -> {NV ++ V, NE ++ E, Failed, NewNoWarn ++ NoWarn, [Mod|Mods]} end. --spec start_compilation(file:filename(), servers()) -> data(). +-spec start_compilation(file:filename(), servers()) -> + {error, term()} |{ok, integer(), compilation_data()}. start_compilation(File, {Callgraph, Codeserver, StartFrom, Includes, Defines, UseContracts}) -> @@ -368,9 +373,9 @@ store_core(Mod, Core, NoWarn, Callgraph, CServer) -> CServer = dialyzer_codeserver:insert_exports(Exp, CServer), CServer = dialyzer_codeserver:insert_temp_exported_types(ExpTypes, CServer), CoreTree = cerl:from_records(Core), - {cerl_trees:size(CoreTree), {Mod, CoreTree, NoWarn, Callgraph, CServer}}. + {ok, cerl_trees:size(CoreTree), {Mod, CoreTree, NoWarn, Callgraph, CServer}}. --spec continue_compilation(integer(), data()) -> {integer(), file_result()}. +-spec continue_compilation(integer(), compilation_data()) -> file_result(). continue_compilation(NextLabel, {Mod, CoreTree, NoWarn, Callgraph, CServer}) -> {LabeledTree, _NewNextLabel} = cerl_trees:label(CoreTree, NextLabel), diff --git a/lib/dialyzer/src/dialyzer_callgraph.erl b/lib/dialyzer/src/dialyzer_callgraph.erl index bf939655d0..bb96ada65f 100644 --- a/lib/dialyzer/src/dialyzer_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_callgraph.erl @@ -264,7 +264,7 @@ get_required_by(SCC, #callgraph{active_digraph = DG}) -> modules(#callgraph{digraph = DG}) -> ordsets:from_list([M || {M,_F,_A} <- digraph_vertices(DG)]). --spec module_postorder(callgraph()) -> [module()]. +-spec module_postorder(callgraph()) -> {[module()], digraph()}. module_postorder(#callgraph{digraph = DG}) -> Edges = digraph_edges(DG), @@ -323,7 +323,8 @@ reset_from_funs(Funs, #callgraph{digraph = DG, digraph_delete(SubGraph), {Postorder, CG#callgraph{active_digraph = NewActiveDG}}. --spec module_postorder_from_funs([mfa_or_funlbl()], callgraph()) -> [module()]. +-spec module_postorder_from_funs([mfa_or_funlbl()], callgraph()) -> + {[module()], callgraph()}. module_postorder_from_funs(Funs, #callgraph{digraph = DG} = CG) -> SubGraph = digraph_reaching_subgraph(Funs, DG), @@ -352,7 +353,8 @@ ets_lookup_set(Key, Table) -> %% The set of labels in the tree must be disjoint from the set of %% labels already occuring in the callgraph. --spec scan_core_tree(cerl:c_module(), callgraph()) -> callgraph(). +-spec scan_core_tree(cerl:c_module(), callgraph()) -> + {[mfa_or_funlbl()], [callgraph_edge()]}. scan_core_tree(Tree, #callgraph{calls = ETSCalls, esc = ETSEsc, @@ -595,9 +597,10 @@ renew_race_code(Races, #callgraph{race_data_server = RaceDataServer} = CG) -> ok = race_data_server_cast( {renew_race_code, {Fun, FunArgs, Code}}, RaceDataServer), - CG; -renew_race_code({Fun, FunArgs, Code}, - #race_data_state{race_code = RaceCode} = State) -> + CG. + +renew_race_code_handler({Fun, FunArgs, Code}, + #race_data_state{race_code = RaceCode} = State) -> State#race_data_state{race_code = dict:store(Fun, [FunArgs, Code], RaceCode)}. -spec renew_race_public_tables(label(), callgraph()) -> callgraph(). @@ -606,9 +609,11 @@ renew_race_public_tables(VarLabel, #callgraph{race_data_server = RaceDataServer} = CG) -> ok = race_data_server_cast({renew_race_public_tables, VarLabel}, RaceDataServer), - CG; -renew_race_public_tables(VarLabel, - #race_data_state{public_tables = PT} = State) -> + CG. + +renew_race_public_tables_handler(VarLabel, + #race_data_state{public_tables = PT} + = State) -> State#race_data_state{public_tables = ordsets:add_element(VarLabel, PT)}. -spec cleanup(callgraph()) -> callgraph(). @@ -739,8 +744,8 @@ race_data_server_handle_cast(race_code_new, State) -> race_data_server_handle_cast({Tag, Data}, State) -> case Tag of renew_race_info -> renew_race_info(Data, State); - renew_race_code -> renew_race_code(Data, State); - renew_race_public_tables -> renew_race_public_tables(Data, State); + renew_race_code -> renew_race_code_handler(Data, State); + renew_race_public_tables -> renew_race_public_tables_handler(Data, State); put_race_code -> State#race_data_state{race_code = Data}; put_public_tables -> State#race_data_state{public_tables = Data}; put_named_tables -> State#race_data_state{named_tables = Data}; @@ -775,7 +780,7 @@ to_dot(#callgraph{digraph = DG, esc = Esc} = CG, File) -> end end, Escaping = [{Fun(L), {color, red}} - || L <- sets:to_list(Esc), L =/= external], + || L <- [E || {E} <- ets:tab2list(Esc)], L =/= external], Vertices = digraph_edges(DG), hipe_dot:translate_list(Vertices, File, "CG", Escaping). diff --git a/lib/dialyzer/src/dialyzer_coordinator.erl b/lib/dialyzer/src/dialyzer_coordinator.erl index d8a3ef2bd2..9bcd7e4c63 100644 --- a/lib/dialyzer/src/dialyzer_coordinator.erl +++ b/lib/dialyzer/src/dialyzer_coordinator.erl @@ -46,17 +46,19 @@ -module(dialyzer_coordinator). -%%% Exports for all possible uses of coordinator +%%% Exports for all possible uses of coordinator from main process -export([start/2, all_spawned/1]). +%%% Exports for all possible workers +-export([job_done/3]). + %%% Exports for the typesig and dataflow analysis main process -export([scc_spawn/2, receive_not_fixpoint/0]). %%% Exports for the typesig and dataflow analysis workers --export([scc_done/3, - sccs_to_pids_reply/0, +-export([sccs_to_pids_reply/0, sccs_to_pids_request/2]). %%% Exports for the compilation main process @@ -67,39 +69,44 @@ -export([compilation_done/3, get_next_label/2]). +-export_type([coordinator/0, mode/0]). + -behaviour(gen_server). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --type coordinator() :: pid(). --type map() :: dict(). --type scc() :: [mfa_or_funlbl()]. --type mode() :: 'typesig' | 'dataflow' | 'compile'. - --record(state, {parent :: pid(), - mode :: mode(), - spawn_count = 0 :: integer(), - all_spawned = false :: boolean(), - job_to_pid :: map(), - next_label :: integer(), - result :: [mfa_or_funlbl()] | - dialyzer_analysis_callgraph:result(), - init_job_data :: dialyzer_typesig:servers() +-type coordinator() :: pid(). %%opaque + +-type map() :: dict(). +-type scc() :: [mfa_or_funlbl()]. +-type mode() :: 'typesig' | 'dataflow' | 'compile'. +-type servers() :: dialyzer_succ_typings:servers() | + dialyzer_analysis_callgraph:servers(). + +-record(state, {parent :: pid(), + mode :: mode(), + spawn_count = 0 :: integer(), + all_spawned = false :: boolean(), + job_to_pid :: map(), + next_label :: integer(), + result :: [mfa_or_funlbl()] | + dialyzer_analysis_callgraph:result(), + init_job_data :: servers() }). -include("dialyzer.hrl"). %%-------------------------------------------------------------------- --spec start('typesig' | 'dataflow', dialyzer_typesig:servers()) -> pid(); +-spec start('typesig' | 'dataflow', dialyzer_succ_typings:servers()) -> pid(); ('compile', dialyzer_analysis_callgraph:servers()) -> pid(). start(Mode, Servers) -> {ok, Pid} = gen_server:start(?MODULE, {self(), Mode, Servers}, []), Pid. --spec scc_spawn(scc(), coordinator()) -> ok. +-spec scc_spawn(scc() | module(), coordinator()) -> ok. scc_spawn(SCC, Coordinator) -> cast({scc_spawn, SCC}, Coordinator). @@ -119,10 +126,10 @@ scc_to_pids_request_handle(Worker, SCCs, SCCtoPID) -> sccs_to_pids_reply() -> receive {sccs_to_pids, Pids} -> Pids end. --spec scc_done(scc(), scc(), coordinator()) -> ok. +-spec job_done(scc() | file:filename(), term(), coordinator()) -> ok. -scc_done(SCC, NotFixpoint, Coordinator) -> - cast({done, SCC, NotFixpoint}, Coordinator). +job_done(Job, Result, Coordinator) -> + cast({done, Job, Result}, Coordinator). -spec compilation_done(file:filename(), dialyzer_analysis_callgraph:compilation_data(), @@ -145,9 +152,10 @@ send_done_to_parent(#state{mode = Mode, X when X =:= 'typesig'; X =:= 'dataflow' -> {not_fixpoint, Result}; 'compile' -> {compilation_data, Result, NextLabel} end, - Parent ! Msg. + Parent ! Msg, + ok. --spec receive_not_fixpoint() -> dialyzer_plt:plt(). +-spec receive_not_fixpoint() -> [mfa_or_funlbl()]. receive_not_fixpoint() -> receive {not_fixpoint, NotFixpoint} -> NotFixpoint end. @@ -172,8 +180,7 @@ get_next_label(EstimatedSize, Coordinator) -> %%-------------------------------------------------------------------- --spec init({pid(), mode(), dialyzer_succ_typings:servers() | - dialyzer_analysis_callgraph:servers()}) -> {ok, #state{}}. +-spec init({pid(), mode(), servers()}) -> {ok, #state{}}. init({Parent, Mode, InitJobData}) -> InitState = #state{parent = Parent, mode = Mode, init_job_data = InitJobData}, @@ -247,7 +254,7 @@ handle_cast({scc_spawn, SCC}, spawn_count = SpawnCount, job_to_pid = SCCtoPID } = State) -> - Pid = dialyzer_worker:launch(Mode, SCC, Servers), + Pid = dialyzer_worker:launch(Mode, SCC, Servers, self()), {noreply, State#state{spawn_count = SpawnCount + 1, job_to_pid = store_map(SCC, Pid, SCCtoPID)} @@ -257,7 +264,7 @@ handle_cast({compiler_spawn, Filename}, init_job_data = Servers, spawn_count = SpawnCount } = State) -> - dialyzer_worker:launch(Mode, Filename, Servers), + dialyzer_worker:launch(Mode, Filename, Servers, self()), {noreply, State#state{spawn_count = SpawnCount + 1} }. diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index 248ad328ab..cb376daf68 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -37,9 +37,6 @@ state__get_records/1, state__put_callgraph/2, state__put_races/2, state__records_only/1]). -%% Debug and test interfaces. --export([get_top_level_signatures/2, pp/1]). - -export_type([state/0]). -include("dialyzer.hrl"). @@ -68,7 +65,7 @@ %%-define(DEBUG, true). %%-define(DEBUG_PP, true). -%%-define(DOT, true). +%%-define(DEBUG_TIME, true). -ifdef(DEBUG). -import(erl_types, [t_to_string/1]). @@ -129,137 +126,12 @@ get_fun_types(Tree, Plt, Callgraph, Records) -> State = analyze_module(Tree, Plt, Callgraph, Records, false), state__all_fun_types(State). -%%-------------------------------------------------------------------- - --spec pp(file:filename()) -> 'ok'. - -pp(File) -> - {ok, Code} = dialyzer_utils:get_core_from_src(File, [no_copt]), - Plt = get_def_plt(), - AnnTree = annotate_module(Code, Plt), - io:put_chars(cerl_prettypr:format(AnnTree, [{hook, cerl_typean:pp_hook()}])), - io:nl(). - -%%-------------------------------------------------------------------- -%% This is used in the testsuite. - --spec get_top_level_signatures(cerl:c_module(), dict()) -> - [{{atom(), arity()}, erl_types:erl_type()}]. - -get_top_level_signatures(Code, Records) -> - {Tree, _} = cerl_trees:label(cerl:from_records(Code)), - Callgraph0 = dialyzer_callgraph:new(), - Callgraph1 = dialyzer_callgraph:scan_core_tree(Tree, Callgraph0), - {Callgraph2, _} = dialyzer_callgraph:remove_external(Callgraph1), - Callgraph = dialyzer_callgraph:finalize(Callgraph2), - to_dot(Callgraph), - Plt = get_def_plt(), - FunTypes = get_fun_types(Tree, Plt, Callgraph, Records), - FunTypes1 = lists:foldl(fun({V, F}, Acc) -> - Label = get_label(F), - case dict:find(Label, Acc) of - error -> - Arity = cerl:fname_arity(V), - Type = t_fun(lists:duplicate(Arity, - t_none()), - t_none()), - dict:store(Label, Type, Acc); - {ok, _} -> Acc - end - end, FunTypes, cerl:module_defs(Tree)), - dialyzer_callgraph:delete(Callgraph), - Sigs = [{{cerl:fname_id(V), cerl:fname_arity(V)}, - dict:fetch(get_label(F), FunTypes1)} - || {V, F} <- cerl:module_defs(Tree)], - ordsets:from_list(Sigs). - -get_def_plt() -> - try - dialyzer_plt:from_file(dialyzer_plt:get_default_plt()) - catch - throw:{dialyzer_error, _} -> dialyzer_plt:new() - end. - -%%% =========================================================================== -%%% -%%% Annotate all top level funs. -%%% -%%% =========================================================================== - -annotate_module(Code, Plt) -> - {Tree, _} = cerl_trees:label(cerl:from_records(Code)), - Callgraph0 = dialyzer_callgraph:new(), - Callgraph1 = dialyzer_callgraph:scan_core_tree(Tree, Callgraph0), - {Callgraph2, _} = dialyzer_callgraph:remove_external(Callgraph1), - Callgraph = dialyzer_callgraph:finalize(Callgraph2), - State = analyze_module(Tree, Plt, Callgraph), - Res = annotate(Tree, State), - dialyzer_callgraph:delete(Callgraph), - Res. - -annotate(Tree, State) -> - case cerl:subtrees(Tree) of - [] -> set_type(Tree, State); - List -> - NewSubTrees = [[annotate(Subtree, State) || Subtree <- Group] - || Group <- List], - NewTree = cerl:update_tree(Tree, NewSubTrees), - set_type(NewTree, State) - end. - -set_type(Tree, State) -> - case cerl:type(Tree) of - 'fun' -> - Type = state__fun_type(Tree, State), - case t_is_any(Type) of - true -> - cerl:set_ann(Tree, delete_ann(typesig, cerl:get_ann(Tree))); - false -> - cerl:set_ann(Tree, append_ann(typesig, Type, cerl:get_ann(Tree))) - end; - apply -> - case state__find_apply_return(Tree, State) of - unknown -> Tree; - ReturnType -> - case t_is_any(ReturnType) of - true -> - cerl:set_ann(Tree, delete_ann(type, cerl:get_ann(Tree))); - false -> - cerl:set_ann(Tree, append_ann(type, ReturnType, - cerl:get_ann(Tree))) - end - end; - _ -> - Tree - end. - -append_ann(Tag, Val, [X | Xs]) -> - if tuple_size(X) >= 1, element(1, X) =:= Tag -> - append_ann(Tag, Val, Xs); - true -> - [X | append_ann(Tag, Val, Xs)] - end; -append_ann(Tag, Val, []) -> - [{Tag, Val}]. - -delete_ann(Tag, [X | Xs]) -> - if tuple_size(X) >= 1, element(1, X) =:= Tag -> - delete_ann(Tag, Xs); - true -> - [X | delete_ann(Tag, Xs)] - end; -delete_ann(_, []) -> - []. - %%% =========================================================================== %%% %%% The analysis. %%% %%% =========================================================================== -analyze_module(Tree, Plt, Callgraph) -> - analyze_module(Tree, Plt, Callgraph, dict:new(), false). - analyze_module(Tree, Plt, Callgraph, Records, GetWarnings) -> debug_pp(Tree, false), Module = cerl:atom_val(cerl:module_name(Tree)), @@ -3204,21 +3076,6 @@ state__fun_info(Fun, #state{callgraph = CG, fun_tab = FunTab, plt = PLT}) -> ?debug("LocalRet: ~s\n", [t_to_string(LocalRet)]), {Fun, Sig, Contract, LocalRet}. -state__find_apply_return(Tree, #state{callgraph = Callgraph} = State) -> - Apply = get_label(Tree), - case dialyzer_callgraph:lookup_call_site(Apply, Callgraph) of - error -> - unknown; - {ok, List} -> - case lists:member(external, List) of - true -> t_any(); - false -> - FunTypes = [state__fun_type(F, State) || F <- List], - Returns = [t_fun_range(F) || F <- FunTypes], - t_sup(Returns) - end - end. - forward_args(Fun, ArgTypes, #state{work = Work, fun_tab = FunTab} = State) -> {OldArgTypes, OldOut, Fixpoint} = case dict:find(Fun, FunTab) of @@ -3652,17 +3509,3 @@ strip_annotations(Tree) -> debug_pp(_Tree, _UseHook) -> ok. -endif. - -%%---------------------------------------------------------------------------- - --spec to_dot(dialyzer_callgraph:callgraph()) -> 'ok'. - --ifdef(DOT). -to_dot(CG) -> - dialyzer_callgraph:to_dot(CG). --else. -to_dot(_CG) -> - ok. --endif. - -%%---------------------------------------------------------------------------- diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl index 90d851bc3c..38f3d47353 100644 --- a/lib/dialyzer/src/dialyzer_succ_typings.erl +++ b/lib/dialyzer/src/dialyzer_succ_typings.erl @@ -29,7 +29,10 @@ -export([analyze_callgraph/3, analyze_callgraph/4, - get_warnings/6, + get_warnings/6 + ]). + +-export([ find_succ_types_for_scc/1, refine_one_module/1, collect_scc_data/2, @@ -38,12 +41,9 @@ find_depends_on/2 ]). -%% These are only intended as debug functions. --export([doit/1, - get_top_level_signatures/3]). +-export_type([servers/0, scc_data/0, scc_refine_data/0]). %%-define(DEBUG, true). -%%-define(DEBUG_PP, true). -ifdef(DEBUG). -define(debug(X__, Y__), io:format(X__, Y__)). @@ -213,9 +213,9 @@ refine_succ_typings([], State, Coordinator) -> false -> {not_fixpoint, NotFixpoint, State} end. --type servers() :: term(). --type scc_data() :: term(). --type scc_refine_data() :: term(). +-type servers() :: term(). %%opaque +-type scc_data() :: term(). %%opaque +-type scc_refine_data() :: term(). %%opaque -type scc() :: [mfa_or_funlbl()] | [module()]. -spec find_depends_on(scc(), servers()) -> [scc()]. @@ -237,18 +237,17 @@ collect_refine_scc_data(M, {CodeServer, Callgraph, PLT}) -> FunTypes = get_fun_types_from_plt(AllFuns, Callgraph, PLT), {ModCode, PLT, Callgraph, Records, FunTypes}. --spec refine_one_module(scc_refine_data()) -> - {dialyzer_callgraph:callgraph(), [label()]}. % ordset +-spec refine_one_module(scc_refine_data()) -> [label()]. % ordset -refine_one_module({ModCode, PLT, Callgraph, Records, FunTypes}) -> +refine_one_module({ModCode, Plt, Callgraph, Records, FunTypes}) -> NewFunTypes = - dialyzer_dataflow:get_fun_types(ModCode, PLT, Callgraph, Records), + dialyzer_dataflow:get_fun_types(ModCode, Plt, Callgraph, Records), case reached_fixpoint(FunTypes, NewFunTypes) of true -> ordsets:new(); {false, NotFixpoint} -> ?debug("Not fixpoint\n", []), - insert_into_plt(dict:from_list(NotFixpoint), Callgraph, PLT), + Plt = insert_into_plt(dict:from_list(NotFixpoint), Callgraph, Plt), ordsets:from_list([FunLbl || {FunLbl,_Type} <- NotFixpoint]) end. @@ -366,8 +365,8 @@ find_succ_types_for_scc({SCC_Info, Contracts, NextLabel, AllFuns, {value, _} -> true end end, PltContracts), - insert_into_plt(FilteredFunTypes, Callgraph, Plt), - dialyzer_plt:insert_contract_list(Plt, PltContracts), + Plt = insert_into_plt(FilteredFunTypes, Callgraph, Plt), + Plt = dialyzer_plt:insert_contract_list(Plt, PltContracts), case (ContractFixpoint andalso reached_fixpoint_strict(PropTypes, FilteredFunTypes)) of true -> []; @@ -460,122 +459,3 @@ send_log(Parent, Msg) -> format_scc(SCC) -> [MFA || {_M, _F, _A} = MFA <- SCC]. - -%% ============================================================================ -%% -%% Debug interface. -%% -%% ============================================================================ - --spec doit(atom() | file:filename()) -> 'ok'. - -doit(Module) -> - {ok, AbstrCode} = dialyzer_utils:get_abstract_code_from_src(Module), - {ok, Code} = dialyzer_utils:get_core_from_abstract_code(AbstrCode), - {ok, Records} = dialyzer_utils:get_record_and_type_info(AbstrCode), - %% contract typing info in dictionary format - {ok, Contracts, _Callbacks} = - dialyzer_utils:get_spec_info(cerl:concrete(cerl:module_name(Code)), - AbstrCode, Records), - Sigs0 = get_top_level_signatures(Code, Records, Contracts), - M = if is_atom(Module) -> - list_to_atom(filename:basename(atom_to_list(Module))); - is_list(Module) -> - list_to_atom(filename:basename(Module)) - end, - Sigs1 = [{{M, F, A}, Type} || {{F, A}, Type} <- Sigs0], - Sigs = ordsets:from_list(Sigs1), - io:format("==================== Final result ====================\n\n", []), - pp_signatures(Sigs, Records), - ok. - --spec get_top_level_signatures(cerl:c_module(), dict(), dict()) -> - [{{atom(), arity()}, erl_types:erl_type()}]. - -get_top_level_signatures(Code, Records, Contracts) -> - Tree = cerl:from_records(Code), - {LabeledTree, NextLabel} = cerl_trees:label(Tree), - Plt = get_def_plt(), - ModuleName = cerl:atom_val(cerl:module_name(LabeledTree)), - Plt1 = dialyzer_plt:delete_module(Plt, ModuleName), - Plt2 = analyze_module(LabeledTree, NextLabel, Plt1, Records, Contracts), - M = cerl:concrete(cerl:module_name(Tree)), - Functions = [{M, cerl:fname_id(V), cerl:fname_arity(V)} - || {V, _F} <- cerl:module_defs(LabeledTree)], - %% First contracts check - AllContracts = dict:fetch_keys(Contracts), - ErrorContracts = AllContracts -- Functions, - lists:foreach(fun(C) -> - io:format("Contract for non-existing function: ~w\n",[C]) - end, ErrorContracts), - Types = [{MFA, dialyzer_plt:lookup(Plt2, MFA)} || MFA <- Functions], - Sigs = [{{F, A}, erl_types:t_fun(ArgT, RetT)} - || {{_M, F, A}, {value, {RetT, ArgT}}} <- Types], - ordsets:from_list(Sigs). - -get_def_plt() -> - try - dialyzer_plt:from_file(dialyzer_plt:get_default_plt()) - catch - error:no_such_file -> dialyzer_plt:new(); - throw:{dialyzer_error, _} -> dialyzer_plt:new() - end. - -pp_signatures([{{_, module_info, 0}, _}|Left], Records) -> - pp_signatures(Left, Records); -pp_signatures([{{_, module_info, 1}, _}|Left], Records) -> - pp_signatures(Left, Records); -pp_signatures([{{M, F, _A}, Type}|Left], Records) -> - TypeString = - case cerl:is_literal(Type) of -%% Commented out so that dialyzer does not complain -%% false -> -%% "fun(" ++ String = erl_types:t_to_string(Type, Records), -%% string:substr(String, 1, length(String)-1); - true -> - io_lib:format("~w", [cerl:concrete(Type)]) - end, - io:format("~w:~w~s\n", [M, F, TypeString]), - pp_signatures(Left, Records); -pp_signatures([], _Records) -> - ok. - --ifdef(DEBUG_PP). -debug_pp(Tree, _Map) -> - Tree1 = strip_annotations(Tree), - io:put_chars(cerl_prettypr:format(Tree1)), - io:nl(). - -strip_annotations(Tree) -> - cerl_trees:map(fun(T) -> - case cerl:is_literal(T) orelse cerl:is_c_values(T) of - true -> cerl:set_ann(T, []); - false -> - Label = cerl_trees:get_label(T), - cerl:set_ann(T, [{'label', Label}]) - end - end, Tree). --else. -debug_pp(_Tree, _Map) -> - ok. --endif. % DEBUG_PP - -%% -%% Analysis of a single module -%% -analyze_module(LabeledTree, NextLbl, Plt, Records, Contracts) -> - debug_pp(LabeledTree, dict:new()), - CallGraph1 = dialyzer_callgraph:new(), - CallGraph2 = dialyzer_callgraph:scan_core_tree(LabeledTree, CallGraph1), - {CallGraph3, _Ext} = dialyzer_callgraph:remove_external(CallGraph2), - CallGraph4 = dialyzer_callgraph:finalize(CallGraph3), - CodeServer1 = dialyzer_codeserver:new(), - Mod = cerl:concrete(cerl:module_name(LabeledTree)), - CodeServer2 = dialyzer_codeserver:insert(Mod, LabeledTree, CodeServer1), - CodeServer3 = dialyzer_codeserver:set_next_core_label(NextLbl, CodeServer2), - CodeServer4 = dialyzer_codeserver:store_records(Mod, Records, CodeServer3), - CodeServer5 = dialyzer_codeserver:store_contracts(Mod, Contracts, CodeServer4), - Res = analyze_callgraph(CallGraph4, Plt, CodeServer5), - dialyzer_callgraph:delete(CallGraph4), - dialyzer_codeserver:delete(CodeServer5), - Res. diff --git a/lib/dialyzer/src/dialyzer_worker.erl b/lib/dialyzer/src/dialyzer_worker.erl index b24103c5a8..48dae7cb56 100644 --- a/lib/dialyzer/src/dialyzer_worker.erl +++ b/lib/dialyzer/src/dialyzer_worker.erl @@ -20,18 +20,26 @@ -module(dialyzer_worker). --export([launch/3]). +-export([launch/4]). --type worker() :: pid(). +-export_type([worker/0]). + +-type worker() :: pid(). %%opaque + +-type mode() :: dialyzer_coordinator:mode(). +-type coordinator() :: dialyzer_coordinator:coordinator(). +-type servers() :: dialyzer_succ_typings:servers() | + dialyzer_analysis_callgraph:servers(). +-type data() :: dialyzer_succ_typings:scc_data() | + dialyzer_succ_typings:scc_refine_data(). -record(state, { - mode :: dialyzer_coordinator:mode(), + mode :: mode(), job :: mfa_or_funlbl() | file:filename(), + coordinator :: coordinator(), + servers :: servers(), depends_on = [] :: list(), - coordinator :: dialyzer_coordinator:coordinator(), - servers :: dialyzer_typesig:servers() | - dialyzer_analysis_callgraph:servers(), - scc_data :: dialyzer_typesig:scc_data() + scc_data :: data() }). -include("dialyzer.hrl"). @@ -46,14 +54,13 @@ %%-------------------------------------------------------------------- --spec launch(dialyzer_coordinator:mode(), [mfa_or_funlbl()], - dialyzer_typesig:servers()) -> worker(). +-spec launch(mode(), [mfa_or_funlbl()], servers(), coordinator()) -> worker(). -launch(Mode, Job, Servers) -> +launch(Mode, Job, Servers, Coordinator) -> State = #state{mode = Mode, job = Job, servers = Servers, - coordinator = self()}, + coordinator = Coordinator}, InitState = case Mode of X when X =:= 'typesig'; X =:= 'dataflow' -> initializing; @@ -93,9 +100,14 @@ loop(getting_data, State) -> loop(updating, get_data(State)); loop(running, #state{mode = 'compile'} = State) -> ?debug("Compile: ~s\n",[State#state.job]), - {EstimatedSize, Data} = start_compilation(State), - Label = ask_coordinator_for_label(EstimatedSize, State), - Result = continue_compilation(Label, Data), + Result = + case start_compilation(State) of + {ok, EstimatedSize, Data} -> + Label = ask_coordinator_for_label(EstimatedSize, State), + continue_compilation(Label, Data); + {error, _Reason} = Error -> + Error + end, report_to_coordinator(Result, State); loop(running, #state{mode = Mode} = State) when Mode =:= 'typesig'; Mode =:= 'dataflow' -> @@ -160,10 +172,9 @@ do_work(#state{mode = Mode, scc_data = SCCData}) -> dataflow -> dialyzer_succ_typings:refine_one_module(SCCData) end. -report_to_coordinator(NotFixpoint, - #state{job = Job, coordinator = Coordinator}) -> +report_to_coordinator(Result, #state{job = Job, coordinator = Coordinator}) -> ?debug("Done: ~p\n",[Job]), - dialyzer_coordinator:scc_done(Job, NotFixpoint, Coordinator). + dialyzer_coordinator:job_done(Job, Result, Coordinator). start_compilation(#state{job = Job, servers = Servers}) -> dialyzer_analysis_callgraph:start_compilation(Job, Servers). -- cgit v1.2.3