diff options
Diffstat (limited to 'lib/stdlib')
-rw-r--r-- | lib/stdlib/doc/src/c.xml | 4 | ||||
-rw-r--r-- | lib/stdlib/doc/src/erl_eval.xml | 5 | ||||
-rw-r--r-- | lib/stdlib/doc/src/lists.xml | 25 | ||||
-rw-r--r-- | lib/stdlib/src/beam_lib.erl | 18 | ||||
-rw-r--r-- | lib/stdlib/src/c.erl | 6 | ||||
-rw-r--r-- | lib/stdlib/src/epp.erl | 2 | ||||
-rw-r--r-- | lib/stdlib/src/erl_eval.erl | 64 | ||||
-rw-r--r-- | lib/stdlib/src/erl_lint.erl | 137 | ||||
-rw-r--r-- | lib/stdlib/src/erl_pp.erl | 41 | ||||
-rw-r--r-- | lib/stdlib/src/lists.erl | 24 | ||||
-rw-r--r-- | lib/stdlib/src/otp_internal.erl | 181 | ||||
-rw-r--r-- | lib/stdlib/test/c_SUITE.erl | 11 | ||||
-rw-r--r-- | lib/stdlib/test/epp_SUITE.erl | 4 | ||||
-rw-r--r-- | lib/stdlib/test/erl_pp_SUITE.erl | 56 | ||||
-rw-r--r-- | lib/stdlib/test/ets_SUITE.erl | 88 | ||||
-rw-r--r-- | lib/stdlib/test/gen_server_SUITE.erl | 16 | ||||
-rw-r--r-- | lib/stdlib/test/lists_SUITE.erl | 4 | ||||
-rw-r--r-- | lib/stdlib/test/zip_SUITE.erl | 25 |
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). |