aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib')
-rw-r--r--lib/stdlib/doc/src/c.xml4
-rw-r--r--lib/stdlib/doc/src/erl_eval.xml5
-rw-r--r--lib/stdlib/doc/src/lists.xml25
-rw-r--r--lib/stdlib/src/beam_lib.erl18
-rw-r--r--lib/stdlib/src/c.erl6
-rw-r--r--lib/stdlib/src/epp.erl2
-rw-r--r--lib/stdlib/src/erl_eval.erl64
-rw-r--r--lib/stdlib/src/erl_lint.erl137
-rw-r--r--lib/stdlib/src/erl_pp.erl41
-rw-r--r--lib/stdlib/src/lists.erl24
-rw-r--r--lib/stdlib/src/otp_internal.erl181
-rw-r--r--lib/stdlib/test/c_SUITE.erl11
-rw-r--r--lib/stdlib/test/epp_SUITE.erl4
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl56
-rw-r--r--lib/stdlib/test/ets_SUITE.erl88
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl16
-rw-r--r--lib/stdlib/test/lists_SUITE.erl4
-rw-r--r--lib/stdlib/test/zip_SUITE.erl25
18 files changed, 507 insertions, 204 deletions
diff --git a/lib/stdlib/doc/src/c.xml b/lib/stdlib/doc/src/c.xml
index ddae388a1b..9cd4581a89 100644
--- a/lib/stdlib/doc/src/c.xml
+++ b/lib/stdlib/doc/src/c.xml
@@ -140,9 +140,9 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w
</func>
<func>
<name name="ls" arity="1"/>
- <fsummary>List files in a directory</fsummary>
+ <fsummary>List files in a directory or a single file</fsummary>
<desc>
- <p>Lists files in directory <c><anno>Dir</anno></c>.</p>
+ <p>Lists files in directory <c><anno>Dir</anno></c> or, if Dir is a file, only list it.</p>
</desc>
</func>
<func>
diff --git a/lib/stdlib/doc/src/erl_eval.xml b/lib/stdlib/doc/src/erl_eval.xml
index d0622594d9..24940f8396 100644
--- a/lib/stdlib/doc/src/erl_eval.xml
+++ b/lib/stdlib/doc/src/erl_eval.xml
@@ -288,10 +288,7 @@ Func(FuncSpec, Arguments) </code>
<section>
<title>Bugs</title>
- <p>The evaluator is not complete. <c>receive</c> cannot be
- handled properly.
- </p>
- <p>Any undocumented functions in <c>erl_eval</c> should not be used.</p>
+ <p>Undocumented functions in <c>erl_eval</c> should not be used.</p>
</section>
</erlref>
diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml
index b6c0fa4e05..1aff78f4fc 100644
--- a/lib/stdlib/doc/src/lists.xml
+++ b/lib/stdlib/doc/src/lists.xml
@@ -152,6 +152,31 @@
</desc>
</func>
<func>
+ <name name="filtermap" arity="2"/>
+ <fsummary>Filter and map elements which satisfy a function</fsummary>
+ <desc>
+ <p>Calls <c><anno>Fun</anno>(<anno>Elem</anno>)</c> on successive elements <c>Elem</c>
+ of <c><anno>List1</anno></c>. <c><anno>Fun</anno>/2</c> must return either a boolean
+ or a tuple <c>{true, <anno>Value</anno>}</c>. The function returns the list of elements
+ for which <c><anno>Fun</anno></c> returns a new value, where a value of <c>true</c>
+ is synonymous with <c>{true, <anno>Elem</anno>}</c>.</p>
+ <p>That is, <c>filtermap</c> behaves as if it had been defined as follows:</p>
+ <code type="none">
+filtermap(Fun, List1) ->
+ lists:foldr(fun(Elem, Acc) ->
+ case Fun(Elem) of
+ false -> Acc;
+ true -> [Elem|Acc];
+ {true,Value} -> [Value|Acc]
+ end,
+ end, [], List1).</code>
+ <p>Example:</p>
+ <pre>
+> <input>lists:filtermap(fun(X) -> case X rem 2 of 0 -> {true, X div 2}; _ -> false end end, [1,2,3,4,5]).</input>
+[1,2]</pre>
+ </desc>
+ </func>
+ <func>
<name name="flatlength" arity="1"/>
<fsummary>Length of flattened deep list</fsummary>
<desc>
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index fe7e0f8e60..121f9febed 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -300,12 +300,12 @@ clear_crypto_key_fun() ->
call_crypto_server(clear_crypto_key_fun).
-spec make_crypto_key(mode(), string()) ->
- {binary(), binary(), binary(), binary()}.
+ {mode(), [binary()], binary(), integer()}.
-make_crypto_key(des3_cbc, String) ->
+make_crypto_key(des3_cbc=Type, String) ->
<<K1:8/binary,K2:8/binary>> = First = erlang:md5(String),
<<K3:8/binary,IVec:8/binary>> = erlang:md5([First|reverse(String)]),
- {K1,K2,K3,IVec}.
+ {Type,[K1,K2,K3],IVec,8}.
%%
%% Local functions
@@ -864,20 +864,20 @@ mandatory_chunks() ->
-define(CRYPTO_KEY_SERVER, beam_lib__crypto_key_server).
-decrypt_abst(Mode, Module, File, Id, AtomTable, Bin) ->
+decrypt_abst(Type, Module, File, Id, AtomTable, Bin) ->
try
- KeyString = get_crypto_key({debug_info, Mode, Module, File}),
- Key = make_crypto_key(des3_cbc, KeyString),
- Term = decrypt_abst_1(Mode, Key, Bin),
+ KeyString = get_crypto_key({debug_info, Type, Module, File}),
+ Key = make_crypto_key(Type, KeyString),
+ Term = decrypt_abst_1(Key, Bin),
{AtomTable, {Id, Term}}
catch
_:_ ->
error({key_missing_or_invalid, File, Id})
end.
-decrypt_abst_1(des3_cbc, {K1, K2, K3, IVec}, Bin) ->
+decrypt_abst_1({Type,Key,IVec,_BlockSize}, Bin) ->
ok = start_crypto(),
- NewBin = crypto:des3_cbc_decrypt(K1, K2, K3, IVec, Bin),
+ NewBin = crypto:block_decrypt(Type, Key, IVec, Bin),
binary_to_term(NewBin).
start_crypto() ->
diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl
index 91d317489c..6e96e3d564 100644
--- a/lib/stdlib/src/c.erl
+++ b/lib/stdlib/src/c.erl
@@ -713,8 +713,10 @@ ls(Dir) ->
case file:list_dir(Dir) of
{ok, Entries} ->
ls_print(sort(Entries));
- {error,_E} ->
- format("Invalid directory\n")
+ {error, enotdir} ->
+ ls_print([Dir]);
+ {error, Error} ->
+ format("~s\n", [file:format_error(Error)])
end.
ls_print([]) -> ok;
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index e31cd63f69..d1d060ebc8 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -601,7 +601,7 @@ enter_file2(NewF, Pname, From, St0, AtLocation) ->
%% file will depend on the order of file inclusions in the parent files
Path = [filename:dirname(Pname) | tl(St0#epp.path)],
_ = set_encoding(NewF),
- #epp{file=NewF,location=Loc,name=Pname,delta=0,
+ #epp{file=NewF,location=Loc,name=Pname,name2=Pname,delta=0,
sstk=[St0|St0#epp.sstk],path=Path,macs=Ms}.
enter_file_reply(From, Name, Location, AtLocation) ->
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 0b57af1b6d..73b8da335a 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -245,10 +245,10 @@ expr({'case',_,E,Cs}, Bs0, Lf, Ef, RBs) ->
expr({'try',_,B,Cases,Catches,AB}, Bs, Lf, Ef, RBs) ->
try_clauses(B, Cases, Catches, AB, Bs, Lf, Ef, RBs);
expr({'receive',_,Cs}, Bs, Lf, Ef, RBs) ->
- receive_clauses(Cs, Bs, Lf, Ef, [], RBs);
+ receive_clauses(Cs, Bs, Lf, Ef, RBs);
expr({'receive',_, Cs, E, TB}, Bs0, Lf, Ef, RBs) ->
{value,T,Bs} = expr(E, Bs0, Lf, Ef, none),
- receive_clauses(T, Cs, {TB,Bs}, Bs0, Lf, Ef, [], RBs);
+ receive_clauses(T, Cs, {TB,Bs}, Bs0, Lf, Ef, RBs);
expr({'fun',_Line,{function,Mod0,Name0,Arity0}}, Bs0, Lf, Ef, RBs) ->
{[Mod,Name,Arity],Bs} = expr_list([Mod0,Name0,Arity0], Bs0, Lf, Ef),
F = erlang:make_fun(Mod, Name, Arity),
@@ -807,66 +807,24 @@ case_clauses(Val, Cs, Bs, Lf, Ef, RBs) ->
end.
%%
-%% receive_clauses(Clauses, Bindings, LocalFuncHnd,ExtFuncHnd, Messages, RBs)
+%% receive_clauses(Clauses, Bindings, LocalFuncHnd,ExtFuncHnd, RBs)
%%
-receive_clauses(Cs, Bs, Lf, Ef, Ms, RBs) ->
- receive
- Val ->
- case match_clause(Cs, [Val], Bs, Lf, Ef) of
- {B, Bs1} ->
- merge_queue(Ms),
- exprs(B, Bs1, Lf, Ef, RBs);
- nomatch ->
- receive_clauses(Cs, Bs, Lf, Ef, [Val|Ms], RBs)
- end
- end.
+receive_clauses(Cs, Bs, Lf, Ef, RBs) ->
+ receive_clauses(infinity, Cs, unused, Bs, Lf, Ef, RBs).
%%
%% receive_clauses(TimeOut, Clauses, TimeoutBody, Bindings,
%% ExternalFuncHandler, LocalFuncHandler, RBs)
%%
-receive_clauses(T, Cs, TB, Bs, Lf, Ef, Ms, RBs) ->
- {_,_} = statistics(runtime),
- receive
- Val ->
- case match_clause(Cs, [Val], Bs, Lf, Ef) of
- {B, Bs1} ->
- merge_queue(Ms),
- exprs(B, Bs1, Lf, Ef, RBs);
- nomatch ->
- {_,T1} = statistics(runtime),
- if
- T =:= infinity ->
- receive_clauses(T, Cs, TB,Bs,Lf,Ef,[Val|Ms],RBs);
- T-T1 =< 0 ->
- receive_clauses(0, Cs, TB,Bs,Lf,Ef,[Val|Ms],RBs);
- true ->
- receive_clauses(T-T1, Cs,TB,Bs,Lf,Ef,[Val|Ms],RBs)
- end
- end
- after T ->
- merge_queue(Ms),
+receive_clauses(T, Cs, TB, Bs, Lf, Ef, RBs) ->
+ F = fun (M) -> match_clause(Cs, [M], Bs, Lf, Ef) end,
+ case prim_eval:'receive'(F, T) of
+ {B, Bs1} ->
+ exprs(B, Bs1, Lf, Ef, RBs);
+ timeout ->
{B, Bs1} = TB,
exprs(B, Bs1, Lf, Ef, RBs)
end.
-merge_queue([]) ->
- true;
-merge_queue(Ms) ->
- send_all(recv_all(Ms), self()).
-
-recv_all(Xs) ->
- receive
- X -> recv_all([X|Xs])
- after 0 ->
- reverse(Xs)
- end.
-
-send_all([X|Xs], Self) ->
- Self ! X,
- send_all(Xs, Self);
-send_all([], _) -> true.
-
-
%% match_clause -> {Body, Bindings} or nomatch
-spec(match_clause(Clauses, ValueList, Bindings, LocalFunctionHandler) ->
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 68a8534f15..08b8541014 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -522,8 +522,7 @@ start(File, Opts) ->
warn_format = value_option(warn_format, 1, warn_format, 1,
nowarn_format, 0, Opts),
enabled_warnings = Enabled,
- file = File,
- types = default_types()
+ file = File
}.
%% is_warn_enabled(Category, St) -> boolean().
@@ -1007,7 +1006,10 @@ check_undefined_functions(#lint{called=Called0,defined=Def0}=St0) ->
check_undefined_types(#lint{usage=Usage,types=Def}=St0) ->
Used = Usage#usage.used_types,
UTAs = dict:fetch_keys(Used),
- Undef = [{TA,dict:fetch(TA, Used)} || TA <- UTAs, not dict:is_key(TA, Def)],
+ Undef = [{TA,dict:fetch(TA, Used)} ||
+ TA <- UTAs,
+ not dict:is_key(TA, Def),
+ not is_default_type(TA)],
foldl(fun ({TA,L}, St) ->
add_error(L, {undefined_type,TA}, St)
end, St0, Undef).
@@ -2440,7 +2442,7 @@ type_def(Attr, Line, TypeName, ProtoType, Args, St0) ->
end,
case (dict:is_key(TypePair, TypeDefs) orelse is_var_arity_type(TypeName)) of
true ->
- case dict:is_key(TypePair, default_types()) of
+ case is_default_type(TypePair) of
true ->
case is_newly_introduced_builtin_type(TypePair) of
%% allow some types just for bootstrapping
@@ -2488,8 +2490,8 @@ check_type({paren_type, _L, [Type]}, SeenVars, St) ->
check_type({remote_type, L, [{atom, _, Mod}, {atom, _, Name}, Args]},
SeenVars, #lint{module=CurrentMod} = St) ->
St1 =
- case (dict:is_key({Name, length(Args)}, default_types())
- orelse is_var_arity_type(Name)) of
+ case is_default_type({Name, length(Args)})
+ orelse is_var_arity_type(Name) of
true -> add_error(L, {imported_predefined_type, Name}, St);
false -> St
end,
@@ -2606,63 +2608,62 @@ is_var_arity_type(union) -> true;
is_var_arity_type(record) -> true;
is_var_arity_type(_) -> false.
-default_types() ->
- DefTypes = [{any, 0},
- {arity, 0},
- {array, 0},
- {atom, 0},
- {atom, 1},
- {binary, 0},
- {binary, 2},
- {bitstring, 0},
- {bool, 0},
- {boolean, 0},
- {byte, 0},
- {char, 0},
- {dict, 0},
- {digraph, 0},
- {float, 0},
- {'fun', 0},
- {'fun', 2},
- {function, 0},
- {gb_set, 0},
- {gb_tree, 0},
- {identifier, 0},
- {integer, 0},
- {integer, 1},
- {iodata, 0},
- {iolist, 0},
- {list, 0},
- {list, 1},
- {maybe_improper_list, 0},
- {maybe_improper_list, 2},
- {mfa, 0},
- {module, 0},
- {neg_integer, 0},
- {nil, 0},
- {no_return, 0},
- {node, 0},
- {non_neg_integer, 0},
- {none, 0},
- {nonempty_list, 0},
- {nonempty_list, 1},
- {nonempty_improper_list, 2},
- {nonempty_maybe_improper_list, 0},
- {nonempty_maybe_improper_list, 2},
- {nonempty_string, 0},
- {number, 0},
- {pid, 0},
- {port, 0},
- {pos_integer, 0},
- {queue, 0},
- {range, 2},
- {reference, 0},
- {set, 0},
- {string, 0},
- {term, 0},
- {timeout, 0},
- {var, 1}],
- dict:from_list([{T, -1} || T <- DefTypes]).
+is_default_type({any, 0}) -> true;
+is_default_type({arity, 0}) -> true;
+is_default_type({array, 0}) -> true;
+is_default_type({atom, 0}) -> true;
+is_default_type({atom, 1}) -> true;
+is_default_type({binary, 0}) -> true;
+is_default_type({binary, 2}) -> true;
+is_default_type({bitstring, 0}) -> true;
+is_default_type({bool, 0}) -> true;
+is_default_type({boolean, 0}) -> true;
+is_default_type({byte, 0}) -> true;
+is_default_type({char, 0}) -> true;
+is_default_type({dict, 0}) -> true;
+is_default_type({digraph, 0}) -> true;
+is_default_type({float, 0}) -> true;
+is_default_type({'fun', 0}) -> true;
+is_default_type({'fun', 2}) -> true;
+is_default_type({function, 0}) -> true;
+is_default_type({gb_set, 0}) -> true;
+is_default_type({gb_tree, 0}) -> true;
+is_default_type({identifier, 0}) -> true;
+is_default_type({integer, 0}) -> true;
+is_default_type({integer, 1}) -> true;
+is_default_type({iodata, 0}) -> true;
+is_default_type({iolist, 0}) -> true;
+is_default_type({list, 0}) -> true;
+is_default_type({list, 1}) -> true;
+is_default_type({maybe_improper_list, 0}) -> true;
+is_default_type({maybe_improper_list, 2}) -> true;
+is_default_type({mfa, 0}) -> true;
+is_default_type({module, 0}) -> true;
+is_default_type({neg_integer, 0}) -> true;
+is_default_type({nil, 0}) -> true;
+is_default_type({no_return, 0}) -> true;
+is_default_type({node, 0}) -> true;
+is_default_type({non_neg_integer, 0}) -> true;
+is_default_type({none, 0}) -> true;
+is_default_type({nonempty_list, 0}) -> true;
+is_default_type({nonempty_list, 1}) -> true;
+is_default_type({nonempty_improper_list, 2}) -> true;
+is_default_type({nonempty_maybe_improper_list, 0}) -> true;
+is_default_type({nonempty_maybe_improper_list, 2}) -> true;
+is_default_type({nonempty_string, 0}) -> true;
+is_default_type({number, 0}) -> true;
+is_default_type({pid, 0}) -> true;
+is_default_type({port, 0}) -> true;
+is_default_type({pos_integer, 0}) -> true;
+is_default_type({queue, 0}) -> true;
+is_default_type({range, 2}) -> true;
+is_default_type({reference, 0}) -> true;
+is_default_type({set, 0}) -> true;
+is_default_type({string, 0}) -> true;
+is_default_type({term, 0}) -> true;
+is_default_type({timeout, 0}) -> true;
+is_default_type({var, 1}) -> true;
+is_default_type(_) -> false.
%% R13
is_newly_introduced_builtin_type({arity, 0}) -> true;
@@ -2776,10 +2777,7 @@ check_unused_types(Forms, #lint{usage=Usage, types=Ts, exp_types=ExpTs}=St) ->
L = gb_sets:to_list(ExpTs) ++ dict:fetch_keys(D),
UsedTypes = gb_sets:from_list(L),
FoldFun =
- fun(_Type, -1, AccSt) ->
- %% Default type
- AccSt;
- (Type, #typeinfo{line = FileLine}, AccSt) ->
+ fun(Type, #typeinfo{line = FileLine}, AccSt) ->
case loc(FileLine) of
{FirstFile, _} ->
case gb_sets:is_member(Type, UsedTypes) of
@@ -2801,10 +2799,7 @@ check_unused_types(Forms, #lint{usage=Usage, types=Ts, exp_types=ExpTs}=St) ->
check_local_opaque_types(St) ->
#lint{types=Ts, exp_types=ExpTs} = St,
FoldFun =
- fun(_Type, -1, AccSt) ->
- %% Default type
- AccSt;
- (_Type, #typeinfo{attr = type}, AccSt) ->
+ fun(_Type, #typeinfo{attr = type}, AccSt) ->
AccSt;
(Type, #typeinfo{attr = opaque, line = FileLine}, AccSt) ->
case gb_sets:is_element(Type, ExpTs) of
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 7c7566e4ec..657cb5d34c 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -35,7 +35,7 @@
| fun((Expr :: erl_parse:abstract_expr(),
CurrentIndentation :: integer(),
CurrentPrecedence :: non_neg_integer(),
- HookFunction :: hook_function()) ->
+ Options :: options()) ->
io_lib:chars())).
-type(option() :: {hook, hook_function()}
@@ -214,7 +214,9 @@ lattribute({attribute,_Line,type,Type}, Opts, _State) ->
lattribute({attribute,_Line,opaque,Type}, Opts, _State) ->
[typeattr(opaque, Type, Opts),leaf(".\n")];
lattribute({attribute,_Line,spec,Arg}, _Opts, _State) ->
- [specattr(Arg),leaf(".\n")];
+ [specattr(spec, Arg),leaf(".\n")];
+lattribute({attribute,_Line,callback,Arg}, _Opts, _State) ->
+ [specattr(callback, Arg),leaf(".\n")];
lattribute({attribute,_Line,Name,Arg}, Opts, State) ->
[lattribute(Name, Arg, Opts, State),leaf(".\n")].
@@ -225,7 +227,7 @@ lattribute(module, {M,Vs}, _Opts, _State) ->
lattribute(module, M, _Opts, _State) ->
attr("module", [{var,0,pname(M)}]);
lattribute(export, Falist, _Opts, _State) ->
- call({var,0,"-export"}, [falist(Falist)], 0, none);
+ call({var,0,"-export"}, [falist(Falist)], 0, options(none));
lattribute(import, Name, _Opts, _State) when is_list(Name) ->
attr("import", [{var,0,pname(Name)}]);
lattribute(import, {From,Falist}, _Opts, _State) ->
@@ -240,10 +242,10 @@ lattribute(Name, Arg, #options{encoding = Encoding}, _State) ->
typeattr(Tag, {TypeName,Type,Args}, _Opts) ->
{first,leaf("-"++atom_to_list(Tag)++" "),
- typed(call({atom,0,TypeName}, Args, 0, none), Type)}.
+ typed(call({atom,0,TypeName}, Args, 0, options(none)), Type)}.
ltype({ann_type,_Line,[V,T]}) ->
- typed(lexpr(V, none), T);
+ typed(lexpr(V, options(none)), T);
ltype({paren_type,_Line,[T]}) ->
[$(,ltype(T),$)];
ltype({type,_Line,union,Ts}) ->
@@ -253,7 +255,7 @@ ltype({type,_Line,list,[T]}) ->
ltype({type,_Line,nonempty_list,[T]}) ->
{seq,$[,$],[$,],[ltype(T),leaf("...")]};
ltype({type,Line,nil,[]}) ->
- lexpr({nil,Line}, 0, none);
+ lexpr({nil,Line}, 0, options(none));
ltype({type,Line,tuple,any}) ->
simple_type({atom,Line,tuple}, []);
ltype({type,_Line,tuple,Ts}) ->
@@ -261,7 +263,7 @@ ltype({type,_Line,tuple,Ts}) ->
ltype({type,_Line,record,[{atom,_,N}|Fs]}) ->
record_type(N, Fs);
ltype({type,_Line,range,[_I1,_I2]=Es}) ->
- expr_list(Es, '..', fun lexpr/2, none);
+ expr_list(Es, '..', fun lexpr/2, options(none));
ltype({type,_Line,binary,[I1,I2]}) ->
binary_type(I1, I2); % except binary()
ltype({type,_Line,'fun',[]}) ->
@@ -277,14 +279,14 @@ ltype({remote_type,Line,[M,F,Ts]}) ->
ltype({atom,_,T}) ->
leaf(write(T));
ltype(E) ->
- lexpr(E, 0, none).
+ lexpr(E, 0, options(none)).
binary_type(I1, I2) ->
B = [[] || {integer,_,0} <- [I1]] =:= [],
U = [[] || {integer,_,0} <- [I2]] =:= [],
P = max_prec(),
- E1 = [[leaf("_:"),lexpr(I1, P, none)] || B],
- E2 = [[leaf("_:_*"),lexpr(I2, P, none)] || U],
+ E1 = [[leaf("_:"),lexpr(I1, P, options(none))] || B],
+ E2 = [[leaf("_:_*"),lexpr(I2, P, options(none))] || U],
{seq,'<<','>>',[$,],E1++E2}.
record_type(Name, Fields) ->
@@ -294,7 +296,7 @@ field_types(Fs) ->
tuple_type(Fs, fun field_type/1).
field_type({type,_Line,field_type,[Name,Type]}) ->
- typed(lexpr(Name, none), Type).
+ typed(lexpr(Name, options(none)), Type).
typed(B, {type,_,union,Ts}) ->
%% Special layout for :: followed by union.
@@ -311,14 +313,14 @@ union_elem(T) ->
tuple_type(Ts, F) ->
{seq,${,$},[$,],ltypes(Ts, F)}.
-specattr({FuncSpec,TypeSpecs}) ->
+specattr(SpecKind, {FuncSpec,TypeSpecs}) ->
Func = case FuncSpec of
{F,_A} ->
format("~w", [F]);
{M,F,_A} ->
format("~w:~w", [M, F])
end,
- {first,leaf("-spec "),
+ {first,leaf(lists:concat(["-", SpecKind, " "])),
{list,[{first,leaf(Func),spec_clauses(TypeSpecs)}]}}.
spec_clauses(TypeSpecs) ->
@@ -330,7 +332,8 @@ sig_type(FunType) ->
fun_type([], FunType).
guard_type(Before, Gs) ->
- Gl = {list,[{step,'when',expr_list(Gs, [$,], fun constraint/2, none)}]},
+ Opts = options(none),
+ Gl = {list,[{step,'when',expr_list(Gs, [$,], fun constraint/2, Opts)}]},
{list,[{step,Before,Gl}]}.
constraint({type,_Line,constraint,[Tag,As]}, _Opts) ->
@@ -345,7 +348,7 @@ type_args({type,_line,product,Ts}) ->
targs(Ts).
simple_type(Tag, Types) ->
- {first,lexpr(Tag, 0, none),targs(Types)}.
+ {first,lexpr(Tag, 0, options(none)),targs(Types)}.
targs(Ts) ->
{seq,$(,$),[$,],ltypes(Ts)}.
@@ -357,7 +360,7 @@ ltypes(Ts, F) ->
[F(T) || T <- Ts].
attr(Name, Args) ->
- call({var,0,format("-~s", [Name])}, Args, 0, none).
+ call({var,0,format("-~s", [Name])}, Args, 0, options(none)).
pname(['' | As]) ->
[$. | pname(As)];
@@ -632,11 +635,11 @@ bit_elem_types([T | Rest]) ->
[bit_elem_type(T), $-|bit_elem_types(Rest)].
bit_elem_type({A,B}) ->
- [lexpr(erl_parse:abstract(A), none),
+ [lexpr(erl_parse:abstract(A), options(none)),
$:,
- lexpr(erl_parse:abstract(B), none)];
+ lexpr(erl_parse:abstract(B), options(none))];
bit_elem_type(T) ->
- lexpr(erl_parse:abstract(T), none).
+ lexpr(erl_parse:abstract(T), options(none)).
%% end of BITS
diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl
index 961c060019..0c033acd88 100644
--- a/lib/stdlib/src/lists.erl
+++ b/lib/stdlib/src/lists.erl
@@ -36,7 +36,7 @@
-export([merge/3, rmerge/3, sort/2, umerge/3, rumerge/3, usort/2]).
-export([all/2,any/2,map/2,flatmap/2,foldl/3,foldr/3,filter/2,
- partition/2,zf/2,
+ partition/2,zf/2,filtermap/2,
mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2,splitwith/2,
split/2]).
@@ -1291,18 +1291,28 @@ partition(Pred, [H | T], As, Bs) ->
partition(Pred, [], As, Bs) when is_function(Pred, 1) ->
{reverse(As), reverse(Bs)}.
--spec zf(fun((T) -> boolean() | {'true', X}), [T]) -> [(T | X)].
+-spec filtermap(Fun, List1) -> List2 when
+ Fun :: fun((Elem) -> boolean() | {'true', Value}),
+ List1 :: [Elem],
+ List2 :: [Elem | Value],
+ Elem :: term(),
+ Value :: term().
-zf(F, [Hd|Tail]) ->
+filtermap(F, [Hd|Tail]) ->
case F(Hd) of
true ->
- [Hd|zf(F, Tail)];
+ [Hd|filtermap(F, Tail)];
{true,Val} ->
- [Val|zf(F, Tail)];
+ [Val|filtermap(F, Tail)];
false ->
- zf(F, Tail)
+ filtermap(F, Tail)
end;
-zf(F, []) when is_function(F, 1) -> [].
+filtermap(F, []) when is_function(F, 1) -> [].
+
+-spec zf(fun((T) -> boolean() | {'true', X}), [T]) -> [(T | X)].
+
+zf(F, L) ->
+ filtermap(F, L).
-spec foreach(Fun, List) -> ok when
Fun :: fun((Elem :: T) -> term()),
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index a4f4035c79..cebc9c91bd 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -66,6 +66,183 @@ obsolete_1(rpc, safe_multi_server_call, A) when A =:= 2; A =:= 3 ->
{deprecated, {rpc, multi_server_call, A}};
+%% *** CRYPTO add in R16B01 ***
+
+obsolete_1(crypto, md4, 1) ->
+ {deprecated, {crypto, hash, 2}};
+obsolete_1(crypto, md5, 1) ->
+ {deprecated, {crypto, hash, 2}};
+obsolete_1(crypto, sha, 1) ->
+ {deprecated, {crypto, hash, 2}};
+
+obsolete_1(crypto, md4_init, 0) ->
+ {deprecated, {crypto, hash_init, 1}};
+obsolete_1(crypto, md5_init, 0) ->
+ {deprecated, {crypto, hash_init, 1}};
+obsolete_1(crypto, sha_init, 0) ->
+ {deprecated, {crypto, hash_init, 1}};
+
+obsolete_1(crypto, md4_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+obsolete_1(crypto, md5_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+obsolete_1(crypto, sha_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+
+obsolete_1(crypto, md4_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+obsolete_1(crypto, md5_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+obsolete_1(crypto, sha_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+
+obsolete_1(crypto, md5_mac, 2) ->
+ {deprecated, {crypto, hmac, 3}};
+obsolete_1(crypto, sha_mac, 2) ->
+ {deprecated, {crypto, hmac, 3}};
+obsolete_1(crypto, sha_mac, 3) ->
+ {deprecated, {crypto, hmac, 4}};
+
+obsolete_1(crypto, sha_mac_96, 2) ->
+ {deprecated, {crypto, hmac_n, 3}};
+obsolete_1(crypto, md5_mac_96, 2) ->
+ {deprecated, {crypto, hmac_n, 3}};
+
+obsolete_1(crypto, rsa_sign, 2) ->
+ {deprecated, {crypto, sign, 4}};
+obsolete_1(crypto, rsa_sign, 3) ->
+ {deprecated, {crypto, sign, 4}};
+obsolete_1(crypto, rsa_verify, 3) ->
+ {deprecated, {crypto, verify, 5}};
+obsolete_1(crypto, rsa_verify, 4) ->
+ {deprecated, {crypto, verify, 5}};
+
+obsolete_1(crypto, dss_sign, 2) ->
+ {deprecated, {crypto, sign, 4}};
+obsolete_1(crypto, dss_sign, 3) ->
+ {deprecated, {crypto, sign, 4}};
+
+obsolete_1(crypto, dss_verify, 3) ->
+ {deprecated, {crypto, verify, 4}};
+obsolete_1(crypto, dss_verify, 4) ->
+ {deprecated, {crypto, verify, 4}};
+
+obsolete_1(crypto, mod_exp, 3) ->
+ {deprecated, {crypto, mod_pow, 3}};
+
+obsolete_1(crypto, dh_compute_key, 3) ->
+ {deprecated, {crypto, compute_key, 4}};
+obsolete_1(crypto, dh_generate_key, 1) ->
+ {deprecated, {crypto, generate_key, 3}};
+obsolete_1(crypto, dh_generate_key, 2) ->
+ {deprecated, {crypto, generate_key, 3}};
+
+obsolete_1(crypto, des_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des3_cbc_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_ecb_encrypt, 2) ->
+ {deprecated, {crypto, block_encrypt, 3}};
+obsolete_1(crypto, des_ede3_cbc_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_cfb_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des3_cfb_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_ecb_encrypt, 2) ->
+ {deprecated, {crypto, block_encrypt, 3}};
+obsolete_1(crypto, blowfish_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_cfb64_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_ofb64_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cfb_128_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cbc_128_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cbc_256_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto,rc2_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto,rc2_40_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+
+obsolete_1(crypto, des_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des3_cbc_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_ecb_decrypt, 2) ->
+ {deprecated, {crypto, block_decrypt, 3}};
+obsolete_1(crypto, des_ede3_cbc_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_cfb_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des3_cfb_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_ecb_decrypt, 2) ->
+ {deprecated, {crypto, block_decrypt, 3}};
+obsolete_1(crypto, blowfish_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_cfb64_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_ofb64_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cfb_128_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cbc_128_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cbc_256_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto,rc2_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto,rc2_40_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+
+obsolete_1(crypto, aes_ctr_stream_decrypt, 2) ->
+ {deprecated, {crypto, stream_decrypt, 2}};
+obsolete_1(crypto, aes_ctr_stream_encrypt, 2) ->
+ {deprecated, {crypto, stream_encrypt, 2}};
+obsolete_1(crypto, aes_ctr_decrypt, 3) ->
+ {deprecated, {crypto, stream_decrypt, 2}};
+obsolete_1(crypto, aes_ctr_encrypt, 3) ->
+ {deprecated, {crypto, stream_encrypt, 2}};
+obsolete_1(crypto, rc4_encrypt, 2) ->
+ {deprecated, {crypto, stream_encrypt, 2}};
+obsolete_1(crypto, rc4_encrypt_with_state, 2) ->
+ {deprecated, {crypto, stream_encrypt, 2}};
+obsolete_1(crypto, aes_ctr_stream_init, 2) ->
+ {deprecated, {crypto, stream_init, 3}};
+obsolete_1(crypto, rc4_set_key, 1) ->
+ {deprecated, {crypto, stream_init, 2}};
+
+obsolete_1(crypto, rsa_private_decrypt, 3) ->
+ {deprecated, {crypto, private_decrypt, 4}};
+obsolete_1(crypto, rsa_public_decrypt, 3) ->
+ {deprecated, {crypto, public_decrypt, 4}};
+obsolete_1(crypto, rsa_private_encrypt, 3) ->
+ {deprecated, {crypto, private_encrypt, 4}};
+obsolete_1(crypto, rsa_public_encrypt, 3) ->
+ {deprecated, {crypto, public_encrypt, 4}};
+
+obsolete_1(crypto, des_cfb_ivec, 2) ->
+ {deprecated, {crypto, next_iv, 3}};
+obsolete_1(crypto,des_cbc_ivec, 1) ->
+ {deprecated, {crypto, next_iv, 2}};
+obsolete_1(crypto, aes_cbc_ivec, 1) ->
+ {deprecated, {crypto, next_iv, 2}};
+
+obsolete_1(crypto,info, 0) ->
+ {deprecated, {crypto, module_info, 0}};
+
+obsolete_1(crypto, strong_rand_mpint, 3) ->
+ {deprecated, "needed only by deprecated functions"};
+obsolete_1(crypto, erlint, 1) ->
+ {deprecated, "needed only by deprecated functions"};
+obsolete_1(crypto, mpint, 1) ->
+ {deprecated, "needed only by deprecated functions"};
+
+
%% *** SNMP ***
obsolete_1(snmp, N, A) ->
@@ -73,10 +250,12 @@ obsolete_1(snmp, N, A) ->
false ->
no;
true ->
- {deprecated,"Deprecated; use snmpa:"++atom_to_list(N)++"/"++
+ {deprecated, "Deprecated (will be removed in R17B); use snmpa:"++atom_to_list(N)++"/"++
integer_to_list(A)++" instead"}
end;
+obsolete_1(snmpa, old_info_format, 1) ->
+ {deprecated, "Deprecated; (will be removed in R17B); use \"new\" format instead"};
obsolete_1(snmpm, agent_info, 3) ->
{removed, {snmpm, agent_info, 2}, "R16B"};
obsolete_1(snmpm, update_agent_info, 5) ->
diff --git a/lib/stdlib/test/c_SUITE.erl b/lib/stdlib/test/c_SUITE.erl
index 25281365be..8c55b616b9 100644
--- a/lib/stdlib/test/c_SUITE.erl
+++ b/lib/stdlib/test/c_SUITE.erl
@@ -20,7 +20,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
-export([c_1/1, c_2/1, c_3/1, c_4/1, nc_1/1, nc_2/1, nc_3/1, nc_4/1,
- memory/1]).
+ ls/1, memory/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -29,7 +29,7 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [c_1, c_2, c_3, c_4, nc_1, nc_2, nc_3, nc_4, memory].
+ [c_1, c_2, c_3, c_4, nc_1, nc_2, nc_3, nc_4, ls, memory].
groups() ->
[].
@@ -147,6 +147,13 @@ nc_4(Config) when is_list(Config) ->
?line Result = nc(R,[{outdir,W}]),
?line {ok, m} = Result.
+ls(Config) when is_list(Config) ->
+ Directory = ?config(data_dir, Config),
+ ok = c:ls(Directory),
+ File = filename:join(Directory, "m.erl"),
+ ok = c:ls(File),
+ ok = c:ls("no_such_file").
+
memory(doc) ->
["Checks that c:memory/[0,1] returns consistent results."];
memory(suite) ->
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index b2f1aa955a..0cbdf76270 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -104,6 +104,8 @@ include_local(suite) ->
include_local(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir, Config),
?line File = filename:join(DataDir, "include_local.erl"),
+ FooHrl = filename:join([DataDir,"include","foo.hrl"]),
+ BarHrl = filename:join([DataDir,"include","bar.hrl"]),
%% include_local.erl includes include/foo.hrl which
%% includes bar.hrl (also in include/) without requiring
%% any additional include path, and overriding any file
@@ -111,6 +113,8 @@ include_local(Config) when is_list(Config) ->
?line {ok, List} = epp:parse_file(File, [DataDir], []),
?line {value, {attribute,_,a,{true,true}}} =
lists:keysearch(a,3,List),
+ [{File,1},{FooHrl,1},{BarHrl,1},{FooHrl,5},{File,5}] =
+ [ FileLine || {attribute,_,file,FileLine} <- List ],
ok.
%%% Here is a little reimplementation of epp:parse_file, which times out
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index 9c0a43abcc..2b7cec87df 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -43,13 +43,13 @@
receive_after/1, bits/1, head_tail/1,
cond1/1, block/1, case1/1, ops/1, messages/1,
old_mnemosyne_syntax/1,
- import_export/1, misc_attrs/1,
+ import_export/1, misc_attrs/1, dialyzer_attrs/1,
hook/1,
neg_indent/1,
otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1,
otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1,
- otp_10302/1, otp_10820/1]).
+ otp_10302/1, otp_10820/1, otp_11100/1]).
%% Internal export.
-export([ehook/6]).
@@ -77,11 +77,11 @@ groups() ->
[func, call, recs, try_catch, if_then, receive_after,
bits, head_tail, cond1, block, case1, ops,
messages, old_mnemosyne_syntax]},
- {attributes, [], [misc_attrs, import_export]},
+ {attributes, [], [misc_attrs, import_export, dialyzer_attrs]},
{tickets, [],
[otp_6321, otp_6911, otp_6914, otp_8150, otp_8238,
otp_8473, otp_8522, otp_8567, otp_8664, otp_9147,
- otp_10302, otp_10820]}].
+ otp_10302, otp_10820, otp_11100]}].
init_per_suite(Config) ->
Config.
@@ -597,6 +597,15 @@ misc_attrs(Config) when is_list(Config) ->
ok.
+dialyzer_attrs(suite) ->
+ [];
+dialyzer_attrs(Config) when is_list(Config) ->
+ ok = pp_forms(<<"-type foo() :: #bar{}. ">>),
+ ok = pp_forms(<<"-opaque foo() :: {bar, fun((X, [42,...]) -> X)}. ">>),
+ ok = pp_forms(<<"-spec foo(bar(), qux()) -> [T | baz(T)]. ">>),
+ ok = pp_forms(<<"-callback foo(<<_:32,_:_*4>>, T) -> T. ">>),
+ ok.
+
hook(suite) ->
[];
hook(Config) when is_list(Config) ->
@@ -1103,6 +1112,45 @@ file_attr_is_string("-file(\"" ++ _) -> true;
file_attr_is_string([_ | L]) ->
file_attr_is_string(L).
+otp_11100(doc) ->
+ "OTP-11100. Fix printing of invalid forms.";
+otp_11100(suite) -> [];
+otp_11100(Config) when is_list(Config) ->
+ %% There are a few places where the added code ("options(none)")
+ %% doesn't make a difference (pp:bit_elem_type/1 is an example).
+
+ %% Cannot trigger the use of the hook function with export/import.
+ "-export([{fy,a}/b]).\n" =
+ pf({attribute,1,export,[{{fy,a},b}]}),
+ "-type foo() :: integer(INVALID-FORM:{foo,bar}:).\n" =
+ pf({attribute,1,type,{foo,{type,1,integer,[{foo,bar}]},[]}}),
+ pf({attribute,1,type,
+ {a,{type,1,range,[{integer,1,1},{foo,bar}]},[]}}),
+ "-type foo(INVALID-FORM:{foo,bar}:) :: A.\n" =
+ pf({attribute,1,type,{foo,{var,1,'A'},[{foo,bar}]}}),
+ "-type foo() :: (INVALID-FORM:{foo,bar}: :: []).\n" =
+ pf({attribute,1,type,
+ {foo,{paren_type,1,
+ [{ann_type,1,[{foo,bar},{type,1,nil,[]}]}]},
+ []}}),
+ "-type foo() :: <<_:INVALID-FORM:{foo,bar}:>>.\n" =
+ pf({attribute,1,type,
+ {foo,{type,1,binary,[{foo,bar},{integer,1,0}]},[]}}),
+ "-type foo() :: <<_:10, _:_*INVALID-FORM:{foo,bar}:>>.\n" =
+ pf({attribute,1,type,
+ {foo,{type,1,binary,[{integer,1,10},{foo,bar}]},[]}}),
+ "-type foo() :: #r{INVALID-FORM:{foo,bar}: :: integer()}.\n" =
+ pf({attribute,1,type,
+ {foo,{type,1,record,
+ [{atom,1,r},
+ {type,1,field_type,
+ [{foo,bar},{type,1,integer,[]}]}]},
+ []}}),
+ ok.
+
+pf(Form) ->
+ lists:flatten(erl_pp:form(Form,none)).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
compile(Config, Tests) ->
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index af5d5a8f21..2b29566942 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -75,6 +75,7 @@
-export([otp_9932/1]).
-export([otp_9423/1]).
-export([otp_10182/1]).
+-export([memory_check_summary/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
%% Convenience for manual testing
@@ -149,7 +150,9 @@ all() ->
give_away, setopts, bad_table, types,
otp_10182,
otp_9932,
- otp_9423].
+ otp_9423,
+
+ memory_check_summary]. % MUST BE LAST
groups() ->
[{new, [],
@@ -185,7 +188,8 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
stop_spawn_logger(),
- catch erts_debug:set_internal_state(available_internal_state, false).
+ catch erts_debug:set_internal_state(available_internal_state, false),
+ ok.
init_per_group(_GroupName, Config) ->
Config.
@@ -193,6 +197,26 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+%% Test that we did not have "too many" failed verify_etsmem()'s
+%% in the test suite.
+%% verify_etsmem() may give a low number of false positives
+%% as concurrent activities, such as lingering processes
+%% from earlier test suites, may do unrelated ets (de)allocations.
+memory_check_summary(_Config) ->
+ case whereis(ets_test_spawn_logger) of
+ undefined ->
+ ?t:fail("No spawn logger exist");
+ _ ->
+ ets_test_spawn_logger ! {self(), get_failed_memchecks},
+ receive {get_failed_memchecks, FailedMemchecks} -> ok end,
+ io:format("Failed memchecks: ~p\n",[FailedMemchecks]),
+ if FailedMemchecks > 3 ->
+ ct:fail("Too many failed (~p) memchecks", [FailedMemchecks]);
+ true ->
+ ok
+ end
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -5602,17 +5626,25 @@ etsmem() ->
MemInfo ->
CS = lists:foldl(
fun ({instance, _, L}, Acc) ->
- {value,{_,SBMBCS}} = lists:keysearch(sbmbcs, 1, L),
- {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L),
- {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L),
- [SBMBCS,MBCS,SBCS | Acc]
+ {value,{mbcs,MBCS}} = lists:keysearch(mbcs, 1, L),
+ {value,{sbcs,SBCS}} = lists:keysearch(sbcs, 1, L),
+ NewAcc = [MBCS, SBCS | Acc],
+ case lists:keysearch(mbcs_pool, 1, L) of
+ {value,{mbcs_pool, MBCS_POOL}} ->
+ [MBCS_POOL|NewAcc];
+ _ -> NewAcc
+ end
end,
[],
MemInfo),
lists:foldl(
fun(L, {Bl0,BlSz0}) ->
- {value,{_,Bl,_,_}} = lists:keysearch(blocks, 1, L),
- {value,{_,BlSz,_,_}} = lists:keysearch(blocks_size, 1, L),
+ {value,BlTup} = lists:keysearch(blocks, 1, L),
+ blocks = element(1, BlTup),
+ Bl = element(2, BlTup),
+ {value,BlSzTup} = lists:keysearch(blocks_size, 1, L),
+ blocks_size = element(1, BlSzTup),
+ BlSz = element(2, BlSzTup),
{Bl0+Bl,BlSz0+BlSz}
end, {0,0}, CS)
end},
@@ -5635,7 +5667,8 @@ verify_etsmem({MemInfo,AllTabs}) ->
io:format("Actual: ~p", [MemInfo2]),
io:format("Changed tables before: ~p\n",[AllTabs -- AllTabs2]),
io:format("Changed tables after: ~p\n", [AllTabs2 -- AllTabs]),
- ?t:fail()
+ ets_test_spawn_logger ! failed_memcheck,
+ {comment, "Failed memory check"}
end.
@@ -5657,10 +5690,10 @@ stop_loopers(Loopers) ->
looper(Fun, State) ->
looper(Fun, Fun(State)).
-spawn_logger(Procs) ->
+spawn_logger(Procs, FailedMemchecks) ->
receive
{new_test_proc, Proc} ->
- spawn_logger([Proc|Procs]);
+ spawn_logger([Proc|Procs], FailedMemchecks);
{sync_test_procs, Kill, From} ->
lists:foreach(fun (Proc) when From == Proc ->
ok;
@@ -5683,7 +5716,14 @@ spawn_logger(Procs) ->
end
end, Procs),
From ! test_procs_synced,
- spawn_logger([From])
+ spawn_logger([From], FailedMemchecks);
+
+ failed_memcheck ->
+ spawn_logger(Procs, FailedMemchecks+1);
+
+ {Pid, get_failed_memchecks} ->
+ Pid ! {get_failed_memchecks, FailedMemchecks},
+ spawn_logger(Procs, FailedMemchecks)
end.
pid_status(Pid) ->
@@ -5699,7 +5739,7 @@ start_spawn_logger() ->
case whereis(ets_test_spawn_logger) of
Pid when is_pid(Pid) -> true;
_ -> register(ets_test_spawn_logger,
- spawn_opt(fun () -> spawn_logger([]) end,
+ spawn_opt(fun () -> spawn_logger([], 0) end,
[{priority, max}]))
end.
@@ -5710,8 +5750,7 @@ start_spawn_logger() ->
stop_spawn_logger() ->
Mon = erlang:monitor(process, ets_test_spawn_logger),
(catch exit(whereis(ets_test_spawn_logger), kill)),
- receive {'DOWN', Mon, _, _, _} -> ok end,
- ok.
+ receive {'DOWN', Mon, _, _, _} -> ok end.
wait_for_test_procs() ->
wait_for_test_procs(false).
@@ -5811,7 +5850,7 @@ spawn_monitor_with_pid(Pid, Fun, N) ->
end) of
Pid ->
{Pid, erlang:monitor(process, Pid)};
- Other ->
+ _Other ->
spawn_monitor_with_pid(Pid,Fun,N-1)
end.
@@ -6117,11 +6156,18 @@ repeat_for_opts(F, OptGenList) ->
repeat_for_opts(F, OptGenList, []).
repeat_for_opts(F, [], Acc) ->
- lists:map(fun(Opts) ->
- OptList = lists:filter(fun(E) -> E =/= void end, Opts),
- io:format("Calling with options ~p\n",[OptList]),
- F(OptList)
- end, Acc);
+ lists:foldl(fun(Opts, RV_Acc) ->
+ OptList = lists:filter(fun(E) -> E =/= void end, Opts),
+ io:format("Calling with options ~p\n",[OptList]),
+ RV = F(OptList),
+ case RV_Acc of
+ {comment,_} -> RV_Acc;
+ _ -> case RV of
+ {comment,_} -> RV;
+ _ -> [RV | RV_Acc]
+ end
+ end
+ end, [], Acc);
repeat_for_opts(F, [OptList | Tail], []) when is_list(OptList) ->
repeat_for_opts(F, Tail, [[Opt] || Opt <- OptList]);
repeat_for_opts(F, [OptList | Tail], AccList) when is_list(OptList) ->
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index 3b6a3f38bc..a360a0809b 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -1082,13 +1082,23 @@ replace_state(Config) when is_list(Config) ->
%% Test that the time for a huge message queue is not
%% significantly slower than with an empty message queue.
call_with_huge_message_queue(Config) when is_list(Config) ->
+ case test_server:is_native(gen) of
+ true ->
+ {skip,
+ "gen is native - huge message queue optimization "
+ "is not implemented"};
+ false ->
+ do_call_with_huge_message_queue()
+ end.
+
+do_call_with_huge_message_queue() ->
?line Pid = spawn_link(fun echo_loop/0),
- ?line {Time,ok} = tc(fun() -> calls(10, Pid) end),
+ ?line {Time,ok} = tc(fun() -> calls(10000, Pid) end),
?line [self() ! {msg,N} || N <- lists:seq(1, 500000)],
erlang:garbage_collect(),
- ?line {NewTime,ok} = tc(fun() -> calls(10, Pid) end),
+ ?line {NewTime,ok} = tc(fun() -> calls(10000, Pid) end),
io:format("Time for empty message queue: ~p", [Time]),
io:format("Time for huge message queue: ~p", [NewTime]),
diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl
index b56f0b39d8..cd7210f8ec 100644
--- a/lib/stdlib/test/lists_SUITE.erl
+++ b/lib/stdlib/test/lists_SUITE.erl
@@ -2532,8 +2532,8 @@ otp_5939(Config) when is_list(Config) ->
?line [] = lists:filter(Pred, []),
?line {'EXIT', _} = (catch lists:partition(func, [])),
?line {[],[]} = lists:partition(Pred, []),
- ?line {'EXIT', _} = (catch lists:zf(func, [])),
- ?line [] = lists:zf(Fun1, []),
+ ?line {'EXIT', _} = (catch lists:filtermap(func, [])),
+ ?line [] = lists:filtermap(Fun1, []),
?line {'EXIT', _} = (catch lists:foreach(func, [])),
?line ok = lists:foreach(Fun1, []),
?line {'EXIT', _} = (catch lists:mapfoldl(func, [], [])),
diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl
index 7233c061ef..a57641ef62 100644
--- a/lib/stdlib/test/zip_SUITE.erl
+++ b/lib/stdlib/test/zip_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2013. 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
@@ -109,13 +109,32 @@ borderline_test(Size, TempDir) ->
ok.
unzip_list(Archive, Name) ->
- case os:find_executable("unzip") of
- Unzip when is_list(Unzip) ->
+ case unix_unzip_exists() of
+ true ->
unzip_list1(Archive, Name);
_ ->
ok
end.
+%% Used to do os:find_executable() to check if unzip exists, but on
+%% some hosts that would give an unzip program which did not take the
+%% "-Z" option.
+%% Here we check that "unzip -Z" (which should display usage) and
+%% check that it exists with status 0.
+unix_unzip_exists() ->
+ case os:type() of
+ {unix,_} ->
+ Port = open_port({spawn,"unzip -Z > /dev/null"}, [exit_status]),
+ receive
+ {Port,{exit_status,0}} ->
+ true;
+ {Port,{exit_status,_Fail}} ->
+ false
+ end;
+ _ ->
+ false
+ end.
+
unzip_list1(Archive, Name) ->
Expect = Name ++ "\n",
cmd_expect("unzip -Z -1 " ++ Archive, Expect).