diff options
author | Björn Gustavsson <[email protected]> | 2016-08-15 15:34:06 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2016-09-02 14:24:36 +0200 |
commit | 0baa07cdf2754748bbc2d969bf83f08c0976fb78 (patch) | |
tree | b5d649dbe4778d8488ae09a99e68435adc216342 /lib/debugger | |
parent | 8a04dd4dd2d479efe488b0bed118e10559835fb6 (diff) | |
download | otp-0baa07cdf2754748bbc2d969bf83f08c0976fb78.tar.gz otp-0baa07cdf2754748bbc2d969bf83f08c0976fb78.tar.bz2 otp-0baa07cdf2754748bbc2d969bf83f08c0976fb78.zip |
Fix overridden BIFs
The filters in a list comprehension can be guard expressions or
an ordinary expressions.
If a guard expression is used as a filter, an exception will basically
mean the same as 'false':
t() ->
L = [{some_tag,42},an_atom],
[X || X <- L, element(1, X) =:= some_tag]
%% Returns [{some_tag,42}]
On the other hand, if an ordinary expression is used as a filter, there
will be an exception:
my_element(N, T) -> element(N, T).
t() ->
L = [{some_tag,42},an_atom],
[X || X <- L, my_element(1, X) =:= some_tag]
%% Causes a 'badarg' exception when element(1, an_atom) is evaluated
It has been allowed for several releases to override a BIF with
a local function. Thus, if we define a function called element/2,
it will be called instead of the BIF element/2 within the module.
We must use the "erlang:" prefix to call the BIF.
Therefore, the following code is expected to work the same way as in
our second example above:
-compile({no_auto_import,[element/2]}).
element(N, T) ->
erlang:element(N, T).
t() ->
L = [{some_tag,42},an_atom],
[X || X <- L, element(1, X) =:= some_tag].
%% Causes a 'badarg' exception when element(1, an_atom) is evaluated
But the compiler refuses to compile the code with the following
diagnostic:
call to local/imported function element/2 is illegal in guard
Diffstat (limited to 'lib/debugger')
-rw-r--r-- | lib/debugger/src/dbg_iload.erl | 45 | ||||
-rw-r--r-- | lib/debugger/test/Makefile | 1 | ||||
-rw-r--r-- | lib/debugger/test/overridden_bif_SUITE.erl | 99 | ||||
-rw-r--r-- | lib/debugger/test/test_lib.erl | 7 |
4 files changed, 128 insertions, 24 deletions
diff --git a/lib/debugger/src/dbg_iload.erl b/lib/debugger/src/dbg_iload.erl index 917f213e60..22e2073df8 100644 --- a/lib/debugger/src/dbg_iload.erl +++ b/lib/debugger/src/dbg_iload.erl @@ -486,30 +486,10 @@ expr({'try',Anno,Es0,CaseCs0,CatchCs0,As0}, Lc) -> CatchCs = icr_clauses(CatchCs0, Lc), As = expr_list(As0), {'try',ln(Anno),Es,CaseCs,CatchCs,As}; -expr({lc,Anno,E0,Gs0}, _Lc) -> %R8. - Gs = lists:map(fun ({generate,L,P0,Qs}) -> - {generate,L,pattern(P0),expr(Qs, false)}; - ({b_generate,L,P0,Qs}) -> %R12. - {b_generate,L,pattern(P0),expr(Qs, false)}; - (Expr) -> - case erl_lint:is_guard_test(Expr) of - true -> {guard,guard([[Expr]])}; - false -> expr(Expr, false) - end - end, Gs0), - {lc,ln(Anno),expr(E0, false),Gs}; -expr({bc,Anno,E0,Gs0}, _Lc) -> %R12. - Gs = lists:map(fun ({generate,L,P0,Qs}) -> - {generate,L,pattern(P0),expr(Qs, false)}; - ({b_generate,L,P0,Qs}) -> %R12. - {b_generate,L,pattern(P0),expr(Qs, false)}; - (Expr) -> - case erl_lint:is_guard_test(Expr) of - true -> {guard,guard([[Expr]])}; - false -> expr(Expr, false) - end - end, Gs0), - {bc,ln(Anno),expr(E0, false),Gs}; +expr({lc,_,_,_}=Compr, _Lc) -> + expr_lc_bc(Compr); +expr({bc,_,_,_}=Compr, _Lc) -> + expr_lc_bc(Compr); expr({match,Anno,P0,E0}, _Lc) -> E1 = expr(E0, false), P1 = pattern(P0), @@ -560,6 +540,23 @@ make_bit_type(_Line, Size, Type0) -> %Integer or 'all' {ok,Size,Bt} = erl_bits:set_bit_type(Size, Type0), {Size,erl_bits:as_list(Bt)}. +expr_lc_bc({Tag,Anno,E0,Gs0}) -> + Gs = lists:map(fun ({generate,L,P0,Qs}) -> + {generate,L,pattern(P0),expr(Qs, false)}; + ({b_generate,L,P0,Qs}) -> %R12. + {b_generate,L,pattern(P0),expr(Qs, false)}; + (Expr) -> + case is_guard_test(Expr) of + true -> {guard,guard([[Expr]])}; + false -> expr(Expr, false) + end + end, Gs0), + {Tag,ln(Anno),expr(E0, false),Gs}. + +is_guard_test(Expr) -> + IsOverridden = fun({_,_}) -> true end, + erl_lint:is_guard_test(Expr, [], IsOverridden). + %% The debugger converts both strings "abc" and lists [67, 68, 69] %% into {value, Line, [67, 68, 69]}, making it impossible to later %% distingish one or the other inside binaries when evaluating. To diff --git a/lib/debugger/test/Makefile b/lib/debugger/test/Makefile index 125abcacda..efb6d9ed8b 100644 --- a/lib/debugger/test/Makefile +++ b/lib/debugger/test/Makefile @@ -46,6 +46,7 @@ MODULES= \ lc_SUITE \ line_number_SUITE \ map_SUITE \ + overridden_bif_SUITE \ record_SUITE \ trycatch_SUITE \ test_lib \ diff --git a/lib/debugger/test/overridden_bif_SUITE.erl b/lib/debugger/test/overridden_bif_SUITE.erl new file mode 100644 index 0000000000..04bef3c0a2 --- /dev/null +++ b/lib/debugger/test/overridden_bif_SUITE.erl @@ -0,0 +1,99 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2016. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(overridden_bif_SUITE). +-compile({no_auto_import,[is_reference/1,size/1]}). + +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2, + init_per_testcase/2,end_per_testcase/2, + overridden_bif/1]). + +-include_lib("common_test/include/ct.hrl"). + +%% Used by overridden_bif/1. +-import(gb_sets, [size/1]). +-import(test_lib, [binary/1]). + +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,1}}]. + +all() -> + [overridden_bif]. + +groups() -> + []. + +init_per_suite(Config) -> + test_lib:interpret(?MODULE), + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> + Config. + +end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> + ok. + +overridden_bif(_Config) -> + L = [-3,-2,-1,0,1,2,3,4], + [-3,0,3] = do_overridden_bif_1(L), + [-2,0,2,4] = do_overridden_bif_2(L), + [3] = do_overridden_bif_3(L), + [2,4] = do_overridden_bif_4(L), + + Set = gb_sets:from_list(L), + [Set] = do_overridden_bif_5([gb_sets:singleton(42),Set]), + + [100,0] = do_overridden_bif_6([100|L]), + ok. + +do_overridden_bif_1(L) -> + [E || E <- L, is_reference(E)]. + +do_overridden_bif_2(L) -> + [E || E <- L, port(E)]. + +do_overridden_bif_3(L) -> + [E || E <- L, (is_reference(E) andalso E > 0)]. + +do_overridden_bif_4(L) -> + [E || E <- L, (port(E) andalso E > 0)]. + +do_overridden_bif_5(L) -> + [E || E <- L, size(E) > 1]. + +do_overridden_bif_6(L) -> + [E || E <- L, binary(E)]. + +is_reference(N) -> + N rem 3 =:= 0. + +port(N) -> + N rem 2 =:= 0. diff --git a/lib/debugger/test/test_lib.erl b/lib/debugger/test/test_lib.erl index b9ac486694..7e98d210e8 100644 --- a/lib/debugger/test/test_lib.erl +++ b/lib/debugger/test/test_lib.erl @@ -23,8 +23,15 @@ -export([interpret/1]). +%% Used by test case that override BIFs. +-export([binary/1]). + interpret(Mod) when is_atom(Mod) -> case lists:member(Mod, int:interpreted()) of true -> ok; false -> {module,Mod} = i:ii(Mod) end. + +%% This is for overridden_bif_SUITE. +binary(N) -> + N rem 10 =:= 0. |