diff options
author | Magnus Lång <[email protected]> | 2016-02-28 00:17:48 +0100 |
---|---|---|
committer | Hans Bolinder <[email protected]> | 2016-04-28 16:16:09 +0200 |
commit | ebd967522612333e52a884181e6132b1ba7e5239 (patch) | |
tree | cd12d37cd4fe9d375cf15acbad8d08e5a4542af5 /lib/dialyzer/src/dialyzer_typesig.erl | |
parent | e3ac51b173585f84c397ae38c27d772be2d308c6 (diff) | |
download | otp-ebd967522612333e52a884181e6132b1ba7e5239.tar.gz otp-ebd967522612333e52a884181e6132b1ba7e5239.tar.bz2 otp-ebd967522612333e52a884181e6132b1ba7e5239.zip |
dialyzer: Unfold cerl patterns containing maps
Dialyzer relies heavily on the assumption that the type of a literal
that is used as a pattern is the type of any value that can match that
pattern. For maps, that is not true, and it was causing bad analysis
results. A new help function dialyzer_utils:refold_pattern/1 identifies
maps in literal patterns, and unfolds and labels them, allowing them to
be properly analysed.
Diffstat (limited to 'lib/dialyzer/src/dialyzer_typesig.erl')
-rw-r--r-- | lib/dialyzer/src/dialyzer_typesig.erl | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl index 12d6673d28..810b7c55e9 100644 --- a/lib/dialyzer/src/dialyzer_typesig.erl +++ b/lib/dialyzer/src/dialyzer_typesig.erl @@ -393,8 +393,18 @@ traverse(Tree, DefinedVars, State) -> {State2, _} = traverse_list(Funs, DefinedVars1, State1), traverse(Body, DefinedVars1, State2); literal -> - Type = t_from_term(cerl:concrete(Tree)), - {State, Type}; + %% Maps are special; a literal pattern matches more than just the value + %% constructed by the literal. For example #{} constructs the empty map, + %% but matches every map. + case state__is_in_match(State) of + true -> + Tree1 = dialyzer_utils:refold_pattern(Tree), + case cerl:is_literal(Tree1) of + false -> traverse(Tree1, DefinedVars, State); + true -> {State, t_from_term(cerl:concrete(Tree))} + end; + _ -> {State, t_from_term(cerl:concrete(Tree))} + end; module -> Defs = cerl:module_defs(Tree), Funs = [Fun || {_Var, Fun} <- Defs], @@ -1110,7 +1120,9 @@ bitstr_val_constr(SizeType, UnitVal, Flags) -> end end. -get_safe_underapprox_1([Pat|Left], Acc, Map) -> +get_safe_underapprox_1([Pat0|Left], Acc, Map) -> + %% Maps should be treated as patterns, not as literals + Pat = dialyzer_utils:refold_pattern(Pat0), case cerl:type(Pat) of alias -> APat = cerl:alias_pat(Pat), |