From 31ffea630ffd73d39970c3def796b00dd782373d Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Sun, 6 Mar 2011 00:01:59 +0200 Subject: Generate better warnings for failing guards --- lib/dialyzer/src/dialyzer.erl | 3 +++ lib/dialyzer/src/dialyzer_dataflow.erl | 42 +++++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl index dde0c17c39..3e7680f4bb 100644 --- a/lib/dialyzer/src/dialyzer.erl +++ b/lib/dialyzer/src/dialyzer.erl @@ -334,6 +334,9 @@ message_to_string({guard_fail, []}) -> "Clause guard cannot succeed.\n"; message_to_string({guard_fail, [Arg1, Infix, Arg2]}) -> io_lib:format("Guard test ~s ~s ~s can never succeed\n", [Arg1, Infix, Arg2]); +message_to_string({neg_guard_fail, [Arg1, Infix, Arg2]}) -> + io_lib:format("Guard test not(~s ~s ~s) can never succeed\n", + [Arg1, Infix, Arg2]); message_to_string({guard_fail, [Guard, Args]}) -> io_lib:format("Guard test ~w~s can never succeed\n", [Guard, Args]); message_to_string({neg_guard_fail, [Guard, Args]}) -> diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index f4e429e6fd..b01e7a4b05 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -2087,7 +2087,10 @@ handle_guard_eq(Guard, Map, Env, Eval, State) -> true -> if Eval =:= pos -> {Map, t_atom(true)}; - Eval =:= neg -> throw({fail, none}); + Eval =:= neg -> + ArgTypes = [t_from_term(cerl:concrete(Arg1)), + t_from_term(cerl:concrete(Arg2))], + signal_guard_fail(Eval, Guard, ArgTypes, State); Eval =:= dont_know -> {Map, t_atom(true)} end; false -> @@ -2142,7 +2145,10 @@ handle_guard_eqeq(Guard, Map, Env, Eval, State) -> {literal, literal} -> case cerl:concrete(Arg1) =:= cerl:concrete(Arg2) of true -> - if Eval =:= neg -> throw({fail, none}); + if Eval =:= neg -> + ArgTypes = [t_from_term(cerl:concrete(Arg1)), + t_from_term(cerl:concrete(Arg2))], + signal_guard_fail(Eval, Guard, ArgTypes, State); Eval =:= pos -> {Map, t_atom(true)}; Eval =:= dont_know -> {Map, t_atom(true)} end; @@ -2238,11 +2244,11 @@ handle_guard_and(Guard, Map, Env, Eval, State) -> pos -> {Map1, Type1} = bind_guard(Arg1, Map, Env, Eval, State), case t_is_atom(true, Type1) of - false -> throw({fail, none}); + false -> signal_guard_fail(Eval, Guard, [Type1, t_any()], State); true -> {Map2, Type2} = bind_guard(Arg2, Map1, Env, Eval, State), case t_is_atom(true, Type2) of - false -> throw({fail, none}); + false -> signal_guard_fail(Eval, Guard, [Type1, Type2], State); true -> {Map2, t_atom(true)} end end; @@ -2257,7 +2263,7 @@ handle_guard_and(Guard, Map, Env, Eval, State) -> end, case t_is_atom(false, Type1) orelse t_is_atom(false, Type2) of true -> {join_maps([Map1, Map2], Map), t_atom(false)}; - false -> throw({fail, none}) + false -> signal_guard_fail(Eval, Guard, [Type1, Type2], State) end; dont_know -> {Map1, Type1} = bind_guard(Arg1, Map, Env, dont_know, State), @@ -2297,16 +2303,16 @@ handle_guard_or(Guard, Map, Env, Eval, State) -> orelse (t_is_atom(true, Bool2) andalso t_is_boolean(Bool1))) of true -> {join_maps([Map1, Map2], Map), t_atom(true)}; - false -> throw({fail, none}) + false -> signal_guard_fail(Eval, Guard, [Bool1, Bool2], State) end; neg -> {Map1, Type1} = bind_guard(Arg1, Map, Env, neg, State), case t_is_atom(false, Type1) of - false -> throw({fail, none}); + false -> signal_guard_fail(Eval, Guard, [Type1, t_any()], State); true -> {Map2, Type2} = bind_guard(Arg2, Map1, Env, neg, State), case t_is_atom(false, Type2) of - false -> throw({fail, none}); + false -> signal_guard_fail(Eval, Guard, [Type1, Type2], State); true -> {Map2, t_atom(false)} end end; @@ -2337,13 +2343,17 @@ handle_guard_not(Guard, Map, Env, Eval, State) -> {Map1, Type} = bind_guard(Arg, Map, Env, pos, State), case t_is_atom(true, Type) of true -> {Map1, t_atom(false)}; - false -> throw({fail, none}) + false -> + {_, Type0} = bind_guard(Arg, Map, Env, Eval, State), + signal_guard_fail(Eval, Guard, [Type0], State) end; pos -> {Map1, Type} = bind_guard(Arg, Map, Env, neg, State), case t_is_atom(false, Type) of true -> {Map1, t_atom(true)}; - false -> throw({fail, none}) + false -> + {_, Type0} = bind_guard(Arg, Map, Env, Eval, State), + signal_guard_fail(Eval, Guard, [Type0], State) end; dont_know -> {Map1, Type} = bind_guard(Arg, Map, Env, dont_know, State), @@ -2382,9 +2392,15 @@ signal_guard_fail(Eval, Guard, ArgTypes, State) -> true -> [ArgType1, ArgType2] = ArgTypes, [Arg1, Arg2] = Args, - {guard_fail, [format_args_1([Arg1], [ArgType1], State), - atom_to_list(F), - format_args_1([Arg2], [ArgType2], State)]}; + Kind = + case Eval of + neg -> neg_guard_fail; + pos -> guard_fail; + dont_know -> guard_fail + end, + {Kind, [format_args_1([Arg1], [ArgType1], State), + atom_to_list(F), + format_args_1([Arg2], [ArgType2], State)]}; false -> mk_guard_msg(Eval, F, Args, ArgTypes, State) end, -- cgit v1.2.3