From be782d05bcd259b229efcac47c0566e4026cf1f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 24 Sep 2013 15:22:41 +0200 Subject: compiler: Check for duplicate key literals in Map If a literal key already is present in a Map update the latter should be used. Warn for previous duplicates in the Map. --- lib/compiler/src/sys_core_fold.erl | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'lib/compiler') diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index 672a8b94c0..cdbe2d0753 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -418,8 +418,31 @@ expr(#c_try{anno=A,arg=E0,vars=Vs0,body=B0,evars=Evs0,handler=H0}=Try, _, Sub0) expr_list(Es, Ctxt, Sub) -> [expr(E, Ctxt, Sub) || E <- Es]. +%% traverse pairs in reverse +%% - remove later literals since they will be overwritten. + pair_list(Es, Ctxt, Sub) -> - [pair(E, Ctxt, Sub) || E <- Es]. + pair_list_reversed(lists:reverse(Es), Ctxt, Sub, [], gb_sets:empty()). + +pair_list_reversed([],_,_,Es,_) -> Es; +pair_list_reversed([E|Es],Ctxt,Sub,Out,Keys) -> + Pair = pair(E,Ctxt,Sub), + case map_has_key(Pair,Keys) of + {false,Keys1} -> + pair_list_reversed(Es,Ctxt,Sub,[Pair|Out],Keys1); + {true,K} -> + add_warning(E, {map_pair_key_overloaded,K}), + pair_list_reversed(Es,Ctxt,Sub,Out,Keys) + end. + +%% check if key already is present in map, i.e. #{ a=>1, a=>2 } +%% where 'a' is duplicate. Update maps set with the key if not present. + +map_has_key(#c_map_pair{key=#c_literal{val=K}},Ks) -> + case gb_sets:is_element(K,Ks) of + false -> {false, gb_sets:add(K,Ks)}; + true -> {true, K} + end. pair(#c_map_pair{key=K,val=V}, effect, Sub) -> make_effect_seq([K,V], Sub); @@ -697,7 +720,7 @@ useless_call(effect, #c_call{anno=Anno, useless_call(_, _) -> no. %% make_effect_seq([Expr], Sub) -> #c_seq{}|void() -%% Convert a list of epressions evaluated in effect context to a chain of +%% Convert a list of expressions evaluated in effect context to a chain of %% #c_seq{}. The body in the innermost #c_seq{} will be void(). %% Anything that will not have any effect will be thrown away. @@ -3019,6 +3042,9 @@ format_error(result_ignored) -> "(suppress the warning by assigning the expression to the _ variable)"; format_error(useless_building) -> "a term is constructed, but never used"; +format_error({map_pair_key_overloaded,K}) -> + M = io_lib:format("the key ~p is used multiple times in map value association",[K]), + flatten(M); format_error(bin_opt_alias) -> "INFO: the '=' operator will prevent delayed sub binary optimization"; format_error(bin_partition) -> -- cgit v1.2.3