summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn-Egil Dahlberg <egil@erlang.org>2014-04-04 12:00:07 +0200
committerBjörn-Egil Dahlberg <egil@erlang.org>2014-04-04 12:00:07 +0200
commit89eef897c6564c72d9717228a73959339e486bdb (patch)
treeebb39bfd3e9bbd3526b2996e36f1d57ee1f0b2c8
parent76c73b9554a3d74b027bc2e1fdace7192b7a8de6 (diff)
parente26dbc750fdd207c852bf9006668c5771f465dcf (diff)
downloaderlang-89eef897c6564c72d9717228a73959339e486bdb.tar.gz
Merge branch 'egil/maps-fix-map-key-patterns'
* egil/maps-fix-map-key-patterns: stdlib: Fix erl_id_trans example stdlib: Deny map keys defined as #{ .. := .. } in patterns compiler: Fix compiling map keys in patterns from core compiler,stdlib: Fix Map literals as keys for Maps in patterns
-rw-r--r--lib/compiler/src/cerl.erl2
-rw-r--r--lib/compiler/src/core_lib.erl11
-rw-r--r--lib/compiler/src/core_pp.erl6
-rw-r--r--lib/compiler/src/sys_core_fold.erl12
-rw-r--r--lib/compiler/src/sys_pre_expand.erl2
-rw-r--r--lib/compiler/src/v3_core.erl29
-rw-r--r--lib/compiler/test/map_SUITE.erl5
-rw-r--r--lib/stdlib/examples/erl_id_trans.erl2
-rw-r--r--lib/stdlib/src/erl_expand_records.erl6
-rw-r--r--lib/stdlib/src/erl_lint.erl36
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl14
11 files changed, 70 insertions, 55 deletions
diff --git a/lib/compiler/src/cerl.erl b/lib/compiler/src/cerl.erl
index ed11c8de4d..54eac20ac4 100644
--- a/lib/compiler/src/cerl.erl
+++ b/lib/compiler/src/cerl.erl
@@ -133,7 +133,7 @@
]).
-export_type([c_binary/0, c_bitstr/0, c_call/0, c_clause/0, c_cons/0, c_fun/0,
- c_literal/0, c_map_pair/0, c_module/0, c_tuple/0,
+ c_literal/0, c_map/0, c_map_pair/0, c_module/0, c_tuple/0,
c_values/0, c_var/0, cerl/0, var_name/0]).
-include("core_parse.hrl").
diff --git a/lib/compiler/src/core_lib.erl b/lib/compiler/src/core_lib.erl
index 93ec3bbad5..2792fd8fa5 100644
--- a/lib/compiler/src/core_lib.erl
+++ b/lib/compiler/src/core_lib.erl
@@ -59,7 +59,7 @@ is_lit_bin(Es) ->
%% Return the value of LitExpr.
-spec literal_value(cerl:c_literal() | cerl:c_binary() |
- cerl:c_cons() | cerl:c_tuple()) -> term().
+ cerl:c_map() | cerl:c_cons() | cerl:c_tuple()) -> term().
literal_value(#c_literal{val=V}) -> V;
literal_value(#c_binary{segments=Es}) ->
@@ -67,7 +67,14 @@ literal_value(#c_binary{segments=Es}) ->
literal_value(#c_cons{hd=H,tl=T}) ->
[literal_value(H)|literal_value(T)];
literal_value(#c_tuple{es=Es}) ->
- list_to_tuple(literal_value_list(Es)).
+ list_to_tuple(literal_value_list(Es));
+literal_value(#c_map{arg=Cm,es=Cmps}) ->
+ M = literal_value(Cm),
+ lists:foldl(fun(#c_map_pair{ key=Ck, val=Cv },Mi) ->
+ K = literal_value(Ck),
+ V = literal_value(Cv),
+ maps:put(K,V,Mi)
+ end, M, Cmps).
literal_value_list(Vals) -> [literal_value(V) || V <- Vals].
diff --git a/lib/compiler/src/core_pp.erl b/lib/compiler/src/core_pp.erl
index a76327457d..83412ecdd7 100644
--- a/lib/compiler/src/core_pp.erl
+++ b/lib/compiler/src/core_pp.erl
@@ -120,7 +120,11 @@ format_1(#c_literal{anno=A,val=Bitstring}, Ctxt) when is_bitstring(Bitstring) ->
format_1(#c_binary{anno=A,segments=Segs}, Ctxt);
format_1(#c_literal{anno=A,val=M},Ctxt) when is_map(M) ->
Pairs = maps:to_list(M),
- Cpairs = [#c_map_pair{op=#c_literal{val=assoc},
+ Op = case Ctxt of
+ #ctxt{ class = clause } -> exact;
+ _ -> assoc
+ end,
+ Cpairs = [#c_map_pair{op=#c_literal{val=Op},
key=#c_literal{val=V},
val=#c_literal{val=K}} || {K,V} <- Pairs],
format_1(#c_map{anno=A,arg=#c_literal{val=#{}},es=Cpairs},Ctxt);
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index b7422318b2..ce40213bad 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -1556,16 +1556,8 @@ map_pair_pattern_list(Ps0, Isub, Osub0) ->
{Ps,Osub}.
map_pair_pattern(#c_map_pair{op=#c_literal{val=exact},key=K0,val=V0}=Pair,{Isub,Osub0}) ->
- {K,Osub1} = case cerl:type(K0) of
- binary ->
- K1 = eval_binary(K0),
- case cerl:type(K1) of
- literal -> {K1,Osub0};
- _ -> pattern(K0,Isub,Osub0)
- end;
- _ -> pattern(K0,Isub,Osub0)
- end,
- {V,Osub} = pattern(V0,Isub,Osub1),
+ K = expr(K0, Isub),
+ {V,Osub} = pattern(V0,Isub,Osub0),
{Pair#c_map_pair{key=K,val=V},{Isub,Osub}}.
bin_pattern_list(Ps0, Isub, Osub0) ->
diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl
index 91a46a20fe..761ae8409c 100644
--- a/lib/compiler/src/sys_pre_expand.erl
+++ b/lib/compiler/src/sys_pre_expand.erl
@@ -232,7 +232,7 @@ pattern({map,Line,Ps}, St0) ->
{TPs,St1} = pattern_list(Ps, St0),
{{map,Line,TPs},St1};
pattern({map_field_exact,Line,K0,V0}, St0) ->
- {K,St1} = pattern(K0, St0),
+ {K,St1} = expr(K0, St0),
{V,St2} = pattern(V0, St1),
{{map_field_exact,Line,K,V},St2};
%%pattern({struct,Line,Tag,Ps}, St0) ->
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index a548ba2f7c..8c18f6a9f7 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1605,26 +1605,17 @@ 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) ->
- %% FIXME: Better way to construct literals? or missing case
- %% {Key,_,_} = expr(K, St),
- Key = case K of
- {bin,L,Es0} ->
- case constant_bin(Es0) of
- error ->
- %% this will throw a cryptic error message
- %% but it is better than nothing
- throw(nomatch);
- Bin ->
- #c_literal{anno=lineno_anno(L,St),val=Bin}
- end;
+ 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)};
_ ->
- pattern(K,St)
- end,
- #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)
+ end.
%% pat_bin([BinElement], State) -> [BinSeg].
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index cc018e4305..403b7e8405 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -113,6 +113,10 @@ t_build_and_match_literals(Config) when is_list(Config) ->
M = #{ map_1:=#{ map_2:=#{value_3 := third}, value_2:= second}, value_1:=first} =
id(#{ map_1=>#{ map_2=>#{value_3 => third}, value_2=> second}, value_1=>first}),
+ %% map key
+ #{ #{} := 42 } = id(#{ #{} => 42 }),
+ #{ #{ "a" => 3 } := 42 } = id(#{ #{ "a" => 3} => 42 }),
+
%% nil key
#{[]:=ok,1:=2} = id(#{[]=>ok,1=>2}),
@@ -123,6 +127,7 @@ t_build_and_match_literals(Config) when is_list(Config) ->
{'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id(#{y=>3}))),
{'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id(#{x=>"three"}))),
{'EXIT',{badarg,_}} = (catch id(#{<<0:258>> =>"three"})),
+ {'EXIT',{{badmatch,_},_}} = (catch (#{#{"a"=>42} := 3}=id(#{#{"a"=>3}=>42}))),
ok.
t_build_and_match_aliasing(Config) when is_list(Config) ->
diff --git a/lib/stdlib/examples/erl_id_trans.erl b/lib/stdlib/examples/erl_id_trans.erl
index 5fcb74310e..e71e26e51a 100644
--- a/lib/stdlib/examples/erl_id_trans.erl
+++ b/lib/stdlib/examples/erl_id_trans.erl
@@ -148,7 +148,7 @@ pattern({map,Line,Ps0}) ->
Ps1 = pattern_list(Ps0),
{map,Line,Ps1};
pattern({map_field_exact,Line,K,V}) ->
- Ke = pattern(K),
+ Ke = expr(K),
Ve = pattern(V),
{map_field_exact,Line,Ke,Ve};
%%pattern({struct,Line,Tag,Ps0}) ->
diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl
index f53c6e1278..57e768ba9d 100644
--- a/lib/stdlib/src/erl_expand_records.erl
+++ b/lib/stdlib/src/erl_expand_records.erl
@@ -135,10 +135,10 @@ pattern({tuple,Line,Ps}, St0) ->
pattern({map,Line,Ps}, St0) ->
{TPs,St1} = pattern_list(Ps, St0),
{{map,Line,TPs},St1};
-pattern({map_field_exact,Line,Key0,V0}, St0) ->
- {Key,St1} = pattern(Key0, St0),
+pattern({map_field_exact,Line,K0,V0}, St0) ->
+ {K,St1} = expr(K0, St0),
{V,St2} = pattern(V0, St1),
- {{map_field_exact,Line,Key,V},St2};
+ {{map_field_exact,Line,K,V},St2};
%%pattern({struct,Line,Tag,Ps}, St0) ->
%% {TPs,TPsvs,St1} = pattern_list(Ps, St0),
%% {{struct,Line,Tag,TPs},TPsvs,St1};
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index c4c94fbee4..7c064ce902 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -1407,7 +1407,7 @@ pattern({map,_Line,Ps}, Vt, Old, Bvt, St) ->
({map_field_assoc,L,_,_}, {Psvt,Bvt0,St0}) ->
{Psvt,Bvt0,add_error(L, illegal_pattern, St0)};
({map_field_exact,L,KP,VP}, {Psvt,Bvt0,St0}) ->
- case is_valid_map_key(KP, St0) of
+ case is_valid_map_key(KP, pattern, St0) of
true ->
{Pvt,Bvt1,St1} = pattern(VP, Vt, Old, Bvt, St0),
{vtmerge_pat(Pvt, Psvt),vtmerge_pat(Bvt0, Bvt1), St1};
@@ -2322,14 +2322,16 @@ is_valid_call(Call) ->
%% check for value expression without variables
is_valid_map_key(K,St) ->
+ is_valid_map_key(K,expr,St).
+is_valid_map_key(K,Ctx,St) ->
case expr(K,[],St) of
{[],_} ->
- is_valid_map_key_value(K);
+ is_valid_map_key_value(K,Ctx);
{[Var|_],_} ->
{false,variable,element(1,Var)}
end.
-is_valid_map_key_value(K) ->
+is_valid_map_key_value(K,Ctx) ->
case K of
{char,_,_} -> true;
{integer,_,_} -> true;
@@ -2338,34 +2340,36 @@ is_valid_map_key_value(K) ->
{nil,_} -> true;
{atom,_,_} -> true;
{cons,_,H,T} ->
- is_valid_map_key_value(H) andalso
- is_valid_map_key_value(T);
+ is_valid_map_key_value(H,Ctx) andalso
+ is_valid_map_key_value(T,Ctx);
{tuple,_,Es} ->
foldl(fun(E,B) ->
- B andalso is_valid_map_key_value(E)
+ B andalso is_valid_map_key_value(E,Ctx)
end,true,Es);
{map,_,Arg,Ps} ->
% only check for value expressions to be valid
% invalid map expressions are later checked in
% core and kernel
- is_valid_map_key_value(Arg) andalso foldl(fun
+ is_valid_map_key_value(Arg,Ctx) andalso foldl(fun
({Tag,_,Ke,Ve},B) when Tag =:= map_field_assoc;
- Tag =:= map_field_exact ->
- B andalso is_valid_map_key_value(Ke)
- andalso is_valid_map_key_value(Ve)
+ Tag =:= map_field_exact, Ctx =:= expr ->
+ B andalso is_valid_map_key_value(Ke,Ctx)
+ andalso is_valid_map_key_value(Ve,Ctx);
+ (_,_) -> false
end,true,Ps);
{map,_,Ps} ->
foldl(fun
({Tag,_,Ke,Ve},B) when Tag =:= map_field_assoc;
- Tag =:= map_field_exact ->
- B andalso is_valid_map_key_value(Ke)
- andalso is_valid_map_key_value(Ve)
+ Tag =:= map_field_exact, Ctx =:= expr ->
+ B andalso is_valid_map_key_value(Ke,Ctx)
+ andalso is_valid_map_key_value(Ve,Ctx);
+ (_,_) -> false
end, true, Ps);
{record,_,_,Fs} ->
foldl(fun
({record_field,_,Ke,Ve},B) ->
- B andalso is_valid_map_key_value(Ke)
- andalso is_valid_map_key_value(Ve)
+ B andalso is_valid_map_key_value(Ke,Ctx)
+ andalso is_valid_map_key_value(Ve,Ctx)
end,true,Fs);
{bin,_,Es} ->
% only check for value expressions to be valid
@@ -2373,7 +2377,7 @@ is_valid_map_key_value(K) ->
% core and kernel
foldl(fun
({bin_element,_,E,_,_},B) ->
- B andalso is_valid_map_key_value(E)
+ B andalso is_valid_map_key_value(E,Ctx)
end,true,Es);
_ -> false
end.
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index bb14de333d..d9512c0ef4 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -3406,7 +3406,19 @@ maps(Config) ->
{4,erl_lint,illegal_map_key},
{6,erl_lint,illegal_map_key},
{8,erl_lint,illegal_map_key},
- {10,erl_lint,illegal_map_key}],[]}}],
+ {10,erl_lint,illegal_map_key}],[]}},
+ {errors_in_map_keys_pattern,
+ <<"t(#{ a := 2,
+ #{} := A,
+ #{ 3 => 33 } := hi,
+ #{ 3 := 33 } := hi,
+ #{ hi => 54, \"hello\" => 45 } := hi,
+ #{ V => 33 } := hi }) ->
+ A.
+ ">>,
+ [],
+ {errors,[{4,erl_lint,illegal_map_key},
+ {6,erl_lint,{illegal_map_key_variable,'V'}}],[]}}],
[] = run(Config, Ts),
ok.