diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index 0989f43ed9c7..560c56136c8e 100644 --- a/lib/stdlib/src/erl_eval.erl +++ b/lib/stdlib/src/erl_eval.erl @@ -489,9 +489,24 @@ expr({'fun',_Anno,{function,Mod0,Name0,Arity0}}, Bs0, Lf, Ef, RBs, FUVs) -> {[Mod,Name,Arity],Bs} = expr_list([Mod0,Name0,Arity0], Bs0, Lf, Ef, FUVs), F = erlang:make_fun(Mod, Name, Arity), ret_expr(F, Bs, RBs); -expr({'fun',Anno,{function,Name,Arity}}, Bs0, _Lf, Ef, RBs, _FUVs) -> % R8 - %% Don't know what to do... - apply_error(undef, [{?MODULE,Name,Arity}|?STACKTRACE], Anno, Bs0, Ef, RBs); +expr({'fun',Anno,{function,Name,Arity}}, Bs0, Lf, Ef, RBs, FUVs) -> % R8 + case erl_internal:bif(Name, Arity) of + true -> + %% Auto-imported BIF. Create an external fun. + ret_expr(fun erlang:Name/Arity, Bs0, RBs); + false -> + %% A local function assumed to be defined in the shell. + %% Create a wrapper fun that will call the local fun. + %% Calling the fun will succeed if the local fun is + %% defined when the call is made. + Args = [{var,Anno,list_to_atom("@arg" ++ [V])} || + V <- lists:seq($a, $a+Arity-1)], + H = Args, + G = [{atom,Anno,true}], + B = [{call,Anno,{atom,Anno,Name},Args}], + Cs = [{clause,Anno,H,G,B}], + expr({'fun',Anno,{clauses,Cs}}, Bs0, Lf, Ef, RBs, FUVs) + end; expr({'fun',Anno,{clauses,Cs}} = Ex, Bs, Lf, Ef, RBs, FUVs) -> {En,NewFUVs} = fun_used_bindings(Ex, Cs, Bs, FUVs), Info = {Anno,En,Lf,Ef,NewFUVs,Cs}, diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index e28dd788bb9b..3cecbda63507 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -68,6 +68,7 @@ -export([count_down/2, count_down_fun/0, do_apply/2, local_func/3, local_func_value/2]). -export([simple/0]). +-export([my_div/2]). -ifdef(STANDALONE). -define(config(A,B),config(A,B)). @@ -1217,8 +1218,6 @@ custom_stacktrace(Config) when is_list(Config) -> backtrace_check("#unknown.index.", {undef_record,unknown}, [erl_eval, mystack(1)], none, EFH), - backtrace_check("fun foo/2.", undef, - [{erl_eval, foo, 2}, erl_eval, mystack(1)], none, EFH), backtrace_check("foo(1, 2).", undef, [{erl_eval, foo, 2}, erl_eval, mystack(1)], none, EFH), @@ -1369,7 +1368,6 @@ funs(Config) when is_list(Config) -> error_check("begin F = fun(T) -> timer:sleep(T) end,F(1) end.", got_it, none, AnnEFH), - error_check("fun c/1.", undef), error_check("fun a:b/0().", undef), MaxArgs = 20, @@ -1387,8 +1385,36 @@ funs(Config) when is_list(Config) -> %% Test that {M,F} is not accepted as a fun. error_check("{" ?MODULE_STRING ",module_info}().", {badfun,{?MODULE,module_info}}), + + %% Test defining and calling a fun based on an auto-imported BIF. + check(fun() -> + F = fun is_binary/1, + true = F(<<>>), + false = F(a) + end, + ~S""" + F = fun is_binary/1, + true = F(<<>>), + false = F(a). + """, + false, ['F'], lfh(), none), + + %% Test defining and calling a local fun defined in the shell. + check(fun() -> + D = fun my_div/2, + 3 = D(15, 5) + end, + ~S""" + D = fun my_div/2, + 3 = D(15, 5). + """, + 3, ['D'], lfh(), efh()), + ok. +my_div(A, B) -> + A div B. + run_many_args({S, As}) -> apply(eval_string(S), As) =:= As.