aboutsummaryrefslogtreecommitdiffstats
path: root/lib/debugger
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2013-12-13 11:51:25 +0100
committerBjörn Gustavsson <[email protected]>2013-12-13 11:51:25 +0100
commitfa6407f35c12156a9ed2eb25fb131e1ef5c7f0e4 (patch)
tree86f2b4178f0a15e33d300cf648a0b235252b9990 /lib/debugger
parentaf17798534de376505498b86525ab8618753ebf7 (diff)
parent4df233adc5a1d5ab54d3c7419a463ae1ef417c12 (diff)
downloadotp-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.erl145
-rw-r--r--lib/debugger/src/dbg_iload.erl3
-rw-r--r--lib/debugger/test/erl_eval_SUITE.erl26
-rw-r--r--lib/debugger/test/fun_SUITE.erl17
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.