aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnthony Ramine <[email protected]>2015-03-11 14:03:58 +0100
committerAnthony Ramine <[email protected]>2015-03-11 14:22:40 +0100
commitd6073d78109f026ef96b29af4ce748242df2389d (patch)
treedd5cffb4e022e2007a298f49b8109b2aa8aaf139
parent735871e63c86814a0f099ab422b4d5bc8821579a (diff)
downloadotp-d6073d78109f026ef96b29af4ce748242df2389d.tar.gz
otp-d6073d78109f026ef96b29af4ce748242df2389d.tar.bz2
otp-d6073d78109f026ef96b29af4ce748242df2389d.zip
Fix compilation of match specs with maps
The previous compilation was just plain wrong with push/pop mismatches. Reported-by: Björn-Egil Dahlberg
-rw-r--r--erts/emulator/beam/erl_db_util.c63
-rw-r--r--erts/emulator/test/match_spec_SUITE.erl3
2 files changed, 42 insertions, 24 deletions
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index 7eb80e3bb1..1d986f2447 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++;
@@ -5302,6 +5313,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 +5335,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..02ef4f8e3f 100644
--- a/erts/emulator/test/match_spec_SUITE.erl
+++ b/erts/emulator/test/match_spec_SUITE.erl
@@ -924,6 +924,9 @@ 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.
empty_list(Config) when is_list(Config) ->