diff options
author | Björn-Egil Dahlberg <[email protected]> | 2015-03-12 17:09:13 +0100 |
---|---|---|
committer | Björn-Egil Dahlberg <[email protected]> | 2015-03-12 17:09:13 +0100 |
commit | e0e056a62c240542decac2e2b3765a5399efae62 (patch) | |
tree | e7e098af3cfe4c3f71c8b33c5740b61be8495f58 | |
parent | be5b000d488692b2e03c4f8318ce74712e56b7ee (diff) | |
parent | 12408cf3657a88540d7afde88e68639c72212299 (diff) | |
download | otp-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.c | 72 | ||||
-rw-r--r-- | erts/emulator/test/match_spec_SUITE.erl | 8 | ||||
-rw-r--r-- | lib/stdlib/test/ets_SUITE.erl | 5 |
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 '_'. |