diff options
author | Björn Gustavsson <[email protected]> | 2013-12-13 11:51:25 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2013-12-13 11:51:25 +0100 |
commit | fa6407f35c12156a9ed2eb25fb131e1ef5c7f0e4 (patch) | |
tree | 86f2b4178f0a15e33d300cf648a0b235252b9990 /lib/debugger | |
parent | af17798534de376505498b86525ab8618753ebf7 (diff) | |
parent | 4df233adc5a1d5ab54d3c7419a463ae1ef417c12 (diff) | |
download | otp-fa6407f35c12156a9ed2eb25fb131e1ef5c7f0e4.tar.gz otp-fa6407f35c12156a9ed2eb25fb131e1ef5c7f0e4.tar.bz2 otp-fa6407f35c12156a9ed2eb25fb131e1ef5c7f0e4.zip |
Merge branch 'nox/eep37/OTP-11537'
* nox/eep37/OTP-11537:
Support EEP37 named funs in emacs erlang-mode
Document named fun expressions
Test named funs
Support named funs in the debugger interpreter
Update primary bootstrap for named funs in the shell
Support named funs in the shell
Update primary bootstrap for named funs
EEP 37: Funs with names
Support non top level letrecs in dialyzer
Diffstat (limited to 'lib/debugger')
-rw-r--r-- | lib/debugger/src/dbg_ieval.erl | 145 | ||||
-rw-r--r-- | lib/debugger/src/dbg_iload.erl | 3 | ||||
-rw-r--r-- | lib/debugger/test/erl_eval_SUITE.erl | 26 | ||||
-rw-r--r-- | lib/debugger/test/fun_SUITE.erl | 17 |
4 files changed, 161 insertions, 30 deletions
diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl index f4b6d488a5..6ce3262ed2 100644 --- a/lib/debugger/src/dbg_ieval.erl +++ b/lib/debugger/src/dbg_ieval.erl @@ -204,7 +204,8 @@ meta(Int, Debugged, M, F, As) -> %% If it's a fun we're evaluating, show a text %% representation of the fun and its arguments, %% not dbg_ieval:eval_fun(...) - {dbg_ieval, eval_fun} -> + {dbg_ieval, EvalFun} when EvalFun =:= eval_fun; + EvalFun =:= eval_named_fun -> {Mx, Fx} = lists:last(As), {Mx, Fx, lists:nth(2, As)}; _ -> @@ -432,7 +433,8 @@ eval_function(Mod, Name, As, Bs, Called, Ieval0, Lc) -> do_eval_function(Mod, Fun, As0, Bs0, _, Ieval0) when is_function(Fun); Mod =:= ?MODULE, - Fun =:= eval_fun -> + Fun =:= eval_fun orelse + Fun =:= eval_named_fun -> #ieval{level=Le,line=Li,top=Top} = Ieval0, case lambda(Fun, As0) of {[{clause,Fc,_,_,_}|_]=Cs,Module,Name,As,Bs} -> @@ -487,13 +489,29 @@ lambda(eval_fun, [Cs,As,Bs,{Mod,Name}=F]) -> true -> {error,{badarity,{F,As}}} end; +lambda(eval_named_fun, [Cs,As,Bs0,FName,RF,{Mod,Name}=F]) -> + %% Fun defined in interpreted code, called from outside + if + length(element(3,hd(Cs))) =:= length(As) -> + db_ref(Mod), %% Adds ref between module and process + Bs1 = add_binding(FName, RF, Bs0), + {Cs,Mod,Name,As,Bs1}; + true -> + {error,{badarity,{F,As}}} + end; lambda(Fun, As) when is_function(Fun) -> %% Fun called from within interpreted code... case erlang:fun_info(Fun, module) of %% ... and the fun was defined in interpreted code {module, ?MODULE} -> - {env, [{Mod,Name},Bs,Cs]} = erlang:fun_info(Fun, env), + {Mod,Name,Bs} = + case erlang:fun_info(Fun, env) of + {env,[{{M,F},Bs0,Cs}]} -> + {M,F,Bs0}; + {env,[{{M,F},Bs0,Cs,FName}]} -> + {M,F,add_binding(FName, Fun, Bs0)} + end, {arity, Arity} = erlang:fun_info(Fun, arity), if length(As) =:= Arity -> @@ -727,50 +745,121 @@ expr({match,Line,Lhs,Rhs0}, Bs0, Ieval0) -> %% Construct a fun expr({make_fun,Line,Name,Cs}, Bs, #ieval{module=Module}=Ieval) -> Arity = length(element(3,hd(Cs))), - Info = {Module,Name}, + Info = {{Module,Name},Bs,Cs}, Fun = case Arity of - 0 -> fun() -> eval_fun(Cs, [], Bs, Info) end; - 1 -> fun(A) -> eval_fun(Cs, [A], Bs,Info) end; - 2 -> fun(A,B) -> eval_fun(Cs, [A,B], Bs,Info) end; - 3 -> fun(A,B,C) -> eval_fun(Cs, [A,B,C], Bs,Info) end; - 4 -> fun(A,B,C,D) -> eval_fun(Cs, [A,B,C,D], Bs,Info) end; - 5 -> fun(A,B,C,D,E) -> eval_fun(Cs, [A,B,C,D,E], Bs,Info) end; - 6 -> fun(A,B,C,D,E,F) -> eval_fun(Cs, [A,B,C,D,E,F], Bs,Info) end; + 0 -> fun() -> eval_fun([], Info) end; + 1 -> fun(A) -> eval_fun([A], Info) end; + 2 -> fun(A,B) -> eval_fun([A,B], Info) end; + 3 -> fun(A,B,C) -> eval_fun([A,B,C], Info) end; + 4 -> fun(A,B,C,D) -> eval_fun([A,B,C,D], Info) end; + 5 -> fun(A,B,C,D,E) -> eval_fun([A,B,C,D,E], Info) end; + 6 -> fun(A,B,C,D,E,F) -> eval_fun([A,B,C,D,E,F], Info) end; 7 -> fun(A,B,C,D,E,F,G) -> - eval_fun(Cs, [A,B,C,D,E,F,G], Bs,Info) end; + eval_fun([A,B,C,D,E,F,G], Info) end; 8 -> fun(A,B,C,D,E,F,G,H) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H], Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H], Info) end; 9 -> fun(A,B,C,D,E,F,G,H,I) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H,I], Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H,I], Info) end; 10 -> fun(A,B,C,D,E,F,G,H,I,J) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J], Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H,I,J], Info) end; 11 -> fun(A,B,C,D,E,F,G,H,I,J,K) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K], Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H,I,J,K], Info) end; 12 -> fun(A,B,C,D,E,F,G,H,I,J,K,L) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L], Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H,I,J,K,L], Info) end; 13 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M], Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M], Info) end; 14 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N], Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N], Info) end; 15 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O], Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O], Info) end; 16 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P], Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P], Info) end; 17 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q], Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q], Info) end; 18 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R], Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R], Info) end; 19 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S],Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S],Info) end; 20 -> fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T) -> - eval_fun(Cs, [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T],Bs,Info) end; + eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T],Info) end; _Other -> exception(error, {'argument_limit',{'fun',Cs}}, Bs, Ieval#ieval{line=Line}) end, {value,Fun,Bs}; +%% Construct a fun +expr({make_named_fun,Line,Name,FName,Cs}, Bs, #ieval{module=Module}=Ieval) -> + Arity = length(element(3,hd(Cs))), + Info = {{Module,Name},Bs,Cs,FName}, + Fun = + case Arity of + 0 -> fun RF() -> eval_named_fun([], RF, Info) end; + 1 -> fun RF(A) -> eval_named_fun([A], RF, Info) end; + 2 -> fun RF(A,B) -> + eval_named_fun([A,B], RF, Info) end; + 3 -> fun RF(A,B,C) -> + eval_named_fun([A,B,C], RF, Info) end; + 4 -> fun RF(A,B,C,D) -> + eval_named_fun([A,B,C,D], RF, Info) end; + 5 -> fun RF(A,B,C,D,E) -> + eval_named_fun([A,B,C,D,E], + RF, Info) end; + 6 -> fun RF(A,B,C,D,E,F) -> + eval_named_fun([A,B,C,D,E,F], + RF, Info) end; + 7 -> fun RF(A,B,C,D,E,F,G) -> + eval_named_fun([A,B,C,D,E,F,G], + RF, Info) end; + 8 -> fun RF(A,B,C,D,E,F,G,H) -> + eval_named_fun([A,B,C,D,E,F,G,H], + RF, Info) end; + 9 -> fun RF(A,B,C,D,E,F,G,H,I) -> + eval_named_fun([A,B,C,D,E,F,G,H,I], + RF, Info) end; + 10 -> fun RF(A,B,C,D,E,F,G,H,I,J) -> + eval_named_fun([A,B,C,D,E,F,G,H,I,J], + RF, Info) end; + 11 -> fun RF(A,B,C,D,E,F,G,H,I,J,K) -> + eval_named_fun([A,B,C,D,E,F,G,H,I,J,K], + RF, Info) end; + 12 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L) -> + eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L], + RF, Info) end; + 13 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M) -> + eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M], + RF, Info) end; + 14 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N) -> + eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N], + RF, Info) end; + 15 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O) -> + eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O], + RF, Info) end; + 16 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) -> + eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P], + RF, Info) end; + 17 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q) -> + eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q], + RF, Info) end; + 18 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) -> + eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q, + R], + RF, Info) end; + 19 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S) -> + eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q, + R,S], + RF, Info) end; + 20 -> fun RF(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T) -> + eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q, + R,S,T], + RF, Info) end; + _Other -> + exception(error, {'argument_limit',{named_fun,FName,Cs}}, Bs, + Ieval#ieval{line=Line}) + end, + {value,Fun,Bs}; + %% Construct an external fun. expr({make_ext_fun,Line,MFA0}, Bs0, Ieval0) -> {[M,F,A],Bs} = eval_list(MFA0, Bs0, Ieval0), @@ -960,9 +1049,13 @@ expr(E, _Bs, _Ieval) -> erlang:error({'NYI',E}). %% Interpreted fun() called from uninterpreted module, recurse -eval_fun(Cs, As, Bs, Info) -> +eval_fun(As, {Info,Bs,Cs}) -> dbg_debugged:eval(?MODULE, eval_fun, [Cs,As,Bs,Info]). +%% Interpreted named fun() called from uninterpreted module, recurse +eval_named_fun(As, RF, {Info,Bs,Cs,FName}) -> + dbg_debugged:eval(?MODULE, eval_named_fun, [Cs,As,Bs,FName,RF,Info]). + %% eval_lc(Expr,[Qualifier],Bindings,IevalState) -> %% {value,Value,Bindings}. %% This is evaluating list comprehensions "straight out of the book". diff --git a/lib/debugger/src/dbg_iload.erl b/lib/debugger/src/dbg_iload.erl index 3c95ef8068..9806692afc 100644 --- a/lib/debugger/src/dbg_iload.erl +++ b/lib/debugger/src/dbg_iload.erl @@ -369,6 +369,9 @@ expr({'fun',Line,{function,F,A},{_Index,_OldUniq,Name}}, _Lc) -> As = new_vars(A, Line), Cs = [{clause,Line,As,[],[{local_call,Line,F,As,true}]}], {make_fun,Line,Name,Cs}; +expr({named_fun,Line,FName,Cs0,{_,_,Name}}, _Lc) when is_atom(Name) -> + Cs = fun_clauses(Cs0), + {make_named_fun,Line,Name,FName,Cs}; expr({'fun',Line,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Lc) when 0 =< A, A =< 255 -> %% New format in R15 for fun M:F/A (literal values). diff --git a/lib/debugger/test/erl_eval_SUITE.erl b/lib/debugger/test/erl_eval_SUITE.erl index bb2669f450..be9312b68f 100644 --- a/lib/debugger/test/erl_eval_SUITE.erl +++ b/lib/debugger/test/erl_eval_SUITE.erl @@ -39,7 +39,8 @@ otp_8133/1, funs/1, try_catch/1, - eval_expr_5/1]). + eval_expr_5/1, + eep37/1]). %% %% Define to run outside of test server @@ -78,7 +79,7 @@ all() -> pattern_expr, match_bin, guard_3, guard_4, lc, simple_cases, unary_plus, apply_atom, otp_5269, otp_6539, otp_6543, otp_6787, otp_6977, otp_7550, - otp_8133, funs, try_catch, eval_expr_5]. + otp_8133, funs, try_catch, eval_expr_5, eep37]. groups() -> []. @@ -1323,6 +1324,27 @@ eval_expr_5(Config) when is_list(Config) -> ok end. +eep37(Config) when is_list(Config) -> + check(fun () -> (fun _(X) -> X end)(42) end, + "(fun _(X) -> X end)(42).", + 42), + check(fun () -> (fun _Id(X) -> X end)(42) end, + "(fun _Id(X) -> X end)(42).", 42), + check(fun () -> is_function((fun Self() -> Self end)(), 0) end, + "is_function((fun Self() -> Self end)(), 0).", + true), + check(fun () -> + F = fun Fact(N) when N > 0 -> + N * Fact(N - 1); + Fact(0) -> + 1 + end, + F(6) + end, + "(fun Fact(N) when N > 0 -> N * Fact(N - 1); Fact(0) -> 1 end)(6).", + 720), + ok. + %% Check the string in different contexts: as is; in fun; from compiled code. check(F, String, Result) -> check1(F, String, Result), diff --git a/lib/debugger/test/fun_SUITE.erl b/lib/debugger/test/fun_SUITE.erl index a06cdc7165..8425f973e6 100644 --- a/lib/debugger/test/fun_SUITE.erl +++ b/lib/debugger/test/fun_SUITE.erl @@ -24,7 +24,7 @@ init_per_testcase/2,end_per_testcase/2, init_per_suite/1,end_per_suite/1, good_call/1,bad_apply/1,bad_fun_call/1,badarity/1, - ext_badarity/1,otp_6061/1,external/1]). + ext_badarity/1,otp_6061/1,external/1,eep37/1]). %% Internal exports. -export([nothing/0,call_me/1]). @@ -48,7 +48,7 @@ end_per_group(_GroupName, Config) -> cases() -> [good_call, bad_apply, bad_fun_call, badarity, - ext_badarity, otp_6061, external]. + ext_badarity, otp_6061, external, eep37]. init_per_testcase(_Case, Config) -> test_lib:interpret(?MODULE), @@ -288,5 +288,18 @@ external(Config) when is_list(Config) -> call_me(I) -> {ok,I}. +eep37(Config) when is_list(Config) -> + F = fun Fact(N) when N > 0 -> N * Fact(N - 1); Fact(0) -> 1 end, + Add = fun _(N) -> N + 1 end, + UnusedName = fun BlackAdder(N) -> N + 42 end, + 720 = F(6), + 10 = Add(9), + 50 = UnusedName(8), + [1,1,2,6,24,120] = lists:map(F, lists:seq(0, 5)), + {'EXIT',{{badarity,_},_}} = (catch lists:map(fun G() -> G() end, [1])), + {'EXIT',{{badarity,_},_}} = (catch F()), + + ok. + id(I) -> I. |