aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn-Egil Dahlberg <[email protected]>2015-03-12 17:09:13 +0100
committerBjörn-Egil Dahlberg <[email protected]>2015-03-12 17:09:13 +0100
commite0e056a62c240542decac2e2b3765a5399efae62 (patch)
treee7e098af3cfe4c3f71c8b33c5740b61be8495f58
parentbe5b000d488692b2e03c4f8318ce74712e56b7ee (diff)
parent12408cf3657a88540d7afde88e68639c72212299 (diff)
downloadotp-e0e056a62c240542decac2e2b3765a5399efae62.tar.gz
otp-e0e056a62c240542decac2e2b3765a5399efae62.tar.bz2
otp-e0e056a62c240542decac2e2b3765a5399efae62.zip
Merge branch 'nox/maps-match_specs-fixes/OTP-12270'
* nox/maps-match_specs-fixes/OTP-12270: erts: Strengthen maps match spec compilation tests Properly collect variables in match specs with maps Fix compilation of match specs with maps
-rw-r--r--erts/emulator/beam/erl_db_util.c72
-rw-r--r--erts/emulator/test/match_spec_SUITE.erl8
-rw-r--r--lib/stdlib/test/ets_SUITE.erl5
3 files changed, 60 insertions, 25 deletions
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index 7eb80e3bb1..748be93fe3 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -214,8 +214,8 @@ typedef enum {
matchPushT,
matchPushL,
matchPushM,
- matchPushK,
matchPop,
+ matchSwap,
matchBind,
matchCmp,
matchEqBin,
@@ -225,6 +225,7 @@ typedef enum {
matchEq,
matchList,
matchMap,
+ matchKey,
matchSkip,
matchPushC,
matchConsA, /* Car is below Cdr */
@@ -1399,22 +1400,26 @@ restart:
}
goto error;
}
- DMC_PUSH(text, matchPushK);
- ++(context.stack_used);
+ DMC_PUSH(text, matchKey);
DMC_PUSH(text, dmc_private_copy(&context, key));
- }
- if (context.stack_used > context.stack_need) {
- context.stack_need = context.stack_used;
- }
- for (i = num_iters; i--; ) {
- Eterm value = map_get_values(map_val(t))[i];
- DMC_PUSH(text, matchPop);
- --(context.stack_used);
- res = dmc_one_term(&context, &heap, &stack, &text,
- value);
- ASSERT(res != retFail);
- if (res == retRestart) {
- goto restart;
+ {
+ int old_stack = ++(context.stack_used);
+ Eterm value = map_get_values(map_val(t))[i];
+ res = dmc_one_term(&context, &heap, &stack, &text,
+ value);
+ ASSERT(res != retFail);
+ if (res == retRestart) {
+ goto restart;
+ }
+ if (old_stack != context.stack_used) {
+ ASSERT(old_stack + 1 == context.stack_used);
+ DMC_PUSH(text, matchSwap);
+ }
+ if (context.stack_used > context.stack_need) {
+ context.stack_need = context.stack_used;
+ }
+ DMC_PUSH(text, matchPop);
+ --(context.stack_used);
}
}
break;
@@ -1960,17 +1965,23 @@ restart:
}
*sp++ = map_val_rel(*ep++, base);
break;
- case matchPushK:
+ case matchKey:
t = (Eterm) *pc++;
tp = erts_maps_get_rel(t, make_map_rel(ep, base), base);
if (!tp) {
FAIL();
}
- *sp++ = tp;
+ *sp++ = ep;
+ ep = tp;
break;
case matchPop:
ep = *(--sp);
break;
+ case matchSwap:
+ tp = sp[-1];
+ sp[-1] = sp[-2];
+ sp[-2] = tp;
+ break;
case matchBind:
n = *pc++;
variables[n].term = *ep++;
@@ -3275,7 +3286,14 @@ int db_has_variable(Eterm node) {
while(arity--) {
ESTACK_PUSH(s,*(++tuple));
}
- }
+ } else if (is_map(node)) {
+ Eterm *values = map_get_values(map_val(node));
+ int size = map_get_size(map_val(node));
+ ESTACK_PUSH(s, ((map_t *) map_val(node))->keys);
+ while (size--) {
+ ESTACK_PUSH(s, *(values++));
+ }
+ }
break;
case TAG_PRIMARY_IMMED1:
if (node == am_Underscore || db_is_variable(node) >= 0) {
@@ -5302,6 +5320,12 @@ void db_match_dis(Binary *bp)
++t;
erts_printf("Map\t%beu\n", n);
break;
+ case matchKey:
+ ++t;
+ p = (Eterm) *t;
+ ++t;
+ erts_printf("Key\t%p (%T)\n", t, p);
+ break;
case matchPushT:
++t;
n = *t;
@@ -5318,16 +5342,14 @@ void db_match_dis(Binary *bp)
++t;
erts_printf("PushM\t%beu\n", n);
break;
- case matchPushK:
- ++t;
- p = (Eterm) *t;
- ++t;
- erts_printf("PushK\t%p (%T)\n", t, p);
- break;
case matchPop:
++t;
erts_printf("Pop\n");
break;
+ case matchSwap:
+ ++t;
+ erts_printf("Swap\n");
+ break;
case matchBind:
++t;
n = *t;
diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl
index fc4a5028e1..b231c2bbd9 100644
--- a/erts/emulator/test/match_spec_SUITE.erl
+++ b/erts/emulator/test/match_spec_SUITE.erl
@@ -924,6 +924,14 @@ maps(Config) when is_list(Config) ->
table),
{ok,#{foo := 3},[],[]} =
erlang:match_spec_test({}, [{{},[],[#{foo => {'+',1,2}}]}], table),
+ {ok,"camembert",[],[]} =
+ erlang:match_spec_test(#{b => "camembert",c => "cabécou"},
+ [{#{b => '$1',c => "cabécou"},[],['$1']}], table),
+
+ {ok,#{a :="camembert",b := "hi"},[],[]} =
+ erlang:match_spec_test(#{<<"b">> =>"camembert","c"=>"cabécou", "wat"=>"hi", b=><<"other">>},
+ [{#{<<"b">> => '$1',"wat" => '$2'},[],[#{a=>'$1',b=>'$2'}]}],
+ table),
ok.
empty_list(Config) when is_list(Config) ->
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 2674f6886f..72f3c49b5a 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -3779,6 +3779,7 @@ match_object_do(Opts) ->
?line ets:insert(Tab,{{one,5},5}),
?line ets:insert(Tab,{{two,4},4}),
?line ets:insert(Tab,{{two,5},6}),
+ ?line ets:insert(Tab, {#{camembert=>cabécou},7}),
?line case ets:match_object(Tab, {{one, '_'}, '$0'}) of
[{{one,5},5},{{one,4},4}] -> ok;
[{{one,4},4},{{one,5},5}] -> ok;
@@ -3799,6 +3800,10 @@ match_object_do(Opts) ->
[{{two,4},4},{{two,5},6}] -> ok;
_ -> ?t:fail("ets:match_object() returned something funny.")
end,
+ % Check that maps are inspected for variables.
+ [{#{camembert:=cabécou},7}] =
+ ets:match_object(Tab, {#{camembert=>'_'},7}),
+ {'EXIT',{badarg,_}} = (catch ets:match_object(Tab, {#{'$1'=>'_'},7})),
% Check that unsucessful match returns an empty list.
?line [] = ets:match_object(Tab, {{three,'$0'}, '$92'}),
% Check that '$0' equals '_'.