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