From 56f9f62b59eda9dcc36bd47efef68b0243e0cfd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 28 Nov 2014 02:42:46 +0100 Subject: compiler: Coalesce map keys in dialyzer mode This fixes a regression introduced in commit 805f9c89fc01220bc1bb0f27e1b68fd4eca688ba The problem occured with map keys compiled with dialyzer option turned on. In OTP 17, map keys needs to be literals. --- lib/compiler/src/v3_core.erl | 57 +++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index caf5298d38..59ec0d4199 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -786,23 +786,42 @@ is_valid_map_src(_) -> false. map_pair_list(Es, St) -> foldr(fun ({map_field_assoc,L,K0,V0}, {Ces,Esp,St0}) -> - {K,Ep0,St1} = safe(K0, St0), - ok = ensure_valid_map_key(K), + {K1,Ep0,St1} = safe(K0, St0), + K = ensure_valid_map_key(K1), {V,Ep1,St2} = safe(V0, St1), A = lineno_anno(L, St2), Pair = #c_map_pair{op=#c_literal{val=assoc},anno=A,key=K,val=V}, {[Pair|Ces],Ep0 ++ Ep1 ++ Esp,St2}; ({map_field_exact,L,K0,V0}, {Ces,Esp,St0}) -> - {K,Ep0,St1} = safe(K0, St0), - ok = ensure_valid_map_key(K), + {K1,Ep0,St1} = safe(K0, St0), + K = ensure_valid_map_key(K1), {V,Ep1,St2} = safe(V0, St1), A = lineno_anno(L, St2), Pair = #c_map_pair{op=#c_literal{val=exact},anno=A,key=K,val=V}, {[Pair|Ces],Ep0 ++ Ep1 ++ Esp,St2} end, {[],[],St}, Es). -ensure_valid_map_key(#c_literal{}) -> ok; -ensure_valid_map_key(_) -> throw({bad_map,bad_map_key}). +ensure_valid_map_key(K0) -> + case coalesced_map_key(K0) of + {ok,K1} -> K1; + error -> throw({bad_map,bad_map_key}) + end. + +coalesced_map_key(#c_literal{}=K) -> {ok,K}; +%% Dialyzer hack redux +%% DO coalesce tuples and list in maps for dialyzer +%% Dialyzer tries to break this apart, don't let it +coalesced_map_key(#c_tuple{}=K) -> + case core_lib:is_literal(K) of + true -> {ok,cerl:fold_literal(K)}; + false -> error + end; +coalesced_map_key(#c_cons{}=K) -> + case core_lib:is_literal(K) of + true -> {ok,cerl:fold_literal(K)}; + false -> error + end; +coalesced_map_key(_) -> error. %% try_exception([ExcpClause], St) -> {[ExcpVar],Handler,St}. @@ -1606,17 +1625,23 @@ pattern_alias_map_pair_patterns([Cv]) -> Cv; pattern_alias_map_pair_patterns([Cv1,Cv2|Cvs]) -> pattern_alias_map_pair_patterns([pat_alias(Cv1,Cv2)|Cvs]). -pattern_map_pair({map_field_exact,L,K,V}, St) -> +pattern_map_pair({map_field_exact,L,K,V},St) -> + #c_map_pair{anno=lineno_anno(L, St), + op=#c_literal{val=exact}, + key=pattern_map_key(K,St), + val=pattern(V, St)}. + +pattern_map_key(K,St) -> + %% Throws 'nomatch' if the key can't be a literal + %% this will be a cryptic error message but it is better than nothing case expr(K,St) of - {#c_literal{}=Key,_,_} -> - #c_map_pair{anno=lineno_anno(L, St), - op=#c_literal{val=exact}, - key=Key, - val=pattern(V, St)}; - _ -> - %% this will throw a cryptic error message - %% but it is better than nothing - throw(nomatch) + {Key0,[],_} -> + %% Dialyzer hack redux + case coalesced_map_key(Key0) of + {ok,Key1} -> Key1; + error -> throw(nomatch) + end; + _ -> throw(nomatch) end. %% pat_bin([BinElement], State) -> [BinSeg]. -- cgit v1.2.3 From 6f7dd46137f9651b2f1b1b6f9803cd2434cb87eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 1 Dec 2014 16:40:13 +0100 Subject: dialyzer: Test recoalesced map keys --- lib/dialyzer/test/small_SUITE_data/src/maps1.erl | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/dialyzer/test/small_SUITE_data/src/maps1.erl b/lib/dialyzer/test/small_SUITE_data/src/maps1.erl index 06ced5b69e..228ffe2c22 100644 --- a/lib/dialyzer/test/small_SUITE_data/src/maps1.erl +++ b/lib/dialyzer/test/small_SUITE_data/src/maps1.erl @@ -10,6 +10,7 @@ -export([recv/3, decode/1]). +-export([get_my_map/0,is_my_map/1]). %-record(can_pkt, {id, data :: binary(), timestamp}). @@ -39,3 +40,38 @@ t2() -> ok. update(#{ id := Id, val := Val } = M, X) when is_integer(Id) -> M#{ val := [Val,X] }. + +%% key coalescing + +-spec get_my_map() -> map(). + +get_my_map() -> + #{labels => [one, two], + number => 27, + [1,2,3] => wer, + {4,5,6} => sdf, + kvok => #{ + <<"wat">> => v, + a => qwe, + 2 => asd, + [1,2,3] => wer, + {4,5,6} => sdf, + "abc" => zxc + } + }. + +-spec is_my_map(map()) -> 'ok'. + +is_my_map(#{labels := [one, two], + number := 27, + [1,2,3] := wer, + {4,5,6} := sdf, + kvok := #{ + <<"wat">> := v, + a := qwe, + 2 := asd, + [1,2,3] := wer, + {4,5,6} := sdf, + "abc" := zxc + } + }) -> ok. -- cgit v1.2.3