1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2000-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(fun_SUITE).
21
22-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
23	 init_per_group/2,end_per_group/2,
24	 test1/1,overwritten_fun/1,otp_7202/1,bif_fun/1,
25         external/1,eep37/1,eep37_dup/1,badarity/1,badfun/1,
26         duplicated_fun/1,unused_fun/1,coverage/1]).
27
28%% Internal exports.
29-export([call_me/1,dup1/0,dup2/0]).
30
31-include_lib("common_test/include/ct.hrl").
32
33suite() -> [{ct_hooks,[ts_install_cth]}].
34
35all() ->
36    [{group,p}].
37
38groups() ->
39    [{p,[parallel],
40      [test1,overwritten_fun,otp_7202,bif_fun,external,eep37,
41       eep37_dup,badarity,badfun,duplicated_fun,unused_fun,
42       coverage]}].
43
44init_per_suite(Config) ->
45    test_lib:recompile(?MODULE),
46    Config.
47
48end_per_suite(_Config) ->
49    ok.
50
51init_per_group(_GroupName, Config) ->
52    Config.
53
54end_per_group(_GroupName, Config) ->
55    Config.
56
57%%% The help functions below are copied from emulator:bs_construct_SUITE.
58
59-define(T(B, L), {fun() -> B end(), ??B, L}).
60
61l1() ->
62    [
63     ?T((begin A = 3, F = fun(A) -> 1; (_) -> 2 end, F(2) end), 1),
64     ?T((begin G = fun(1=0) -> ok end, {'EXIT',_} = (catch G(2)), ok end), ok),
65     ?T((begin F = fun(_, 1) -> 1; (F, N) -> N * F(F, N-1) end, F(F, 5) end), 120),
66     ?T((begin F = fun(_, 1) -> 1; (F, N) -> N * F(F, N-1) end, F(F, 1), ok end), ok)
67    ].
68
69test1(Config) when is_list(Config) ->
70    lists:foreach(fun one_test/1, eval_list(l1(), [])),
71    ok.
72
73evaluate(Str, Vars) ->
74    {ok,Tokens,_} =
75	erl_scan:string(Str ++ " . "),
76    {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
77    case erl_eval:expr(Expr, Vars) of
78	{value, Result, _} ->
79	    Result
80    end.
81
82eval_list([], _Vars) ->
83    [];
84eval_list([{C_bin, Str, Bytes} | Rest], Vars) ->
85    case catch evaluate(Str, Vars) of
86	{'EXIT', Error} ->
87	    io:format("Evaluation error: ~p, ~p, ~p~n", [Str, Vars, Error]),
88	    exit(Error);
89	E_bin ->
90	    [{C_bin, E_bin, Str, Bytes} | eval_list(Rest, Vars)]
91    end.
92
93one_test({C, E, Str, Correct}) ->
94    io:format("  ~s, ~p~n", [Str, Correct]),
95    if
96	C == Correct ->
97	    ok;
98	true ->
99	    io:format("ERROR: Compiled: ~p. Expected ~p. Got ~p.~n",
100		      [Str, Correct, C]),
101	    ct:fail(comp)
102    end,
103    if
104	E == Correct ->
105	    ok;
106	true ->
107	    io:format("ERROR: Interpreted: ~p. Expected ~p. Got ~p.~n",
108		      [Str, Correct, E]),
109	    ct:fail(comp)
110    end.
111
112-record(b, {c}).
113
114%% OTP-7102. (Thanks to Simon Cornish.)
115
116overwritten_fun(Config) when is_list(Config) ->
117    {a2,a} = overwritten_fun_1(a),
118    {a2,{b,c}} = overwritten_fun_1(#b{c=c}),
119    one = overwritten_fun_1(#b{c=[]}),
120    ok.
121
122overwritten_fun_1(A) ->
123    F = fun() ->
124		{ok, A}
125	end,
126    if A#b.c == [] ->
127	    one;
128       true ->
129	    case F() of
130		{ok, A2} ->
131		    {a2, A2};
132		_ ->
133		    three
134	    end
135    end.
136
137%% OTP-7202. The liveness calculation for the make_fun2 instruction was wrong.
138
139otp_7202(Config) when is_list(Config) ->
140    otp_7202().
141
142otp_7202() ->
143    List = [a],
144    Error = case otp_7202_func() of
145                no_value -> true;
146                {ok, V} -> V
147             end,
148    lists:foreach(fun(_E) ->
149                          case Error of
150                              true ->
151                                  ok;
152                              false ->
153                                  ok
154                          end
155                  end, List).
156
157otp_7202_func() ->
158    no_value.
159
160bif_fun(Config) when is_list(Config) ->
161    F = fun abs/1,
162    5 = F(-5),
163    ok.
164
165-define(APPLY(M, F, A), (fun(Fun) -> {ok,{a,b}} = Fun({a,b}) end)(fun M:F/A)).
166-define(APPLY2(M, F, A),
167	(fun(Map) ->
168		 Id = fun(I) -> I end,
169		 List = [x,y],
170		 List = Map(Id, List),
171		 {type,external} = erlang:fun_info(Map, type)
172	 end)(fun M:F/A)).
173
174external(Config) when is_list(Config) ->
175    Mod = id(?MODULE),
176    Func = id(call_me),
177    Arity = id(1),
178
179    ?APPLY(?MODULE, call_me, 1),
180    ?APPLY(?MODULE, call_me, Arity),
181    ?APPLY(?MODULE, Func, 1),
182    ?APPLY(?MODULE, Func, Arity),
183    ?APPLY(Mod, call_me, 1),
184    ?APPLY(Mod, call_me, Arity),
185    ?APPLY(Mod, Func, 1),
186    ?APPLY(Mod, Func, Arity),
187
188    ListsMod = id(lists),
189    ListsMap = id(map),
190    ListsArity = id(2),
191
192    ?APPLY2(lists, map, 2),
193    ?APPLY2(lists, map, ListsArity),
194    ?APPLY2(lists, ListsMap, 2),
195    ?APPLY2(lists, ListsMap, ListsArity),
196    ?APPLY2(ListsMod, map, 2),
197    ?APPLY2(ListsMod, map, ListsArity),
198    ?APPLY2(ListsMod, ListsMap, 2),
199    ?APPLY2(ListsMod, ListsMap, ListsArity),
200
201    42 = (fun erlang:abs/1)(-42),
202    42 = (id(fun erlang:abs/1))(-42),
203    42 = apply(fun erlang:abs/1, [-42]),
204    42 = apply(id(fun erlang:abs/1), [-42]),
205    6 = (fun lists:sum/1)([1,2,3]),
206    6 = (id(fun lists:sum/1))([1,2,3]),
207
208    {'EXIT',{{badarity,_},_}} = (catch (fun lists:sum/1)(1, 2, 3)),
209    {'EXIT',{{badarity,_},_}} = (catch (id(fun lists:sum/1))(1, 2, 3)),
210    {'EXIT',{{badarity,_},_}} = (catch apply(fun lists:sum/1, [1,2,3])),
211
212    {'EXIT',{badarg,_}} = (catch bad_external_fun()),
213
214    ok.
215
216call_me(I) ->
217    {ok,I}.
218
219bad_external_fun() ->
220    V0 = idea,
221    fun V0:V0/V0,                               %Should fail.
222    never_reached.
223
224eep37(Config) when is_list(Config) ->
225    F = fun Fact(N) when N > 0 -> N * Fact(N - 1); Fact(0) -> 1 end,
226    Add = fun _(N) -> N + 1 end,
227    UnusedName = fun BlackAdder(N) -> N + 42 end,
228    720 = F(6),
229    10 = Add(9),
230    50 = UnusedName(8),
231    ok.
232
233eep37_dup(Config) when is_list(Config) ->
234    dup1 = (dup1())(),
235    dup2 = (dup2())(),
236    ok.
237
238dup1() ->
239    fun _F() -> dup1 end.
240
241dup2() ->
242    fun _F() -> dup2 end.
243
244badarity(Config) when is_list(Config) ->
245    {'EXIT',{{badarity,{_,[]}},_}} = (catch (fun badarity/1)()),
246    {'EXIT',{{badarity,_},_}} = (catch fun() -> 42 end(0)),
247    ok.
248
249badfun(_Config) ->
250    X = not_a_fun,
251    expect_badfun(42, catch 42()),
252    expect_badfun(42.0, catch 42.0(1)),
253    expect_badfun(X, catch X()),
254    expect_badfun(X, catch X(1)),
255    Len = length(atom_to_list(X)),
256    expect_badfun(Len, catch begin length(atom_to_list(X)) end(1)),
257
258    expect_badfun(42, catch 42(put(?FUNCTION_NAME, yes))),
259    yes = erase(?FUNCTION_NAME),
260
261    expect_badfun(X, catch X(put(?FUNCTION_NAME, of_course))),
262    of_course = erase(?FUNCTION_NAME),
263
264    %% A literal as a Fun used to crash the code generator. This only happened
265    %% when type optimization had reduced `Fun` to a literal, hence the match.
266    Literal = fun(literal = Fun) ->
267                      Fun()
268              end,
269    expect_badfun(literal, catch Literal(literal)),
270
271    ok.
272
273expect_badfun(Term, Exit) ->
274    {'EXIT',{{badfun,Term},_}} = Exit.
275
276duplicated_fun(_Config) ->
277    try
278        %% The following code used to crash the compiler before
279        %% v3_core:is_safe/1 was corrected to consider fun variables
280        %% unsafe.
281        id([print_result_paths_fun = fun duplicated_fun_helper/1]),
282        ct:error(should_fail)
283    catch
284        error:{badmatch,F} when is_function(F, 1) ->
285            ok
286    end.
287
288duplicated_fun_helper(_) ->
289    ok.
290
291%% ERL-1166: beam_kernel_to_ssa would crash if a fun was unused.
292unused_fun(_Config) ->
293    _ = fun() -> ok end,
294    try id(ok) of
295        _ -> fun() -> ok end
296    catch _ -> ok end,
297    ok.
298
299coverage(_Config) ->
300    ok = coverage_1(),
301    ok.
302
303coverage_1() ->
304    %% Cover a line in beam_ssa_pre_codegen:need_frame_1/2 when the
305    %% no_make_fun3 option is given.
306    catch
307        fun(whatever) -> 0;
308           ("abc") -> party
309        end,
310        ok.
311
312
313id(I) ->
314    I.
315