diff options
author | Björn Gustavsson <[email protected]> | 2018-08-10 07:43:31 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2018-08-13 09:26:36 +0200 |
commit | 7e1eb2ed1f724945884d839bd8a99154e9382849 (patch) | |
tree | 42dd357548847ad0197c825157a2b091838a6099 /lib/compiler/src | |
parent | 77d307e6c3e705e14843101d4c5348c6c079ace0 (diff) | |
download | otp-7e1eb2ed1f724945884d839bd8a99154e9382849.tar.gz otp-7e1eb2ed1f724945884d839bd8a99154e9382849.tar.bz2 otp-7e1eb2ed1f724945884d839bd8a99154e9382849.zip |
Correct error behavior of is_map_key/2 in guards
Consider the following functions:
foo() -> bar(not_a_map).
bar(M) when not is_map_key(a, M) -> ok;
bar(_) -> error.
What will `foo/0` return? It depends. If the module is compiled
with the default compiler options, the return value will be
`ok`. If the module is compiled with the `inline` option,
the return value will be `error`.
The correct value is `error`, because the call to `is_map_key/2`
when the second argument is not a map should fail the entire
guard. That is the way other failing guards BIFs are handled.
For example:
foo() -> bar(not_a_tuple).
bar(T) when not element(1, T) -> ok;
bar(_) -> error.
`foo/0` always returns `error` (whether the code is inlined
or not).
This bug can be fixed by changing the classification of `is_map_key/2`
in the `erl_internal` module. It is now classified as a type test,
which is incorrect because type tests should not fail. Reclassifying
it as a plain guard BIF corrects the bug.
This correction also fixes the internal consistency check
failure which was reported in:
https://bugs.erlang.org/browse/ERL-699
Diffstat (limited to 'lib/compiler/src')
-rw-r--r-- | lib/compiler/src/v3_codegen.erl | 5 |
1 files changed, 0 insertions, 5 deletions
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl index 6cd114abf7..e9152ba88f 100644 --- a/lib/compiler/src/v3_codegen.erl +++ b/lib/compiler/src/v3_codegen.erl @@ -1621,11 +1621,6 @@ test_cg(is_boolean, [#k_atom{val=Val}], Fail, I, Vdb, Bef, St) -> false -> [{jump,{f,Fail}}] end, {Is,Aft,St}; -test_cg(is_map_key, As, Fail, I, Vdb, Bef, St) -> - [Key,Map] = cg_reg_args(As, Bef), - Aft = clear_dead(Bef, I, Vdb), - F = {f,Fail}, - {[{test,is_map,F,[Map]},{test,has_map_fields,F,Map,{list,[Key]}}],Aft,St}; test_cg(Test, As, Fail, I, Vdb, Bef, St) -> Args = cg_reg_args(As, Bef), Aft = clear_dead(Bef, I, Vdb), |