Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:24
erlang
5021-Allow-max-2-and-min-2-to-be-used-in-guards...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 5021-Allow-max-2-and-min-2-to-be-used-in-guards.patch of Package erlang
From 5da4b90d861e75bf913b420bd810f5ce3c1c0cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org> Date: Fri, 16 Dec 2022 04:07:03 +0100 Subject: [PATCH] Allow max/2 and min/2 to be used in guards Closes #6544 --- erts/doc/src/erlang.xml | 4 +++ erts/doc/src/match_spec.xml | 12 ++++++-- erts/emulator/beam/bif.tab | 6 ++++ erts/emulator/beam/erl_bif_guard.c | 10 +++++++ erts/emulator/beam/erl_db_util.c | 12 ++++++++ erts/emulator/test/bif_SUITE.erl | 32 ++++++++++----------- erts/preloaded/src/erlang.erl | 4 +++ lib/compiler/src/beam_ssa_codegen.erl | 2 ++ lib/compiler/src/compile.erl | 2 +- lib/compiler/src/v3_kernel.erl | 30 +++++++++++++------ lib/stdlib/src/erl_internal.erl | 2 ++ lib/stdlib/src/ms_transform.erl | 2 ++ lib/stdlib/test/ms_transform_SUITE.erl | 2 ++ system/doc/reference_manual/expressions.xml | 9 ++++++ 14 files changed, 100 insertions(+), 29 deletions(-) diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 6ef15d73ab..27c72ce8b2 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -4229,6 +4229,8 @@ is_process_alive(P2Pid), <pre> > <input>max("abc", "b").</input> "b"</pre> + <p>Allowed in guard tests.</p> + <change><p>Allowed in guards tests from Erlang/OTP 26.</p></change> </desc> </func> @@ -4481,6 +4483,8 @@ RealSystem = system + MissedSystem</code> <pre> > <input>min("abc", "b").</input> "abc"</pre> + <p>Allowed in guard tests.</p> + <change><p>Allowed in guards tests from Erlang/OTP 26.</p></change> </desc> </func> diff --git a/erts/doc/src/match_spec.xml b/erts/doc/src/match_spec.xml index 988f895dde..62ddefdc47 100644 --- a/erts/doc/src/match_spec.xml +++ b/erts/doc/src/match_spec.xml @@ -111,7 +111,9 @@ <item>GuardFunction ::= BoolFunction | <c><![CDATA[abs]]></c> | <c><![CDATA[element]]></c> | <c><![CDATA[hd]]></c> | <c><![CDATA[length]]></c> | <c><![CDATA[map_get]]></c> | - <c><![CDATA[map_size]]></c> | <c><![CDATA[node]]></c> | + <c><![CDATA[map_size]]></c> | + <c><![CDATA[max]]></c> | <c><![CDATA[min]]></c> | + <c><![CDATA[node]]></c> | <c><![CDATA[round]]></c> | <c><![CDATA[size]]></c> | <c><![CDATA[bit_size]]></c> | <c><![CDATA[byte_size]]></c> | <c><![CDATA[tl]]></c> | <c><![CDATA[trunc]]></c> | @@ -195,7 +197,9 @@ <item>GuardFunction ::= BoolFunction | <c><![CDATA[abs]]></c> | <c><![CDATA[element]]></c> | <c><![CDATA[hd]]></c> | <c><![CDATA[length]]></c> | <c><![CDATA[map_get]]></c> | - <c><![CDATA[map_size]]></c> | <c><![CDATA[node]]></c> | + <c><![CDATA[map_size]]></c> | + <c><![CDATA[max]]></c> | <c><![CDATA[min]]></c> | + <c><![CDATA[node]]></c> | <c><![CDATA[round]]></c> | <c><![CDATA[size]]></c> | <c><![CDATA[bit_size]]></c> | <c><![CDATA[byte_size]]></c> | <c><![CDATA[tl]]></c> | <c><![CDATA[trunc]]></c> | @@ -275,7 +279,9 @@ <c><![CDATA['xor']]></c> returns false.</p> </item> <tag><c>abs</c>, <c>element</c>, <c>hd</c>, <c>length</c>, - <c>map_get</c>, <c>map_size</c>, <c>node</c>, <c>round</c>, + <c>map_get</c>, <c>map_size</c>, + <c>max</c>, <c>min</c>, + <c>node</c>, <c>round</c>, <c>size</c>, <c>bit_size</c>, <c>byte_size</c>, <c>tl</c>, <c>trunc</c>, <c>binary_part</c>, <c>'+'</c>, <c>'-'</c>, <c>'*'</c>, <c>'div'</c>, <c>'rem'</c>, <c>'band'</c>, diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 455992e0e9..e1ca5a961b 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -778,3 +778,9 @@ bif erlang:unalias/1 # New in 24 (in a patch) bif erts_internal:binary_to_integer/2 bif erts_internal:list_to_integer/2 + +# +# New in 26 +# +ubif erlang:min/2 +ubif erlang:max/2 diff --git a/erts/emulator/beam/erl_bif_guard.c b/erts/emulator/beam/erl_bif_guard.c index 2242570cad..62a48a45ff 100644 --- a/erts/emulator/beam/erl_bif_guard.c +++ b/erts/emulator/beam/erl_bif_guard.c @@ -462,3 +462,13 @@ BIF_RETTYPE binary_part_2(BIF_ALIST_2) badarg: BIF_ERROR(BIF_P,BADARG); } + +BIF_RETTYPE min_2(BIF_ALIST_2) +{ + return CMP_GT(BIF_ARG_1, BIF_ARG_2) ? BIF_ARG_2 : BIF_ARG_1; +} + +BIF_RETTYPE max_2(BIF_ALIST_2) +{ + return CMP_LT(BIF_ARG_1, BIF_ARG_2) ? BIF_ARG_2 : BIF_ARG_1; +} diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index 8243ac1a73..e05c552c0e 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -629,6 +629,18 @@ static DMCGuardBif guard_tab[] = 1, DBIF_ALL }, + { + am_max, + &max_2, + 2, + DBIF_ALL + }, + { + am_min, + &min_2, + 2, + DBIF_ALL + }, { am_node, &node_1, diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl index 69e911e796..32bf961fab 100644 --- a/erts/emulator/test/bif_SUITE.erl +++ b/erts/emulator/test/bif_SUITE.erl @@ -356,6 +356,11 @@ auto_imports([], Errors) -> extract_functions(M, Abstr) -> [{{M,F,A},Body} || {function,_,F,A,Body} <- Abstr]. +check_stub({_,F,2}, _B) when F =:= min; F =:= max -> + %% In Erlang/OTP 26, min/2 and max/2 are guard BIFs. For backward + %% compatibility with code compiled with an earlier version, the + %% Erlang implementation of them is kept. + ok; check_stub({_,F,A}, B) -> try [{clause,_,Args,[],Body}] = B, @@ -724,19 +729,7 @@ fail_atom_to_binary(Term) -> end. -min_max(Config) when is_list(Config) -> - a = erlang:min(id(a), a), - a = erlang:min(id(a), b), - a = erlang:min(id(b), a), - b = erlang:min(id(b), b), - a = erlang:max(id(a), a), - b = erlang:max(id(a), b), - b = erlang:max(id(b), a), - b = erlang:max(id(b), b), - - 42.0 = erlang:min(42.0, 42), - 42.0 = erlang:max(42.0, 42), - %% And now (R14) they are also autoimported! +min_max(Config) when is_list(Config) -> a = min(id(a), a), a = min(id(a), b), a = min(id(b), a), @@ -746,10 +739,17 @@ min_max(Config) when is_list(Config) -> b = max(id(b), a), b = max(id(b), b), - 42.0 = min(42.0, 42), - 42.0 = max(42.0, 42), - ok. + %% Return the first argument when arguments are equal. + 42.0 = min(id(42.0), 42), + 42.0 = max(id(42.0), 42), + Min = id(min), + Max = id(max), + + "abc" = erlang:Min("abc", "def"), + <<"def">> = erlang:Max(<<"abc">>, <<"def">>), + + ok. erlang_halt(Config) when is_list(Config) -> diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 2703e865cd..b650eb70aa 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -4043,6 +4043,8 @@ rvrs([X|Xs],Ys) -> rvrs(Xs, [X|Ys]). Term1 :: term(), Term2 :: term(), Minimum :: term(). +%% In Erlang/OTP 26, min/2 is a guard BIF. This implementation is kept +%% for backward compatibility with code compiled with an earlier version. min(A, B) when A > B -> B; min(A, _) -> A. @@ -4051,6 +4053,8 @@ min(A, _) -> A. Term1 :: term(), Term2 :: term(), Maximum :: term(). +%% In Erlang/OTP 26, max/2 is a guard BIF. This implementation is kept +%% for backward compatibility with code compiled with an earlier version. max(A, B) when A < B -> B; max(A, _) -> A. diff --git a/lib/compiler/src/beam_ssa_codegen.erl b/lib/compiler/src/beam_ssa_codegen.erl index 869490e710..93b707c476 100644 --- a/lib/compiler/src/beam_ssa_codegen.erl +++ b/lib/compiler/src/beam_ssa_codegen.erl @@ -2397,6 +2397,8 @@ local_func_label(Key, #cg{functable=Map}=St0) -> is_gc_bif(hd, [_]) -> false; is_gc_bif(tl, [_]) -> false; is_gc_bif(self, []) -> false; +is_gc_bif(max, [_,_]) -> false; +is_gc_bif(min, [_,_]) -> false; is_gc_bif(node, []) -> false; is_gc_bif(node, [_]) -> false; is_gc_bif(element, [_,_]) -> false; diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl index 70b2b56d68..4074f12cd4 100644 --- a/lib/compiler/src/v3_kernel.erl +++ b/lib/compiler/src/v3_kernel.erl @@ -119,6 +119,7 @@ copy_anno(Kdst, Ksrc) -> free=#{}, %Free variables ws=[] :: [warning()], %Warnings. no_shared_fun_wrappers=false :: boolean(), + no_min_max_bifs=false :: boolean(), labels=sets:new([{version, 2}]) }). @@ -130,7 +131,9 @@ module(#c_module{anno=A,name=M,exports=Es,attrs=As,defs=Fs}, Options) -> Kes = map(fun (#c_var{name={_,_}=Fname}) -> Fname end, Es), NoSharedFunWrappers = proplists:get_bool(no_shared_fun_wrappers, Options), - St0 = #kern{no_shared_fun_wrappers=NoSharedFunWrappers}, + NoMinMaxBifs = proplists:get_bool(no_min_max_bifs, Options), + St0 = #kern{no_shared_fun_wrappers=NoSharedFunWrappers, + no_min_max_bifs=NoMinMaxBifs}, {Kfs,St} = mapfoldl(fun function/2, St0, Fs), {ok,#k_mdef{anno=A,name=M#c_literal.val,exports=Kes,attributes=Kas, body=Kfs ++ St#kern.funs},sort(St#kern.ws)}. @@ -323,7 +326,7 @@ expr(#c_call{anno=A,module=M0,name=F0,args=Cargs}, Sub, St0) -> Ar = length(Cargs), {[M,F|Kargs],Ap,St1} = atomic_list([M0,F0|Cargs], Sub, St0), Remote = #k_remote{mod=M,name=F,arity=Ar}, - case call_type(M0, F0, Cargs) of + case call_type(M0, F0, Cargs, St1) of bif -> {#k_bif{anno=A,op=Remote,args=Kargs},Ap,St1}; call -> @@ -543,15 +546,24 @@ map_key_clean(#k_literal{val=V}) -> {lit,V}. %% call_type(Module, Function, Arity) -> call | bif | error. %% Classify the call. -call_type(#c_literal{val=M}, #c_literal{val=F}, As) when is_atom(M), is_atom(F) -> +call_type(#c_literal{val=M}, #c_literal{val=F}, As, St) when is_atom(M), is_atom(F) -> case is_remote_bif(M, F, As) of - false -> call; - true -> bif + false -> + call; + true -> + %% The guard BIFs min/2 and max/2 were introduced in + %% Erlang/OTP 26. If we are compiling for an earlier + %% version, we must translate them as call instructions. + case {M,F,St#kern.no_min_max_bifs} of + {erlang,min,true} -> call; + {erlang,max,true} -> call; + {_,_,_} -> bif + end end; -call_type(#c_var{}, #c_literal{val=A}, _) when is_atom(A) -> call; -call_type(#c_literal{val=A}, #c_var{}, _) when is_atom(A) -> call; -call_type(#c_var{}, #c_var{}, _) -> call; -call_type(_, _, _) -> error. +call_type(#c_var{}, #c_literal{val=A}, _, _) when is_atom(A) -> call; +call_type(#c_literal{val=A}, #c_var{}, _, _) when is_atom(A) -> call; +call_type(#c_var{}, #c_var{}, _, _) -> call; +call_type(_, _, _, _) -> error. %% match_vars(Kexpr, State) -> {[Kvar],[PreKexpr],State}. %% Force return from body into a list of variables. diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl index 92651084c7..8453c1e7b7 100644 --- a/lib/stdlib/src/erl_internal.erl +++ b/lib/stdlib/src/erl_internal.erl @@ -78,6 +78,8 @@ guard_bif(is_map_key, 2) -> true; guard_bif(length, 1) -> true; guard_bif(map_size, 1) -> true; guard_bif(map_get, 2) -> true; +guard_bif(max, 2) -> true; +guard_bif(min, 2) -> true; guard_bif(node, 0) -> true; guard_bif(node, 1) -> true; guard_bif(round, 1) -> true; diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl index dde8e572a3..ba3a5c42bf 100644 --- a/lib/stdlib/src/ms_transform.erl +++ b/lib/stdlib/src/ms_transform.erl @@ -977,6 +977,8 @@ real_guard_function(abs,1) -> true; real_guard_function(element,2) -> true; real_guard_function(hd,1) -> true; real_guard_function(length,1) -> true; +real_guard_function(max,2) -> true; +real_guard_function(min,2) -> true; real_guard_function(node,0) -> true; real_guard_function(node,1) -> true; real_guard_function(round,1) -> true; diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl index c34c7e9e69..2a7b003809 100644 --- a/lib/stdlib/test/ms_transform_SUITE.erl +++ b/lib/stdlib/test/ms_transform_SUITE.erl @@ -582,6 +582,8 @@ autoimported(Config) when is_list(Config) -> {element,2}, {hd,1}, {length,1}, + {max,2}, + {min,2}, {node,0}, {node,1}, {round,1}, diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml index 341fa32432..3ad0616dd2 100644 --- a/system/doc/reference_manual/expressions.xml +++ b/system/doc/reference_manual/expressions.xml @@ -2022,6 +2022,12 @@ end</pre> <row> <cell align="left" valign="middle"><c>map_size(Map)</c></cell> </row> + <row> + <cell align="left" valign="middle"><c>max(A, B)</c></cell> + </row> + <row> + <cell align="left" valign="middle"><c>min(A, B)</c></cell> + </row> <row> <cell align="left" valign="middle"><c>node()</c></cell> </row> @@ -2049,6 +2055,9 @@ end</pre> <tcaption>Other BIFs Allowed in Guard Expressions</tcaption> </table> + <change><p>The <c>min/2</c> and <c>max/2</c> BIFs are allowed to be + used in guards from Erlang/OTP 26.</p></change> + <p>If an arithmetic expression, a Boolean expression, a short-circuit expression, or a call to a guard BIF fails (because of invalid arguments), the entire guard fails. If the guard was -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor