summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn-Egil Dahlberg <egil@erlang.org>2014-04-02 17:00:43 +0200
committerBjörn-Egil Dahlberg <egil@erlang.org>2014-04-03 14:32:44 +0200
commitcc7a3c5896bc266bb97287dd4e31b696d8cf604f (patch)
treed19e07f7b30e2723184e1789f9113f6060428a15
parenteba291a52d4a78c128c5802775fa1bff187e0604 (diff)
downloaderlang-cc7a3c5896bc266bb97287dd4e31b696d8cf604f.tar.gz
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/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/src/erl_expand_records.erl6
6 files changed, 29 insertions, 26 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/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/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};