diff options
Diffstat (limited to 'lib/compiler/test/trycatch_SUITE.erl')
-rw-r--r-- | lib/compiler/test/trycatch_SUITE.erl | 911 |
1 files changed, 911 insertions, 0 deletions
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl new file mode 100644 index 0000000000..c2f6dc24be --- /dev/null +++ b/lib/compiler/test/trycatch_SUITE.erl @@ -0,0 +1,911 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(trycatch_SUITE). + +-export([all/1,basic/1,lean_throw/1,try_of/1,try_after/1,%after_bind/1, + catch_oops/1,after_oops/1,eclectic/1,rethrow/1, + nested_of/1,nested_catch/1,nested_after/1, + nested_horrid/1,last_call_optimization/1,bool/1, + plain_catch_coverage/1,andalso_orelse/1]). + +-include("test_server.hrl"). + +all(suite) -> + test_lib:recompile(?MODULE), + [basic,lean_throw,try_of,try_after,%after_bind, + catch_oops,after_oops,eclectic,rethrow, + nested_of,nested_catch,nested_after, + nested_horrid,last_call_optimization, + bool,plain_catch_coverage,andalso_orelse]. + + +basic(Conf) when is_list(Conf) -> + ?line 2 = + try my_div(4, 2) + catch + Class:Reason -> {Class,Reason} + end, + ?line error = + try my_div(1, 0) + catch + error:badarith -> error + end, + ?line error = + try 1.0 / zero() + catch + error:badarith -> error + end, + ?line ok = + try my_add(53, atom) + catch + error:badarith -> ok + end, + ?line exit_nisse = + try exit(nisse) + catch + exit:nisse -> exit_nisse + end, + ?line ok = + try throw(kalle) + catch + kalle -> ok + end, + + %% Try some stuff where the compiler will optimize away the try. + + V = id({a,variable}), + ?line V = try V catch nisse -> error end, + ?line 42 = try 42 catch nisse -> error end, + ?line [V] = try [V] catch nisse -> error end, + ?line {ok,V} = try {ok,V} catch nisse -> error end, + + %% Same idea, but use an after too. + + ?line V = try V catch nisse -> error after after_call() end, + ?line after_clean(), + ?line 42 = try 42 after after_call() end, + ?line after_clean(), + ?line [V] = try [V] catch nisse -> error after after_call() end, + ?line after_clean(), + ?line {ok,V} = try {ok,V} after after_call() end, + + %% Try/of + ?line ok = try V of + {a,variable} -> ok + catch nisse -> erro + end, + + ok. + +after_call() -> + put(basic, after_was_called). + +after_clean() -> + after_was_called = erase(basic). + + +lean_throw(Conf) when is_list(Conf) -> + ?line {throw,kalle} = + try throw(kalle) + catch + Kalle -> {throw,Kalle} + end, + ?line {exit,kalle} = + try exit(kalle) + catch + Throw1 -> {throw,Throw1}; + exit:Reason1 -> {exit,Reason1} + end, + ?line {exit,kalle} = + try exit(kalle) + catch + exit:Reason2 -> {exit,Reason2}; + Throw2 -> {throw,Throw2} + end, + ?line {exit,kalle} = + try try exit(kalle) + catch + Throw3 -> {throw,Throw3} + end + catch + exit:Reason3 -> {exit,Reason3} + end, + ok. + + + +try_of(Conf) when is_list(Conf) -> + ?line {ok,{some,content}} = + try_of_1({value,{good,{some,content}}}), + ?line {error,[other,content]} = + try_of_1({value,{bad,[other,content]}}), + ?line {caught,{exit,{ex,it,[reason]}}} = + try_of_1({exit,{ex,it,[reason]}}), + ?line {caught,{throw,[term,{in,a,{tuple}}]}} = + try_of_1({throw,[term,{in,a,{tuple}}]}), + ?line {caught,{error,[bad,arg]}} = + try_of_1({error,[bad,arg]}), + ?line {caught,{error,badarith}} = + try_of_1({'div',{1,0}}), + ?line {caught,{error,badarith}} = + try_of_1({'add',{a,0}}), + ?line {caught,{error,badarg}} = + try_of_1({'abs',x}), + ?line {caught,{error,function_clause}} = + try_of_1(illegal), + ?line {error,{try_clause,{some,other_garbage}}} = + try try_of_1({value,{some,other_garbage}}) + catch error:Reason -> {error,Reason} + end, + ok. + +try_of_1(X) -> + try foo(X) of + {good,Y} -> {ok,Y}; + {bad,Y} -> {error,Y} + catch + Class:Reason -> + {caught,{Class,Reason}} + end. + + + +try_after(Conf) when is_list(Conf) -> + ?line {{ok,[some,value],undefined},finalized} = + try_after_1({value,{ok,[some,value]}},finalized), + ?line {{error,badarith,undefined},finalized} = + try_after_1({'div',{1,0}},finalized), + ?line {{error,badarith,undefined},finalized} = + try_after_1({'add',{1,a}},finalized), + ?line {{error,badarg,undefined},finalized} = + try_after_1({'abs',a},finalized), + ?line {{error,[the,{reason}],undefined},finalized} = + try_after_1({error,[the,{reason}]},finalized), + ?line {{throw,{thrown,[reason]},undefined},finalized} = + try_after_1({throw,{thrown,[reason]}},finalized), + ?line {{exit,{exited,{reason}},undefined},finalized} = + try_after_1({exit,{exited,{reason}}},finalized), + ?line {{error,function_clause,undefined},finalized} = + try_after_1(function_clause,finalized), + ?line ok = + try try_after_1({'add',{1,1}}, finalized) + catch + error:{try_clause,2} -> ok + end, + ?line finalized = erase(try_after), + ?line ok = + try try foo({exit,[reaso,{n}]}) + after put(try_after, finalized) + end + catch + exit:[reaso,{n}] -> ok + end, + ok. + +try_after_1(X, Y) -> + erase(try_after), + Try = + try foo(X) of + {ok,Value} -> {ok,Value,get(try_after)} + catch + Reason -> {throw,Reason,get(try_after)}; + error:Reason -> {error,Reason,get(try_after)}; + exit:Reason -> {exit,Reason,get(try_after)} + after + put(try_after, Y) + end, + {Try,erase(try_after)}. + + + +-ifdef(begone). + +after_bind(Conf) when is_list(Conf) -> + V = [make_ref(),self()|value], + ?line {value,{value,V}} = + after_bind_1({value,V}, V, {value,V}), + ok. + +after_bind_1(X, V, Y) -> + try + Try = + try foo(X) of + V -> value + catch + C1:V -> {caught,C1} + after + After = foo(Y) + end, + {Try,After} + of + V -> {value,V} + catch + C:D -> {caught,{C,D}} + end. + +-endif. + + + +catch_oops(Conf) when is_list(Conf) -> + V = {v,[a,l|u],{e},self()}, + ?line {value,V} = catch_oops_1({value,V}), + ?line {value,1} = catch_oops_1({'div',{1,1}}), + ?line {error,badarith} = catch_oops_1({'div',{1,0}}), + ?line {error,function_clause} = catch_oops_1(function_clause), + ?line {throw,V} = catch_oops_1({throw,V}), + ?line {exit,V} = catch_oops_1({exit,V}), + ok. + +catch_oops_1(X) -> + Ref = make_ref(), + try try foo({error,Ref}) + catch + error:Ref -> + foo(X) + end of + Value -> {value,Value} + catch + Class:Data -> {Class,Data} + end. + + + +after_oops(Conf) when is_list(Conf) -> + V = {self(),make_ref()}, + ?line {{value,V},V} = after_oops_1({value,V}, {value,V}), + ?line {{exit,V},V} = after_oops_1({exit,V}, {value,V}), + ?line {{error,V},undefined} = after_oops_1({value,V}, {error,V}), + ?line {{error,function_clause},undefined} = + after_oops_1({exit,V}, function_clause), + ok. + +after_oops_1(X, Y) -> + erase(after_oops), + Try = + try try foo(X) + after + put(after_oops, foo(Y)) + end of + V -> {value,V} + catch + C:D -> {C,D} + end, + {Try,erase(after_oops)}. + + + +eclectic(Conf) when is_list(Conf) -> + V = {make_ref(),3.1415926535,[[]|{}]}, + ?line {{value,{value,V},V},V} = + eclectic_1({foo,{value,{value,V}}}, undefined, {value,V}), + ?line {{'EXIT',{V,[{?MODULE,foo,1}|_]}},V} = + eclectic_1({catch_foo,{error,V}}, undefined, {value,V}), + ?line {{error,{exit,V},{'EXIT',V}},V} = + eclectic_1({foo,{error,{exit,V}}}, error, {value,V}), + ?line {{value,{value,V},V}, + {'EXIT',{badarith,[{?MODULE,my_add,2}|_]}}} = + eclectic_1({foo,{value,{value,V}}}, undefined, {'add',{0,a}}), + ?line {{'EXIT',V},V} = + eclectic_1({catch_foo,{exit,V}}, undefined, {throw,V}), + ?line {{error,{'div',{1,0}},{'EXIT',{badarith,[{?MODULE,my_div,2}|_]}}}, + {'EXIT',V}} = + eclectic_1({foo,{error,{'div',{1,0}}}}, error, {exit,V}), + ?line {{{error,V},{'EXIT',{V,[{?MODULE,foo,1}|_]}}}, + {'EXIT',V}} = + eclectic_1({catch_foo,{throw,{error,V}}}, undefined, {exit,V}), + %% + ?line {{value,{value,{value,V},V}},V} = + eclectic_2({value,{value,V}}, undefined, {value,V}), + ?line {{value,{throw,{value,V},V}},V} = + eclectic_2({throw,{value,V}}, throw, {value,V}), + ?line {{caught,{'EXIT',V}},undefined} = + eclectic_2({value,{value,V}}, undefined, {exit,V}), + ?line {{caught,{'EXIT',{V,[{?MODULE,foo,1}|_]}}},undefined} = + eclectic_2({error,{value,V}}, throw, {error,V}), + ?line {{caught,{'EXIT',{badarg,[{erlang,abs,[V]}|_]}}},V} = + eclectic_2({value,{'abs',V}}, undefined, {value,V}), + ?line {{caught,{'EXIT',{badarith,[{?MODULE,my_add,2}|_]}}},V} = + eclectic_2({exit,{'add',{0,a}}}, exit, {value,V}), + ?line {{caught,{'EXIT',V}},undefined} = + eclectic_2({value,{error,V}}, undefined, {exit,V}), + ?line {{caught,{'EXIT',{V,[{?MODULE,foo,1}|_]}}},undefined} = + eclectic_2({throw,{'div',{1,0}}}, throw, {error,V}), + ok. + +eclectic_1(X, C, Y) -> + erase(eclectic), + Done = make_ref(), + Try = + try case X of + {catch_foo,V} -> catch {Done,foo(V)}; + {foo,V} -> {Done,foo(V)} + end of + {Done,D} -> {value,D,catch foo(D)}; + {'EXIT',_}=Exit -> Exit; + D -> {D,catch foo(D)} + catch + C:D -> {C,D,catch foo(D)} + after + put(eclectic, catch foo(Y)) + end, + {Try,erase(eclectic)}. + +eclectic_2(X, C, Y) -> + Done = make_ref(), + erase(eclectic), + Catch = + case + catch + {Done, + try foo(X) of + V -> {value,V,foo(V)} + catch + C:D -> {C,D,foo(D)} + after + put(eclectic, foo(Y)) + end} of + {Done,Z} -> {value,Z}; + Z -> {caught,Z} + end, + {Catch,erase(eclectic)}. + + + +rethrow(Conf) when is_list(Conf) -> + V = {a,[b,{c,self()},make_ref]}, + ?line {value2,value1} = + rethrow_1({value,V}, V), + ?line {caught2,{error,V}} = + rethrow_2({error,V}, undefined), + ?line {caught2,{exit,V}} = + rethrow_1({exit,V}, error), + ?line {caught2,{throw,V}} = + rethrow_1({throw,V}, undefined), + ?line {caught2,{throw,V}} = + rethrow_2({throw,V}, undefined), + ?line {caught2,{error,badarith}} = + rethrow_1({'add',{0,a}}, throw), + ?line {caught2,{error,function_clause}} = + rethrow_2(function_clause, undefined), + ?line {caught2,{error,{try_clause,V}}} = + rethrow_1({value,V}, exit), + ?line {value2,{caught1,V}} = + rethrow_1({error,V}, error), + ?line {value2,{caught1,V}} = + rethrow_1({exit,V}, exit), + ?line {value2,caught1} = + rethrow_2({throw,V}, V), + ok. + +rethrow_1(X, C1) -> + try try foo(X) of + C1 -> value1 + catch + C1:D1 -> {caught1,D1} + end of + V2 -> {value2,V2} + catch + C2:D2 -> {caught2,{C2,D2}} + end. + +rethrow_2(X, C1) -> + try try foo(X) of + C1 -> value1 + catch + C1 -> caught1 % Implicit class throw: + end of + V2 -> {value2,V2} + catch + C2:D2 -> {caught2,{C2,D2}} + end. + + + +nested_of(Conf) when is_list(Conf) -> + V = {[self()|make_ref()],1.4142136}, + ?line {{value,{value1,{V,x2}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_of_1({{value,{V,x1}},void,{V,x1}}, + {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{throw,{V,x2}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_of_1({{value,{V,x1}},void,{V,x1}}, + {throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + undefined, + {V,x4}, + finalized} = + nested_of_1({{value,{V,x1}},void,{V,x1}}, + {throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + undefined, + undefined, + finalized} = + nested_of_1({{value,{V,x1}},void,{V,x1}}, + {throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}), + %% + ?line {{caught,{error,{try_clause,{V,x1}}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_of_1({{value,{V,x1}},void,try_clause}, + void, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{exit,{V,x3}}}, + undefined, + {V,x4}, + finalized} = + nested_of_1({{value,{V,x1}},void,try_clause}, + void, {exit,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{throw,{V,x4}}}, + undefined, + undefined, + finalized} = + nested_of_1({{value,{V,x1}},void,try_clause}, + void, {exit,{V,x3}}, {throw,{V,x4}}), + %% + ?line {{value,{caught1,{V,x2}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_of_1({{error,{V,x1}},error,{V,x1}}, + {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + {V,x3}, + {V,x4}, + finalized} = + nested_of_1({{error,{V,x1}},error,{V,x1}}, + {'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + undefined, + {V,x4}, + finalized} = + nested_of_1({{error,{V,x1}},error,{V,x1}}, + {'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}), + ?line {{caught,{error,badarg}}, + undefined, + undefined, + finalized} = + nested_of_1({{error,{V,x1}},error,{V,x1}}, + {'add',{1,c}}, {'div',{17,0}}, {'abs',V}), + %% + ?line {{caught,{error,badarith}}, + {V,x3}, + {V,x4}, + finalized} = + nested_of_1({{'add',{2,c}},rethrow,void}, + void, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarg}}, + undefined, + {V,x4}, + finalized} = + nested_of_1({{'add',{2,c}},rethrow,void}, + void, {'abs',V}, {value,{V,x4}}), + ?line {{caught,{error,function_clause}}, + undefined, + undefined, + finalized} = + nested_of_1({{'add',{2,c}},rethrow,void}, + void, {'abs',V}, function_clause), + ok. + +nested_of_1({X1,C1,V1}, + X2, X3, X4) -> + erase(nested3), + erase(nested4), + erase(nested), + Self = self(), + Try = + try + try self() + of + Self -> + try + foo(X1) + of + V1 -> {value1,foo(X2)} + catch + C1:V1 -> {caught1,foo(X2)} + after + put(nested3, foo(X3)) + end + after + put(nested4, foo(X4)) + end + of + V -> {value,V} + catch + C:D -> {caught,{C,D}} + after + put(nested, finalized) + end, + {Try,erase(nested3),erase(nested4),erase(nested)}. + + + +nested_catch(Conf) when is_list(Conf) -> + V = {[make_ref(),1.4142136,self()]}, + ?line {{value,{value1,{V,x2}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_catch_1({{value,{V,x1}},void,{V,x1}}, + {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{throw,{V,x2}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_catch_1({{value,{V,x1}},void,{V,x1}}, + {throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + undefined, + {V,x4}, + finalized} = + nested_catch_1({{value,{V,x1}},void,{V,x1}}, + {throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + undefined, + undefined, + finalized} = + nested_catch_1({{value,{V,x1}},void,{V,x1}}, + {throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}), + %% + ?line {{caught,{error,{try_clause,{V,x1}}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_catch_1({{value,{V,x1}},void,try_clause}, + void, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{exit,{V,x3}}}, + undefined, + {V,x4}, + finalized} = + nested_catch_1({{value,{V,x1}},void,try_clause}, + void, {exit,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{throw,{V,x4}}}, + undefined, + undefined, + finalized} = + nested_catch_1({{value,{V,x1}},void,try_clause}, + void, {exit,{V,x3}}, {throw,{V,x4}}), + %% + ?line {{value,{caught1,{V,x2}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_catch_1({{error,{V,x1}},error,{V,x1}}, + {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + {V,x3}, + {V,x4}, + finalized} = + nested_catch_1({{error,{V,x1}},error,{V,x1}}, + {'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + undefined, + {V,x4}, + finalized} = + nested_catch_1({{error,{V,x1}},error,{V,x1}}, + {'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}), + ?line {{caught,{error,badarg}}, + undefined, + undefined, + finalized} = + nested_catch_1({{error,{V,x1}},error,{V,x1}}, + {'add',{1,c}}, {'div',{17,0}}, {'abs',V}), + %% + ?line {{caught,{error,badarith}}, + {V,x3}, + {V,x4}, + finalized} = + nested_catch_1({{'add',{2,c}},rethrow,void}, + void, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarg}}, + undefined, + {V,x4}, + finalized} = + nested_catch_1({{'add',{2,c}},rethrow,void}, + void, {'abs',V}, {value,{V,x4}}), + ?line {{caught,{error,function_clause}}, + undefined, + undefined, + finalized} = + nested_catch_1({{'add',{2,c}},rethrow,void}, + void, {'abs',V}, function_clause), + ok. + +nested_catch_1({X1,C1,V1}, + X2, X3, X4) -> + erase(nested3), + erase(nested4), + erase(nested), + Throw = make_ref(), + Try = + try + try throw(Throw) + catch + Throw -> + try + foo(X1) + of + V1 -> {value1,foo(X2)} + catch + C1:V1 -> {caught1,foo(X2)} + after + put(nested3, foo(X3)) + end + after + put(nested4, foo(X4)) + end + of + V -> {value,V} + catch + C:D -> {caught,{C,D}} + after + put(nested, finalized) + end, + {Try,erase(nested3),erase(nested4),erase(nested)}. + + + +nested_after(Conf) when is_list(Conf) -> + V = [{make_ref(),1.4142136,self()}], + ?line {value, + {V,x3}, + {value1,{V,x2}}, + finalized} = + nested_after_1({{value,{V,x1}},void,{V,x1}}, + {value,{V,x2}}, {value,{V,x3}}), + ?line {{caught,{error,{V,x2}}}, + {V,x3}, + undefined, + finalized} = + nested_after_1({{value,{V,x1}},void,{V,x1}}, + {error,{V,x2}}, {value,{V,x3}}), + ?line {{caught,{exit,{V,x3}}}, + undefined, + undefined, + finalized} = + nested_after_1({{value,{V,x1}},void,{V,x1}}, + {error,{V,x2}}, {exit,{V,x3}}), + %% + ?line {{caught,{error,{try_clause,{V,x1}}}}, + {V,x3}, + undefined, + finalized} = + nested_after_1({{value,{V,x1}},void,try_clause}, + void, {value,{V,x3}}), + ?line {{caught,{error,badarith}}, + undefined, + undefined, + finalized} = + nested_after_1({{value,{V,x1}},void,try_clause}, + void, {'div',{17,0}}), + %% + ?line {value, + {V,x3}, + {caught1,{V,x2}}, + finalized} = + nested_after_1({{throw,{V,x1}},throw,{V,x1}}, + {value,{V,x2}}, {value,{V,x3}}), + ?line {{caught,{error,badarith}}, + {V,x3}, + undefined, + finalized} = + nested_after_1({{throw,{V,x1}},throw,{V,x1}}, + {'add',{a,b}}, {value,{V,x3}}), + ?line {{caught,{error,badarg}}, + undefined, + undefined, + finalized} = + nested_after_1({{throw,{V,x1}},throw,{V,x1}}, + {'add',{a,b}}, {'abs',V}), + %% + ?line {{caught,{throw,{V,x1}}}, + {V,x3}, + undefined, + finalized} = + nested_after_1({{throw,{V,x1}},rethrow,void}, + void, {value,{V,x3}}), + ?line {{caught,{error,badarith}}, + undefined, + undefined, + finalized} = + nested_after_1({{throw,{V,x1}},rethrow,void}, + void, {'div',{1,0}}), + ok. + +nested_after_1({X1,C1,V1}, + X2, X3) -> + erase(nested3), + erase(nested4), + erase(nested), + Self = self(), + Try = + try + try self() + after + After = + try + foo(X1) + of + V1 -> {value1,foo(X2)} + catch + C1:V1 -> {caught1,foo(X2)} + after + put(nested3, foo(X3)) + end, + put(nested4, After) + end + of + Self -> value + catch + C:D -> {caught,{C,D}} + after + put(nested, finalized) + end, + {Try,erase(nested3),erase(nested4),erase(nested)}. + + + +nested_horrid(Config) when is_list(Config) -> + _V = {make_ref(),nested_horrid,4.711}, + {[true,true],{[true,1.0],1.0}} = + nested_horrid_1({true,void,void}, 1.0), + ok. + +nested_horrid_1({X1,C1,V1}, X2) -> + try A1 = [X1,X1], + B1 = if X1 -> + A2 = [X1,X2], + B2 = foo(X2), + {A2,B2}; + true -> + A3 = [X2,X1], + B3 = foo(X2), + {A3,B3} + end, + {A1,B1} + catch + C1:V1 -> caught1 + end. + + + +foo({value,Value}) -> Value; +foo({'div',{A,B}}) -> + my_div(A, B); +foo({'add',{A,B}}) -> + my_add(A, B); +foo({'abs',X}) -> + my_abs(X); +foo({error,Error}) -> + erlang:error(Error); +foo({throw,Throw}) -> + erlang:throw(Throw); +foo({exit,Exit}) -> + erlang:exit(Exit); +foo({raise,{Class,Reason}}) -> + erlang:raise(Class, Reason); +foo(Term) when not is_atom(Term) -> Term. +%%foo(Atom) when is_atom(Atom) -> % must not be defined! + +my_div(A, B) -> + A div B. + +my_add(A, B) -> + A + B. + +my_abs(X) -> abs(X). + + +last_call_optimization(Config) when is_list(Config) -> + ?line error = in_tail(dum), + ?line StkSize0 = in_tail(0), + ?line StkSize = in_tail(50000), + io:format("StkSize0 = ~p", [StkSize0]), + io:format("StkSize = ~p", [StkSize]), + ?line StkSize = StkSize0, + ok. + +in_tail(E) -> + try erlang:abs(E) of + T -> + A = id([]), + B = id([]), + C = id([]), + id([A,B,C]), + do_tail(T) + catch error:badarg -> error + end. + +do_tail(0) -> + process_info(self(), stack_size); +do_tail(N) -> + in_tail(N-1). + +bool(Config) when is_list(Config) -> + ok = do_bool(false, false), + error = do_bool(false, true), + error = do_bool(true, false), + error = do_bool(true, true), + error = do_bool(true, blurf), + {'EXIT',_} = (catch do_bool(blurf, false)), + ok. + +%% The following function used to cause a crash in beam_bool. +do_bool(A0, B) -> + A = not A0, + try + id(42), + if + A, not B -> ok + end + catch + _:_ -> + error + end. + +plain_catch_coverage(Config) when is_list(Config) -> + %% Cover some code in beam_block:alloc_may_pass/1. + ?line {a,[42]} = do_plain_catch_list(42). + +do_plain_catch_list(X) -> + B = [X], + catch id({a,B}). + +andalso_orelse(Config) when is_list(Config) -> + ?line {2,{a,42}} = andalso_orelse_1(true, {a,42}), + ?line {b,{b}} = andalso_orelse_1(false, {b}), + ?line {catched,no_tuple} = andalso_orelse_1(false, no_tuple), + + ?line ok = andalso_orelse_2({type,[a]}), + ?line also_ok = andalso_orelse_2({type,[]}), + ?line also_ok = andalso_orelse_2({type,{a}}), + ok. + +andalso_orelse_1(A, B) -> + {try + if + A andalso element(1, B) =:= a -> + tuple_size(B); + true -> + element(1, B) + end + catch error:_ -> + catched + end,B}. + +id(I) -> I. + +andalso_orelse_2({Type,Keyval}) -> + try + if is_atom(Type) andalso length(Keyval) > 0 -> ok; + true -> also_ok + end + catch + _:_ -> fail + end. + +zero() -> + 0.0. |