diff options
Diffstat (limited to 'lib/stdlib')
38 files changed, 1178 insertions, 556 deletions
diff --git a/lib/stdlib/doc/src/erl_parse.xml b/lib/stdlib/doc/src/erl_parse.xml index 0938b5dec3..13be488c33 100644 --- a/lib/stdlib/doc/src/erl_parse.xml +++ b/lib/stdlib/doc/src/erl_parse.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2015</year> + <year>1996</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -44,21 +44,33 @@ </description> <datatypes> <datatype> - <name name="abstract_clause"></name> - <desc><p>Parse tree for Erlang clause.</p> + <name>abstract_clause()</name> + <desc><p><marker id="type-abstract_clause"/> + Abstract form of an Erlang clause.</p> </desc> </datatype> <datatype> - <name name="abstract_expr"></name> - <desc><p>Parse tree for Erlang expression.</p> + <name>abstract_expr()</name> + <desc><p><marker id="type-abstract_expr"/> + Abstract form of an Erlang expression.</p> </desc> </datatype> <datatype> - <name name="abstract_form"></name> - <desc><p>Parse tree for Erlang form.</p> + <name>abstract_form()</name> + <desc><p><marker id="type-abstract_form"/> + Abstract form of an Erlang form.</p> </desc> </datatype> <datatype> + <name>abstract_type()</name> + <desc><p><marker id="type-abstract_type"/> + Abstract form of an Erlang type.</p> + </desc> + </datatype> + <datatype> + <name name="erl_parse_tree"></name> + </datatype> + <datatype> <name name="error_description"></name> </datatype> <datatype> @@ -180,7 +192,7 @@ <p>Converts the Erlang data structure <c><anno>Data</anno></c> into an abstract form of type <c><anno>AbsTerm</anno></c>.</p> <p>The <c><anno>Line</anno></c> option is the line that will - be assigned to each node of the abstract form.</p> + be assigned to each node of <c><anno>AbsTerm</anno></c>.</p> <p>The <c><anno>Encoding</anno></c> option is used for selecting which integer lists will be considered as strings. The default is to use the encoding returned by @@ -196,47 +208,53 @@ <func> <name name="map_anno" arity="2"/> <fsummary> - Map a function over the annotations of an abstract form + Map a function over the annotations of a <c>erl_parse</c> tree </fsummary> <desc> - <p>Modifies the abstract form <anno>Abstr</anno> by applying - <anno>Fun</anno> on every collection of annotations of the - abstract form. The abstract form is traversed in a - depth-first, left-to-right, fashion. + <p>Modifies the <c>erl_parse</c> tree <c><anno>Abstr</anno></c> + by applying <c><anno>Fun</anno></c> on each collection of + annotations of the nodes of the <c>erl_parse</c> tree. The + <c>erl_parse</c> tree is traversed in a depth-first, + left-to-right, fashion. </p> </desc> </func> <func> <name name="fold_anno" arity="3"/> <fsummary> - Fold a function over the annotations of an abstract form + Fold a function over the annotations of a <c>erl_parse</c> tree </fsummary> <desc> - <p>Updates an accumulator by applying <anno>Fun</anno> on - every collection of annotations of the abstract form - <anno>Abstr</anno>. The first call to <anno>Fun</anno> has - <anno>AccIn</anno> as argument, and the returned accumulator - <anno>AccOut</anno> is passed to the next call, and so on. - The final value of the accumulator is returned. The abstract - form is traversed in a depth-first, left-to-right, fashion. + <p>Updates an accumulator by applying <c><anno>Fun</anno></c> on + each collection of annotations of the <c>erl_parse</c> tree + <c><anno>Abstr</anno></c>. The first call to + <c><anno>Fun</anno></c> has <c><anno>AccIn</anno></c> as + argument, and the returned accumulator + <c><anno>AccOut</anno></c> is passed to the next call, and + so on. The final value of the accumulator is returned. The + <c>erl_parse</c> tree is traversed in a depth-first, left-to-right, + fashion. </p> </desc> </func> <func> <name name="mapfold_anno" arity="3"/> <fsummary> - Map and fold a function over the annotations of an abstract form + Map and fold a function over the annotations of a + <c>erl_parse</c> tree </fsummary> <desc> - <p>Modifies the abstract form <anno>Abstr</anno> by applying - <anno>Fun</anno> on every collection of annotations of the - abstract form, while at the same time updating an - accumulator. The first call to <anno>Fun</anno> has - <anno>AccIn</anno> as second argument, and the returned - accumulator <anno>AccOut</anno> is passed to the next call, - and so on. The modified abstract form as well as the the - final value of the accumulator is returned. The abstract - form is traversed in a depth-first, left-to-right, fashion. + <p>Modifies the <c>erl_parse</c> tree <c><anno>Abstr</anno></c> + by applying <c><anno>Fun</anno></c> on each collection of + annotations of the nodes of the <c>erl_parse</c> tree, while + at the same time updating an accumulator. The first call to + <c><anno>Fun</anno></c> has <c><anno>AccIn</anno></c> as + second argument, and the returned accumulator + <c><anno>AccOut</anno></c> is passed to the next call, and + so on. The modified <c>erl_parse</c> tree as well as the the + final value of the accumulator are returned. The + <c>erl_parse</c> tree is traversed in a depth-first, + left-to-right, fashion. </p> </desc> </func> @@ -246,12 +264,15 @@ Create new annotations </fsummary> <desc> - <p>Creates an abstract form from a term which has the same - structure as an abstract form, but <seealso - marker="erl_anno#type-location">locations</seealso> where the - abstract form has annotations. For each location, <seealso - marker="erl_anno#new/1"><c>erl_anno:new/1</c></seealso> is - called, and the annotations replace the location. + <p>Assumes that <c><anno>Term</anno></c> is a term with the same + structure as a <c>erl_parse</c> tree, but with <seealso + marker="erl_anno#type-location">locations</seealso> where a + <c>erl_parse</c> tree has collections of annotations. + Returns a <c>erl_parse</c> tree where each location <c>L</c> + has been replaced by the value returned by <seealso + marker="erl_anno#new/1"><c>erl_anno:new(L)</c></seealso>. + The term <c><anno>Term</anno></c> is traversed in a + depth-first, left-to-right, fashion. </p> </desc> </func> @@ -261,12 +282,14 @@ Return annotations as terms </fsummary> <desc> - <p>Assumes that <anno>Term</anno> is a term with the same - structure as an abstract form, but with terms, T say, on - those places where an abstract form has annotations. Returns - an abstract form where every term T has been replaced by the - value returned by calling <c>erl_anno:from_term(T)</c>. The - term <anno>Term</anno> is traversed in a depth-first, + <p>Assumes that <c><anno>Term</anno></c> is a term with the same + structure as a <c>erl_parse</c> tree, but with terms, + <c>T</c> say, where a <c>erl_parse</c> tree has collections + of annotations. Returns a <c>erl_parse</c> tree where each + term <c>T</c> has been replaced by the value returned by + <seealso marker="erl_anno#from_term/1"> + <c>erl_anno:from_term(T)</c></seealso>. The term + <c><anno>Term</anno></c> is traversed in a depth-first, left-to-right, fashion. </p> </desc> @@ -277,10 +300,13 @@ Return the representation of annotations </fsummary> <desc> - <p>Returns a term where every collection of annotations Anno of - <anno>Abstr</anno> has been replaced by the term returned by - calling <c>erl_anno:to_term(Anno)</c>. The abstract form is - traversed in a depth-first, left-to-right, fashion. + <p>Returns a term where each collection of annotations + <c>Anno</c> of the nodes of the <c>erl_parse</c> tree + <c><anno>Abstr</anno></c> has been replaced by the term + returned by <seealso marker="erl_anno#to_term/1"> + <c>erl_anno:to_term(Anno)</c></seealso>. The + <c>erl_parse</c> tree is traversed in a depth-first, + left-to-right, fashion. </p> </desc> </func> diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml index c84ca9c8ad..267a993a1b 100644 --- a/lib/stdlib/doc/src/notes.xml +++ b/lib/stdlib/doc/src/notes.xml @@ -31,6 +31,67 @@ </header> <p>This document describes the changes made to the STDLIB application.</p> +<section><title>STDLIB 2.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>The Erlang Pretty Printer uses <c>::</c> for function + type constraints.</p> <p>A bug concerning pretty printing + of annotated type union elements in map pair types has + been fixed.</p> <p>Some minor issues regarding the + documentation of types and specs have been corrected.</p> + <p> + Own Id: OTP-13084</p> + </item> + <item> + <p> The shell command <c>rp</c> prints strings as lists + of integers if pretty printing of lists is set to + <c>false</c>. </p> + <p> + Own Id: OTP-13145</p> + </item> + <item> + <p> + The shell would crash if a bit syntax expression with + conflicting types were given (e.g. if a field type was + given as '<c>integer-binary</c>'). (Thanks to Aleksei + Magusev for reporting this bug.)</p> + <p> + Own Id: OTP-13157</p> + </item> + <item> + <p>The <c>rand:export_seed/0</c> would never return + '<c>undefined</c>' even if no seed has previously been + created. Fixed to return '<c>undefined</c>' if there is + no seed in the process dictionary.</p> + <p> + Own Id: OTP-13162</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add support for the Delete, Home and End keys in the + Erlang shell.</p> + <p> + Own Id: OTP-13032</p> + </item> + <item> + <p><c>beam_lib:all_chunks/1</c> and + <c>beam_lib:build_module/1</c> have been documented.</p> + <p> + Own Id: OTP-13063</p> + </item> + </list> + </section> + +</section> + <section><title>STDLIB 2.6</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/stdlib/doc/src/rand.xml b/lib/stdlib/doc/src/rand.xml index e7d4728ef7..50057259c6 100644 --- a/lib/stdlib/doc/src/rand.xml +++ b/lib/stdlib/doc/src/rand.xml @@ -104,7 +104,7 @@ strong. If a strong cryptographic random number generator is needed, use one of functions in the <seealso marker="crypto:crypto">crypto</seealso> - module, for example <c>crypto:rand_bytes/1</c>.</p></note> + module, for example <c>crypto:strong_rand_bytes/1</c>.</p></note> </description> <datatypes> <datatype> diff --git a/lib/stdlib/doc/src/random.xml b/lib/stdlib/doc/src/random.xml index d3d7c90c31..fc4f796863 100644 --- a/lib/stdlib/doc/src/random.xml +++ b/lib/stdlib/doc/src/random.xml @@ -48,7 +48,7 @@ tuple of three integers.</p> <p>It should be noted that this random number generator is not cryptographically strong. If a strong cryptographic random number generator is needed for - example <c>crypto:rand_bytes/1</c> could be used instead.</p> + example <c>crypto:strong_rand_bytes/1</c> could be used instead.</p> <note><p>The new and improved <seealso marker="stdlib:rand">rand</seealso> module should be used instead of this module.</p></note> diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl index 6d07f4018a..6887bda67c 100644 --- a/lib/stdlib/src/dets.erl +++ b/lib/stdlib/src/dets.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2014. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -1124,7 +1124,9 @@ repl({delayed_write, {Delay,Size} = C}, Defs) Defs#open_args{delayed_write = C}; repl({estimated_no_objects, I}, Defs) -> repl({min_no_slots, I}, Defs); -repl({file, File}, Defs) -> +repl({file, File}, Defs) when is_list(File) -> + Defs#open_args{file = File}; +repl({file, File}, Defs) when is_atom(File) -> Defs#open_args{file = to_list(File)}; repl({keypos, P}, Defs) when is_integer(P), P > 0 -> Defs#open_args{keypos =P}; @@ -1289,7 +1291,15 @@ init(Parent, Server) -> open_file_loop(#head{parent = Parent, server = Server}). open_file_loop(Head) -> - open_file_loop(Head, 0). + %% The Dets server pretends the file is open before + %% internal_open() has been called, which means that unless the + %% internal_open message is applied first, other processes can + %% find the pid by calling dets_server:get_pid() and do things + %% before Head has been initialized properly. + receive + ?DETS_CALL(From, {internal_open, _Ref, _Args}=Op) -> + do_apply_op(Op, From, Head, 0) + end. open_file_loop(Head, N) when element(1, Head#head.update_mode) =:= error -> open_file_loop2(Head, N); diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl index c8bba579cc..45f616bb02 100644 --- a/lib/stdlib/src/epp.erl +++ b/lib/stdlib/src/epp.erl @@ -40,7 +40,7 @@ -type ifdef() :: 'ifdef' | 'ifndef' | 'else'. --type name() :: {'atom', atom()}. +-type name() :: atom(). -type argspec() :: 'none' %No arguments | non_neg_integer(). %Number of arguments -type tokens() :: [erl_scan:token()]. @@ -58,21 +58,14 @@ istk=[] :: [ifdef()], %Ifdef stack sstk=[] :: [#epp{}], %State stack path=[] :: [file:name()], %Include-path - macs = dict:new() %Macros (don't care locations) - :: dict:dict(name(), {argspec(), tokens()}), - uses = dict:new() %Macro use structure - :: dict:dict(name(), [{argspec(), [used()]}]), + macs = #{} %Macros (don't care locations) + :: #{name() => {argspec(), tokens()}}, + uses = #{} %Macro use structure + :: #{name() => [{argspec(), [used()]}]}, default_encoding = ?DEFAULT_ENCODING :: source_encoding(), pre_opened = false :: boolean() }). -%%% Note on representation: as tokens, both {var, Location, Name} and -%%% {atom, Location, Name} can occur as macro identifiers. However, keeping -%%% this distinction here is done for historical reasons only: previously, -%%% ?FOO and ?'FOO' were not the same, but now they are. Removing the -%%% distinction in the internal representation would simplify the code -%%% a little. - %% open(Options) %% open(FileName, IncludePath) %% open(FileName, IncludePath, PreDefMacros) @@ -550,7 +543,8 @@ init_server(Pid, Name, Options, St0) -> default_encoding=DefEncoding}, From = wait_request(St), Anno = erl_anno:new(AtLocation), - enter_file_reply(From, Name, Anno, AtLocation, code), + enter_file_reply(From, file_name(Name), Anno, + AtLocation, code), wait_req_scan(St); {error,E} -> epp_reply(Pid, {error,E}) @@ -561,18 +555,18 @@ init_server(Pid, Name, Options, St0) -> %% FILE, LINE, MODULE as undefined, MACHINE and MACHINE value. predef_macros(File) -> - Machine = list_to_atom(erlang:system_info(machine)), - Anno = line1(), - dict:from_list([ - {{atom,'FILE'}, {none,[{string,Anno,File}]}}, - {{atom,'LINE'}, {none,[{integer,Anno,1}]}}, - {{atom,'MODULE'}, undefined}, - {{atom,'MODULE_STRING'}, undefined}, - {{atom,'BASE_MODULE'}, undefined}, - {{atom,'BASE_MODULE_STRING'}, undefined}, - {{atom,'MACHINE'}, {none,[{atom,Anno,Machine}]}}, - {{atom,Machine}, {none,[{atom,Anno,true}]}} - ]). + Machine = list_to_atom(erlang:system_info(machine)), + Anno = line1(), + Defs = [{'FILE', {none,[{string,Anno,File}]}}, + {'LINE', {none,[{integer,Anno,1}]}}, + {'MODULE', undefined}, + {'MODULE_STRING', undefined}, + {'BASE_MODULE', undefined}, + {'BASE_MODULE_STRING', undefined}, + {'MACHINE', {none,[{atom,Anno,Machine}]}}, + {Machine, {none,[{atom,Anno,true}]}} + ], + maps:from_list(Defs). %% user_predef(PreDefMacros, Macros) -> %% {ok,MacroDict} | {error,E} @@ -581,28 +575,21 @@ predef_macros(File) -> user_predef([{M,Val,redefine}|Pdm], Ms) when is_atom(M) -> Exp = erl_parse:tokens(erl_parse:abstract(Val)), - user_predef(Pdm, dict:store({atom,M}, {none,Exp}, Ms)); + user_predef(Pdm, Ms#{M=>{none,Exp}}); user_predef([{M,Val}|Pdm], Ms) when is_atom(M) -> - case dict:find({atom,M}, Ms) of - {ok,_Defs} when is_list(_Defs) -> %% User defined macros + case Ms of + #{M:=Defs} when is_list(Defs) -> + %% User defined macros. {error,{redefine,M}}; - {ok,_Def} -> %% Predefined macros + #{M:=_Defs} -> + %% Predefined macros. {error,{redefine_predef,M}}; - error -> + _ -> Exp = erl_parse:tokens(erl_parse:abstract(Val)), - user_predef(Pdm, dict:store({atom,M}, [{none, {none,Exp}}], Ms)) + user_predef(Pdm, Ms#{M=>[{none,{none,Exp}}]}) end; user_predef([M|Pdm], Ms) when is_atom(M) -> - case dict:find({atom,M}, Ms) of - {ok,_Defs} when is_list(_Defs) -> %% User defined macros - {error,{redefine,M}}; - {ok,_Def} -> %% Predefined macros - {error,{redefine_predef,M}}; - error -> - A = line1(), - user_predef(Pdm, - dict:store({atom,M}, [{none, {none,[{atom,A,true}]}}], Ms)) - end; + user_predef([{M,true}|Pdm], Ms); user_predef([Md|_Pdm], _Ms) -> {error,{bad,Md}}; user_predef([], Ms) -> {ok,Ms}. @@ -616,7 +603,9 @@ wait_request(St) -> receive {epp_request,From,scan_erl_form} -> From; {epp_request,From,macro_defs} -> - epp_reply(From, dict:to_list(St#epp.macs)), + %% Return the old format to avoid any incompability issues. + Defs = [{{atom,K},V} || {K,V} <- maps:to_list(St#epp.macs)], + epp_reply(From, Defs), wait_request(St); {epp_request,From,close} -> close_file(St), @@ -668,7 +657,8 @@ enter_file(NewName, Inc, From, St) -> enter_file2(NewF, Pname, From, St0, AtLocation) -> Anno = erl_anno:new(AtLocation), enter_file_reply(From, Pname, Anno, AtLocation, code), - Ms = dict:store({atom,'FILE'}, {none,[{string,Anno,Pname}]}, St0#epp.macs), + Ms0 = St0#epp.macs, + Ms = Ms0#{'FILE':={none,[{string,Anno,Pname}]}}, %% update the head of the include path to be the directory of the new %% source file, so that an included file can always include other files %% relative to its current location (this is also how C does it); note @@ -689,7 +679,7 @@ enter_file_reply(From, Name, LocationAnno, AtLocation, Where) -> generated -> erl_anno:set_generated(true, Anno0) end, Rep = {ok, [{'-',Anno},{atom,Anno,file},{'(',Anno}, - {string,Anno,file_name(Name)},{',',Anno}, + {string,Anno,Name},{',',Anno}, {integer,Anno,get_line(LocationAnno)},{')',LocationAnno}, {dot,Anno}]}, epp_reply(From, Rep). @@ -720,9 +710,8 @@ leave_file(From, St) -> name2=OldName2} = OldSt, CurrLoc = add_line(OldLoc, Delta), Anno = erl_anno:new(CurrLoc), - Ms = dict:store({atom,'FILE'}, - {none,[{string,Anno,OldName2}]}, - St#epp.macs), + Ms0 = St#epp.macs, + Ms = Ms0#{'FILE':={none,[{string,Anno,OldName2}]}}, NextSt = OldSt#epp{sstk=Sts,macs=Ms,uses=St#epp.uses}, enter_file_reply(From, OldName, Anno, CurrLoc, code), case OldName2 =:= OldName of @@ -797,91 +786,48 @@ scan_toks(Toks0, From, St) -> end. scan_module([{'-',_Lh},{atom,_Lm,module},{'(',_Ll}|Ts], Ms) -> - scan_module_1(Ts, [], Ms); + scan_module_1(Ts, Ms); scan_module([{'-',_Lh},{atom,_Lm,extends},{'(',_Ll}|Ts], Ms) -> - scan_extends(Ts, [], Ms); + scan_extends(Ts, Ms); scan_module(_Ts, Ms) -> Ms. -scan_module_1([{atom,_,_}=A,{',',L}|Ts], As, Ms) -> +scan_module_1([{atom,_,_}=A,{',',L}|Ts], Ms) -> %% Parameterized modules. - scan_module_1([A,{')',L}|Ts], As, Ms); -scan_module_1([{atom,Ln,A},{')',_Lr}|_Ts], As, Ms0) -> - Mod = lists:concat(lists:reverse([A|As])), - Ms = dict:store({atom,'MODULE'}, - {none,[{atom,Ln,list_to_atom(Mod)}]}, Ms0), - dict:store({atom,'MODULE_STRING'}, {none,[{string,Ln,Mod}]}, Ms); -scan_module_1([{atom,_Ln,A},{'.',_Lr}|Ts], As, Ms) -> - scan_module_1(Ts, [".",A|As], Ms); -scan_module_1([{'.',_Lr}|Ts], As, Ms) -> - scan_module_1(Ts, As, Ms); -scan_module_1(_Ts, _As, Ms) -> Ms. - -scan_extends([{atom,Ln,A},{')',_Lr}|_Ts], As, Ms0) -> - Mod = lists:concat(lists:reverse([A|As])), - Ms = dict:store({atom,'BASE_MODULE'}, - {none,[{atom,Ln,list_to_atom(Mod)}]}, Ms0), - dict:store({atom,'BASE_MODULE_STRING'}, {none,[{string,Ln,Mod}]}, Ms); -scan_extends([{atom,_Ln,A},{'.',_Lr}|Ts], As, Ms) -> - scan_extends(Ts, [".",A|As], Ms); -scan_extends([{'.',_Lr}|Ts], As, Ms) -> - scan_extends(Ts, As, Ms); -scan_extends(_Ts, _As, Ms) -> Ms. + scan_module_1([A,{')',L}|Ts], Ms); +scan_module_1([{atom,Ln,A}=ModAtom,{')',_Lr}|_Ts], Ms0) -> + ModString = atom_to_list(A), + Ms = Ms0#{'MODULE':={none,[ModAtom]}}, + Ms#{'MODULE_STRING':={none,[{string,Ln,ModString}]}}; +scan_module_1(_Ts, Ms) -> Ms. + +scan_extends([{atom,Ln,A}=ModAtom,{')',_Lr}|_Ts], Ms0) -> + ModString = atom_to_list(A), + Ms = Ms0#{'BASE_MODULE':={none,[ModAtom]}}, + Ms#{'BASE_MODULE_STRING':={none,[{string,Ln,ModString}]}}; +scan_extends(_Ts, Ms) -> Ms. %% scan_define(Tokens, DefineToken, From, EppState) -scan_define([{'(',_Lp},{Type,_Lm,M}=Mac,{',',_}=Comma|Toks], _Def, From, St) +scan_define([{'(',_Lp},{Type,_Lm,_}=Mac|Toks], Def, From, St) when Type =:= atom; Type =:= var -> + scan_define_1(Toks, Mac, Def, From, St); +scan_define(_Toks, Def, From, St) -> + epp_reply(From, {error,{loc(Def),epp,{bad,define}}}), + wait_req_scan(St). + +scan_define_1([{',',_}=Comma|Toks], Mac,_Def, From, St) -> case catch macro_expansion(Toks, Comma) of Expansion when is_list(Expansion) -> - case dict:find({atom,M}, St#epp.macs) of - {ok, Defs} when is_list(Defs) -> - %% User defined macros: can be overloaded - case proplists:is_defined(none, Defs) of - true -> - epp_reply(From, {error,{loc(Mac),epp,{redefine,M}}}), - wait_req_scan(St); - false -> - scan_define_cont(From, St, - {atom, M}, - {none, {none,Expansion}}) - end; - {ok, _PreDef} -> - %% Predefined macros: cannot be overloaded - epp_reply(From, {error,{loc(Mac),epp,{redefine_predef,M}}}), - wait_req_scan(St); - error -> - scan_define_cont(From, St, - {atom, M}, - {none, {none,Expansion}}) - end; + scan_define_2(none, {none,Expansion}, Mac, From, St); {error,ErrL,What} -> epp_reply(From, {error,{ErrL,epp,What}}), wait_req_scan(St) end; -scan_define([{'(',_Lp},{Type,_Lm,M}=Mac,{'(',_Lc}|Toks], Def, From, St) - when Type =:= atom; Type =:= var -> +scan_define_1([{'(',_Lc}|Toks], Mac, Def, From, St) -> case catch macro_pars(Toks, []) of - {ok, {As,Me}} -> + {ok,{As,_}=MacroDef} -> Len = length(As), - case dict:find({atom,M}, St#epp.macs) of - {ok, Defs} when is_list(Defs) -> - %% User defined macros: can be overloaded - case proplists:is_defined(Len, Defs) of - true -> - epp_reply(From,{error,{loc(Mac),epp,{redefine,M}}}), - wait_req_scan(St); - false -> - scan_define_cont(From, St, {atom, M}, - {Len, {As, Me}}) - end; - {ok, _PreDef} -> - %% Predefined macros: cannot be overloaded - %% (There are currently no predefined F(...) macros.) - epp_reply(From, {error,{loc(Mac),epp,{redefine_predef,M}}}), - wait_req_scan(St); - error -> - scan_define_cont(From, St, {atom, M}, {Len, {As, Me}}) - end; + scan_define_2(Len, MacroDef, Mac, From, St); {error,ErrL,What} -> epp_reply(From, {error,{ErrL,epp,What}}), wait_req_scan(St); @@ -889,10 +835,29 @@ scan_define([{'(',_Lp},{Type,_Lm,M}=Mac,{'(',_Lc}|Toks], Def, From, St) epp_reply(From, {error,{loc(Def),epp,{bad,define}}}), wait_req_scan(St) end; -scan_define(_Toks, Def, From, St) -> +scan_define_1(_Toks, _Mac, Def, From, St) -> epp_reply(From, {error,{loc(Def),epp,{bad,define}}}), wait_req_scan(St). +scan_define_2(Arity, Def, {_,_,Key}=Mac, From, #epp{macs=Ms}=St) -> + case Ms of + #{Key:=Defs} when is_list(Defs) -> + %% User defined macros: can be overloaded + case proplists:is_defined(Arity, Defs) of + true -> + epp_reply(From, {error,{loc(Mac),epp,{redefine,Key}}}), + wait_req_scan(St); + false -> + scan_define_cont(From, St, Key, Defs, Arity, Def) + end; + #{Key:=_} -> + %% Predefined macros: cannot be overloaded + epp_reply(From, {error,{loc(Mac),epp,{redefine_predef,Key}}}), + wait_req_scan(St); + _ -> + scan_define_cont(From, St, Key, [], Arity, Def) + end. + %%% Detection of circular macro expansions (which would either keep %%% the compiler looping forever, or run out of memory): %%% When a macro is defined, we store the names of other macros it @@ -902,11 +867,17 @@ scan_define(_Toks, Def, From, St) -> %%% the information from St#epp.uses is traversed, and if a circularity %%% is detected, an error message is thrown. -scan_define_cont(F, St, M, {Arity, Def}) -> - Ms = dict:append_list(M, [{Arity, Def}], St#epp.macs), - try dict:append_list(M, [{Arity, macro_uses(Def)}], St#epp.uses) of +scan_define_cont(F, #epp{macs=Ms0}=St, M, Defs, Arity, Def) -> + Ms = Ms0#{M=>[{Arity,Def}|Defs]}, + try macro_uses(Def) of U -> - scan_toks(F, St#epp{uses=U, macs=Ms}) + Uses0 = St#epp.uses, + Val = [{Arity,U}|case Uses0 of + #{M:=UseList} -> UseList; + _ -> [] + end], + Uses = Uses0#{M=>Val}, + scan_toks(F, St#epp{uses=Uses,macs=Ms}) catch {error, Line, Reason} -> epp_reply(F, {error,{Line,epp,Reason}}), @@ -924,23 +895,23 @@ macro_ref([{'?', _}, {'?', _} | Rest]) -> macro_ref([{'?', _}, {atom, _, A}=Atom | Rest]) -> Lm = loc(Atom), Arity = count_args(Rest, Lm, A), - [{{atom, A}, Arity} | macro_ref(Rest)]; + [{A,Arity} | macro_ref(Rest)]; macro_ref([{'?', _}, {var, _, A}=Var | Rest]) -> Lm = loc(Var), Arity = count_args(Rest, Lm, A), - [{{atom, A}, Arity} | macro_ref(Rest)]; + [{A,Arity} | macro_ref(Rest)]; macro_ref([_Token | Rest]) -> macro_ref(Rest). %% scan_undef(Tokens, UndefToken, From, EppState) scan_undef([{'(',_Llp},{atom,_Lm,M},{')',_Lrp},{dot,_Ld}], _Undef, From, St) -> - Macs = dict:erase({atom,M}, St#epp.macs), - Uses = dict:erase({atom,M}, St#epp.uses), + Macs = maps:remove(M, St#epp.macs), + Uses = maps:remove(M, St#epp.uses), scan_toks(From, St#epp{macs=Macs, uses=Uses}); scan_undef([{'(',_Llp},{var,_Lm,M},{')',_Lrp},{dot,_Ld}], _Undef, From,St) -> - Macs = dict:erase({atom,M}, St#epp.macs), - Uses = dict:erase({atom,M}, St#epp.uses), + Macs = maps:remove(M, St#epp.macs), + Uses = maps:remove(M, St#epp.uses), scan_toks(From, St#epp{macs=Macs, uses=Uses}); scan_undef(_Toks, Undef, From, St) -> epp_reply(From, {error,{loc(Undef),epp,{bad,undef}}}), @@ -1007,17 +978,17 @@ scan_include_lib(_Toks, Inc, From, St) -> %% Report a badly formed if[n]def test and then treat as undefined macro. scan_ifdef([{'(',_Llp},{atom,_Lm,M},{')',_Lrp},{dot,_Ld}], _IfD, From, St) -> - case dict:find({atom,M}, St#epp.macs) of - {ok,_Def} -> + case St#epp.macs of + #{M:=_Def} -> scan_toks(From, St#epp{istk=[ifdef|St#epp.istk]}); - error -> + _ -> skip_toks(From, St, [ifdef]) end; scan_ifdef([{'(',_Llp},{var,_Lm,M},{')',_Lrp},{dot,_Ld}], _IfD, From, St) -> - case dict:find({atom,M}, St#epp.macs) of - {ok,_Def} -> + case St#epp.macs of + #{M:=_Def} -> scan_toks(From, St#epp{istk=[ifdef|St#epp.istk]}); - error -> + _ -> skip_toks(From, St, [ifdef]) end; scan_ifdef(_Toks, IfDef, From, St) -> @@ -1025,17 +996,17 @@ scan_ifdef(_Toks, IfDef, From, St) -> wait_req_skip(St, [ifdef]). scan_ifndef([{'(',_Llp},{atom,_Lm,M},{')',_Lrp},{dot,_Ld}], _IfnD, From, St) -> - case dict:find({atom,M}, St#epp.macs) of - {ok,_Def} -> + case St#epp.macs of + #{M:=_Def} -> skip_toks(From, St, [ifndef]); - error -> + _ -> scan_toks(From, St#epp{istk=[ifndef|St#epp.istk]}) end; scan_ifndef([{'(',_Llp},{var,_Lm,M},{')',_Lrp},{dot,_Ld}], _IfnD, From, St) -> - case dict:find({atom,M}, St#epp.macs) of - {ok,_Def} -> + case St#epp.macs of + #{M:=_Def} -> skip_toks(From, St, [ifndef]); - error -> + _ -> scan_toks(From, St#epp{istk=[ifndef|St#epp.istk]}) end; scan_ifndef(_Toks, IfnDef, From, St) -> @@ -1103,7 +1074,8 @@ scan_file([{'(',_Llp},{string,_Ls,Name},{',',_Lc},{integer,_Li,Ln},{')',_Lrp}, {dot,_Ld}], Tf, From, St) -> Anno = erl_anno:new(Ln), enter_file_reply(From, Name, Anno, loc(Tf), generated), - Ms = dict:store({atom,'FILE'}, {none,[{string,line1(),Name}]}, St#epp.macs), + Ms0 = St#epp.macs, + Ms = Ms0#{'FILE':={none,[{string,line1(),Name}]}}, Locf = loc(Tf), NewLoc = new_location(Ln, St#epp.location, Locf), Delta = get_line(element(2, Tf))-Ln + St#epp.delta, @@ -1191,40 +1163,42 @@ macro_expansion([], Anno0) -> throw({error,loc(Anno0),premature_end}). %% Expand the macros in a list of tokens, making sure that an expansion %% gets the same location as the macro call. -expand_macros(Type, MacT, M, Toks, Ms0) -> - %% (Type will always be 'atom') - {Ms, U} = Ms0, +expand_macros(MacT, M, Toks, Ms0) -> + {Ms,U} = Ms0, Lm = loc(MacT), Tinfo = element(2, MacT), - case expand_macro1(Type, Lm, M, Toks, Ms) of + case expand_macro1(Lm, M, Toks, Ms) of {ok,{none,Exp}} -> - check_uses([{{Type,M}, none}], [], U, Lm), - Toks1 = expand_macros(expand_macro(Exp, Tinfo, [], dict:new()), Ms0), + check_uses([{M,none}], [], U, Lm), + Toks1 = expand_macros(expand_macro(Exp, Tinfo, [], #{}), Ms0), expand_macros(Toks1++Toks, Ms0); {ok,{As,Exp}} -> - check_uses([{{Type,M}, length(As)}], [], U, Lm), - {Bs,Toks1} = bind_args(Toks, Lm, M, As, dict:new()), + check_uses([{M,length(As)}], [], U, Lm), + {Bs,Toks1} = bind_args(Toks, Lm, M, As, #{}), expand_macros(expand_macro(Exp, Tinfo, Toks1, Bs), Ms0) end. -expand_macro1(Type, Lm, M, Toks, Ms) -> +expand_macro1(Lm, M, Toks, Ms) -> Arity = count_args(Toks, Lm, M), - case dict:find({Type,M}, Ms) of - error -> %% macro not found - throw({error,Lm,{undefined,M,Arity}}); - {ok, undefined} -> %% Predefined macro without definition + case Ms of + #{M:=undefined} -> + %% Predefined macro without definition. throw({error,Lm,{undefined,M,Arity}}); - {ok, [{none, Def}]} -> - {ok, Def}; - {ok, Defs} when is_list(Defs) -> - case proplists:get_value(Arity, Defs) of + #{M:=[{none,Def}]} -> + {ok,Def}; + #{M:=Defs} when is_list(Defs) -> + case proplists:get_value(Arity, Defs) of undefined -> throw({error,Lm,{mismatch,M}}); Def -> - {ok, Def} + {ok,Def} end; - {ok, PreDef} -> %% Predefined macro - {ok, PreDef} + #{M:=PreDef} -> + %% Predefined macro. + {ok,PreDef}; + _ -> + %% Macro not found. + throw({error,Lm,{undefined,M,Arity}}) end. check_uses([], _Anc, _U, _Lm) -> @@ -1232,7 +1206,7 @@ check_uses([], _Anc, _U, _Lm) -> check_uses([M|Rest], Anc, U, Lm) -> case lists:member(M, Anc) of true -> - {{_, Name},Arity} = M, + {Name,Arity} = M, throw({error,Lm,{circular,Name,Arity}}); false -> L = get_macro_uses(M, U), @@ -1241,23 +1215,23 @@ check_uses([M|Rest], Anc, U, Lm) -> end. get_macro_uses({M,Arity}, U) -> - case dict:find(M, U) of - error -> - []; - {ok, L} -> - proplists:get_value(Arity, L, proplists:get_value(none, L, [])) + case U of + #{M:=L} -> + proplists:get_value(Arity, L, proplists:get_value(none, L, [])); + _ -> + [] end. %% Macro expansion %% Note: io:scan_erl_form() does not return comments or white spaces. expand_macros([{'?',_Lq},{atom,_Lm,M}=MacT|Toks], Ms) -> - expand_macros(atom, MacT, M, Toks, Ms); + expand_macros(MacT, M, Toks, Ms); %% Special macros expand_macros([{'?',_Lq},{var,Lm,'LINE'}=Tok|Toks], Ms) -> Line = erl_scan:line(Tok), [{integer,Lm,Line}|expand_macros(Toks, Ms)]; expand_macros([{'?',_Lq},{var,_Lm,M}=MacT|Toks], Ms) -> - expand_macros(atom, MacT, M, Toks, Ms); + expand_macros(MacT, M, Toks, Ms); %% Illegal macros expand_macros([{'?',_Lq},Token|_Toks], _Ms) -> T = case erl_scan:text(Token) of @@ -1296,7 +1270,7 @@ macro_args(_Toks, Lm, M, _As, _Bs) -> store_arg(L, M, _A, [], _Bs) -> throw({error,L,{mismatch,M}}); store_arg(_L, _M, A, Arg, Bs) -> - dict:store(A, Arg, Bs). + Bs#{A=>Arg}. %% count_args(Tokens, MacroLine, MacroName) %% Count the number of arguments in a macro call. @@ -1369,19 +1343,17 @@ macro_arg([], _E, Arg) -> %% and then the macro arguments, i.e. simulate textual expansion. expand_macro([{var,_Lv,V}|Ts], L, Rest, Bs) -> - case dict:find(V, Bs) of - {ok,Val} -> - %% lists:append(Val, expand_macro(Ts, L, Rest, Bs)); + case Bs of + #{V:=Val} -> expand_arg(Val, Ts, L, Rest, Bs); - error -> + _ -> [{var,L,V}|expand_macro(Ts, L, Rest, Bs)] end; expand_macro([{'?', _}, {'?', _}, {var,_Lv,V}|Ts], L, Rest, Bs) -> - case dict:find(V, Bs) of - {ok,Val} -> - %% lists:append(Val, expand_macro(Ts, L, Rest, Bs)); + case Bs of + #{V:=Val} -> expand_arg(stringify(Val, L), Ts, L, Rest, Bs); - error -> + _ -> [{var,L,V}|expand_macro(Ts, L, Rest, Bs)] end; expand_macro([T|Ts], L, Rest, Bs) -> diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index ca3cc43b19..40a34aa30f 100644 --- a/lib/stdlib/src/erl_eval.erl +++ b/lib/stdlib/src/erl_eval.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2015. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -415,7 +415,7 @@ expr({call,_,{atom,_,Func},As0}, Bs0, Lf, Ef, RBs) -> {As,Bs} = expr_list(As0, Bs0, Lf, Ef), bif(Func, As, Bs, Ef, RBs); false -> - local_func(Func, As0, Bs0, Lf, RBs) + local_func(Func, As0, Bs0, Lf, Ef, RBs) end; expr({call,_,Func0,As0}, Bs0, Lf, Ef, RBs) -> % function or {Mod,Fun} {value,Func,Bs1} = expr(Func0, Bs0, Lf, Ef, none), @@ -542,33 +542,34 @@ unhide_calls([E | Es], MaxLine, D) -> unhide_calls(E, _MaxLine, _D) -> E. -%% local_func(Function, Arguments, Bindings, LocalFuncHandler, RBs) -> +%% local_func(Function, Arguments, Bindings, LocalFuncHandler, +%% ExternalFuncHandler, RBs) -> %% {value,Value,Bindings} | Value when %% LocalFuncHandler = {value,F} | {value,F,Eas} | %% {eval,F} | {eval,F,Eas} | none. -local_func(Func, As0, Bs0, {value,F}, value) -> - {As1,_Bs1} = expr_list(As0, Bs0, {value,F}), +local_func(Func, As0, Bs0, {value,F}, Ef, value) -> + {As1,_Bs1} = expr_list(As0, Bs0, {value,F}, Ef), %% Make tail recursive calls when possible. F(Func, As1); -local_func(Func, As0, Bs0, {value,F}, RBs) -> - {As1,Bs1} = expr_list(As0, Bs0, {value,F}), +local_func(Func, As0, Bs0, {value,F}, Ef, RBs) -> + {As1,Bs1} = expr_list(As0, Bs0, {value,F}, Ef), ret_expr(F(Func, As1), Bs1, RBs); -local_func(Func, As0, Bs0, {value,F,Eas}, RBs) -> +local_func(Func, As0, Bs0, {value,F,Eas}, Ef, RBs) -> Fun = fun(Name, Args) -> apply(F, [Name,Args|Eas]) end, - local_func(Func, As0, Bs0, {value, Fun}, RBs); -local_func(Func, As, Bs, {eval,F}, RBs) -> + local_func(Func, As0, Bs0, {value, Fun}, Ef, RBs); +local_func(Func, As, Bs, {eval,F}, _Ef, RBs) -> local_func2(F(Func, As, Bs), RBs); -local_func(Func, As, Bs, {eval,F,Eas}, RBs) -> +local_func(Func, As, Bs, {eval,F,Eas}, _Ef, RBs) -> local_func2(apply(F, [Func,As,Bs|Eas]), RBs); %% These two clauses are for backwards compatibility. -local_func(Func, As0, Bs0, {M,F}, RBs) -> - {As1,Bs1} = expr_list(As0, Bs0, {M,F}), +local_func(Func, As0, Bs0, {M,F}, Ef, RBs) -> + {As1,Bs1} = expr_list(As0, Bs0, {M,F}, Ef), ret_expr(M:F(Func,As1), Bs1, RBs); -local_func(Func, As, _Bs, {M,F,Eas}, RBs) -> +local_func(Func, As, _Bs, {M,F,Eas}, _Ef, RBs) -> local_func2(apply(M, F, [Func,As|Eas]), RBs); %% Default unknown function handler to undefined function. -local_func(Func, As0, _Bs0, none, _RBs) -> +local_func(Func, As0, _Bs0, none, _Ef, _RBs) -> erlang:raise(error, undef, [{erl_eval,Func,length(As0)}|stacktrace()]). local_func2({value,V,Bs}, RBs) -> @@ -1184,7 +1185,7 @@ match_tuple([], _, _, Bs, _BBs) -> match_map([{map_field_exact, _, K, V}|Fs], Map, Bs0, BBs) -> Vm = try - {value, Ke, _} = expr(K, Bs0), + {value, Ke, _} = expr(K, BBs), maps:get(Ke,Map) catch error:_ -> throw(nomatch) diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index a5f0e7dbd3..9ef4acdf5f 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2015. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -96,7 +96,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) -> %% 'called' and 'exports' contain {Line, {Function, Arity}}, %% the other function collections contain {Function, Arity}. -record(lint, {state=start :: 'start' | 'attribute' | 'function', - module=[], %Module + module='', %Module behaviour=[], %Behaviour exports=gb_sets:empty() :: gb_sets:set(fa()),%Exports imports=[] :: [fa()], %Imports, an orddict() @@ -292,6 +292,9 @@ format_error({variable_in_record_def,V}) -> %% --- binaries --- format_error({undefined_bittype,Type}) -> io_lib:format("bit type ~w undefined", [Type]); +format_error({bittype_mismatch,Val1,Val2,What}) -> + io_lib:format("conflict in ~s specification for bit field: '~p' and '~p'", + [What,Val1,Val2]); format_error(bittype_unit) -> "a bit unit size must not be specified unless a size is specified too"; format_error(illegal_bitsize) -> @@ -370,9 +373,9 @@ format_error({spec_fun_undefined, {F, A}}) -> format_error({missing_spec, {F,A}}) -> io_lib:format("missing specification for function ~w/~w", [F, A]); format_error(spec_wrong_arity) -> - "spec has the wrong arity"; + "spec has wrong arity"; format_error(callback_wrong_arity) -> - "callback has the wrong arity"; + "callback has wrong arity"; format_error({deprecated_builtin_type, {Name, Arity}, Replacement, Rel}) -> UseS = case Replacement of @@ -693,7 +696,12 @@ set_form_file({function,L,N,A,C}, File) -> set_form_file(Form, _File) -> Form. +set_file(Ts, File) when is_list(Ts) -> + [anno_set_file(T, File) || T <- Ts]; set_file(T, File) -> + anno_set_file(T, File). + +anno_set_file(T, File) -> F = fun(Anno) -> erl_anno:set_file(File, Anno) end, erl_parse:map_anno(F, T). @@ -728,7 +736,7 @@ start_state(Form, St) -> %% attribute_state(Form, State) -> %% State' -attribute_state({attribute,_L,module,_M}, #lint{module=[]}=St) -> +attribute_state({attribute,_L,module,_M}, #lint{module=''}=St) -> St; attribute_state({attribute,L,module,_M}, St) -> add_error(L, redefine_module, St); @@ -2875,7 +2883,7 @@ spec_decl(Line, MFA0, TypeSpecs, St0 = #lint{specs = Specs, module = Mod}) -> St1 = St0#lint{specs = dict:store(MFA, Line, Specs)}, case dict:is_key(MFA, Specs) of true -> add_error(Line, {redefine_spec, MFA0}, St1); - false -> check_specs(TypeSpecs, Arity, St1) + false -> check_specs(TypeSpecs, spec_wrong_arity, Arity, St1) end. %% callback_decl(Line, Fun, Types, State) -> State. @@ -2889,7 +2897,8 @@ callback_decl(Line, MFA0, TypeSpecs, St1 = St0#lint{callbacks = dict:store(MFA, Line, Callbacks)}, case dict:is_key(MFA, Callbacks) of true -> add_error(Line, {redefine_callback, MFA0}, St1); - false -> check_specs(TypeSpecs, Arity, St1) + false -> check_specs(TypeSpecs, callback_wrong_arity, + Arity, St1) end end. @@ -2926,7 +2935,7 @@ is_fa({FuncName, Arity}) when is_atom(FuncName), is_integer(Arity), Arity >= 0 -> true; is_fa(_) -> false. -check_specs([FunType|Left], Arity, St0) -> +check_specs([FunType|Left], ETag, Arity, St0) -> {FunType1, CTypes} = case FunType of {type, _, bounded_fun, [FT = {type, _, 'fun', _}, Cs]} -> @@ -2934,18 +2943,16 @@ check_specs([FunType|Left], Arity, St0) -> {FT, lists:append(Types0)}; {type, _, 'fun', _} = FT -> {FT, []} end, - SpecArity = - case FunType1 of - {type, L, 'fun', [any, _]} -> any; - {type, L, 'fun', [{type, _, product, D}, _]} -> length(D) - end, + {type, L, 'fun', [{type, _, product, D}, _]} = FunType1, + SpecArity = length(D), St1 = case Arity =:= SpecArity of true -> St0; - false -> add_error(L, spec_wrong_arity, St0) + false -> %% Cannot happen if called from the compiler. + add_error(L, ETag, St0) end, St2 = check_type({type, nowarn(), product, [FunType1|CTypes]}, St1), - check_specs(Left, Arity, St2); -check_specs([], _Arity, St) -> + check_specs(Left, ETag, Arity, St2); +check_specs([], _ETag, _Arity, St) -> St. nowarn() -> @@ -3189,8 +3196,8 @@ handle_generator(P,E,Vt,Uvt,St0) -> handle_bitstring_gen_pat({bin,_,Segments=[_|_]},St) -> case lists:last(Segments) of {bin_element,Line,{var,_,_},default,Flags} when is_list(Flags) -> - case member(binary, Flags) orelse member(bits, Flags) - orelse member(bitstring, Flags) of + case member(binary, Flags) orelse member(bytes, Flags) + orelse member(bits, Flags) orelse member(bitstring, Flags) of true -> add_error(Line, unsized_binary_in_bin_gen_pattern, St); false -> diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index ae42a8f0b1..b1c574ea60 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2015. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -85,10 +85,6 @@ type_spec -> '(' spec_fun type_sigs ')' : {'$2', '$3'}. spec_fun -> atom : '$1'. spec_fun -> atom ':' atom : {'$1', '$3'}. -%% The following two are retained only for backwards compatibility; -%% they are not part of the EEP syntax and should be removed. -spec_fun -> atom '/' integer '::' : {'$1', '$3'}. -spec_fun -> atom ':' atom '/' integer '::' : {'$1', '$3', '$5'}. typed_attr_val -> expr ',' typed_record_fields : {typed_record, '$1', '$3'}. typed_attr_val -> expr '::' top_type : {type_def, '$1', '$3'}. @@ -531,12 +527,418 @@ Erlang code. -compile([{hipe,[{regalloc,linear_scan}]}]). -export_type([abstract_clause/0, abstract_expr/0, abstract_form/0, - error_info/0]). + abstract_type/0, error_info/0]). + +%% Start of Abstract Format + +-type anno() :: erl_anno:anno(). + +-type abstract_form() :: af_module() + | af_behavior() + | af_behaviour() + | af_export() + | af_import() + | af_export_type() + | af_optional_callbacks() + | af_compile() + | af_file() + | af_record_decl() + | af_type_decl() + | af_function_spec() + | af_wild_attribute() + | af_function_decl(). + +-type af_module() :: {'attribute', anno(), 'module', module()}. + +-type af_behavior() :: {'attribute', anno(), 'behavior', behaviour()}. + +-type af_behaviour() :: {'attribute', anno(), 'behaviour', behaviour()}. + +-type behaviour() :: atom(). + +-type af_export() :: {'attribute', anno(), 'export', af_fa_list()}. + +-type af_import() :: {'attribute', anno(), 'import', af_fa_list()}. + +-type af_fa_list() :: [{function_name(), arity()}]. + +-type af_export_type() :: {'attribute', anno(), 'export_type', af_ta_list()}. + +-type af_ta_list() :: [{type_name(), arity()}]. + +-type af_optional_callbacks() :: + {'attribute', anno(), 'optional_callbacks', af_fa_list()}. + +-type af_compile() :: {'attribute', anno(), 'compile', any()}. + +-type af_file() :: {'attribute', anno(), 'file', {string(), anno()}}. + +-type af_record_decl() :: + {'attribute', anno(), 'record', {record_name(), [af_field_decl()]}}. + +-type af_field_decl() :: af_typed_field() | af_field(). + +-type af_typed_field() :: + {'typed_record_field', af_field(), abstract_type()}. + +-type af_field() :: {'record_field', anno(), af_field_name()} + | {'record_field', anno(), af_field_name(), abstract_expr()}. + +-type af_type_decl() :: {'attribute', anno(), type_attr(), + {type_name(), abstract_type(), [af_variable()]}}. + +-type type_attr() :: 'opaque' | 'type'. + +-type af_function_spec() :: {'attribute', anno(), spec_attr(), + {{function_name(), arity()}, + af_function_type_list()}} + | {'attribute', anno(), 'spec', + {{module(), function_name(), arity()}, + af_function_type_list()}}. + +-type spec_attr() :: 'callback' | 'spec'. + +-type af_wild_attribute() :: {'attribute', anno(), atom(), any()}. + +-type af_function_decl() :: + {'function', anno(), function_name(), arity(), af_clause_seq()}. + +-type abstract_expr() :: af_literal() + | af_match(abstract_expr()) + | af_variable() + | af_tuple(abstract_expr()) + | af_nil() + | af_cons(abstract_expr()) + | af_bin(abstract_expr()) + | af_binary_op(abstract_expr()) + | af_unary_op(abstract_expr()) + | af_record_access(abstract_expr()) + | af_record_update(abstract_expr()) + | af_record_index() + | af_record_field_access(abstract_expr()) + | af_map_access(abstract_expr()) + | af_map_update(abstract_expr()) + | af_catch() + | af_local_call() + | af_remote_call() + | af_list_comprehension() + | af_binary_comprehension() + | af_block() + | af_if() + | af_case() + | af_try() + | af_receive() + | af_local_fun() + | af_remote_fun() + | af_fun() + | af_named_fun(). + +-type af_record_update(T) :: {'record', + anno(), + abstract_expr(), + record_name(), + [af_record_field(T)]}. + +-type af_catch() :: {'catch', anno(), abstract_expr()}. + +-type af_local_call() :: {'call', anno(), af_local_function(), af_args()}. + +-type af_remote_call() :: {'call', anno(), af_remote_function(), af_args()}. + +-type af_args() :: [abstract_expr()]. + +-type af_local_function() :: abstract_expr(). + +-type af_remote_function() :: + {'remote', anno(), abstract_expr(), abstract_expr()}. + +-type af_list_comprehension() :: + {'lc', anno(), af_template(), af_qualifier_seq()}. + +-type af_binary_comprehension() :: + {'bc', anno(), af_template(), af_qualifier_seq()}. + +-type af_template() :: abstract_expr(). + +-type af_qualifier_seq() :: [af_qualifier()]. + +-type af_qualifier() :: af_generator() | af_filter(). + +-type af_generator() :: {'generate', anno(), af_pattern(), abstract_expr()} + | {'b_generate', anno(), af_pattern(), abstract_expr()}. + +-type af_filter() :: abstract_expr(). + +-type af_block() :: {'block', anno(), af_body()}. + +-type af_if() :: {'if', anno(), af_clause_seq()}. + +-type af_case() :: {'case', anno(), abstract_expr(), af_clause_seq()}. + +-type af_try() :: {'try', + anno(), + af_body() | [], + af_clause_seq() | [], + af_clause_seq() | [], + af_body() | []}. + +-type af_clause_seq() :: [af_clause(), ...]. + +-type af_receive() :: + {'receive', anno(), af_clause_seq()} + | {'receive', anno(), af_clause_seq(), abstract_expr(), af_body()}. + +-type af_local_fun() :: + {'fun', anno(), {'function', function_name(), arity()}}. + +-type af_remote_fun() :: + {'fun', anno(), {'function', module(), function_name(), arity()}} + | {'fun', anno(), {'function', af_atom(), af_atom(), af_integer()}}. + +-type af_fun() :: {'fun', anno(), {'clauses', af_clause_seq()}}. + +-type af_named_fun() :: {'named_fun', anno(), fun_name(), af_clause_seq()}. + +-type fun_name() :: atom(). + +-type abstract_clause() :: af_clause(). + +-type af_clause() :: + {'clause', anno(), [af_pattern()], af_guard_seq(), af_body()}. + +-type af_body() :: [abstract_expr(), ...]. + +-type af_guard_seq() :: [af_guard()]. + +-type af_guard() :: [af_guard_test(), ...]. + +-type af_guard_test() :: af_literal() + | af_variable() + | af_tuple(af_guard_test()) + | af_nil() + | af_cons(af_guard_test()) + | af_bin(af_guard_test()) + | af_binary_op(af_guard_test()) + | af_unary_op(af_guard_test()) + | af_record_access(af_guard_test()) + | af_record_index() + | af_record_field_access(af_guard_test()) + | af_map_access(abstract_expr()) % FIXME + | af_map_update(abstract_expr()) % FIXME + | af_guard_call() + | af_remote_guard_call(). + +-type af_record_field_access(T) :: + {'record_field', anno(), T, record_name(), af_field_name()}. + +-type af_map_access(T) :: {'map', anno(), [af_map_field(T)]}. + +-type af_map_update(T) :: {'map', anno(), T, [af_map_field(T)]}. + +-type af_map_field(T) :: af_map_field_assoc(T) | af_map_field_exact(T). + +-type af_map_field_assoc(T) :: {'map_field_assoc', anno(), T, T}. + +-type af_map_field_exact(T) :: {'map_field_exact', anno(), T, T}. + +-type af_guard_call() :: {'call', anno(), function_name(), [af_guard_test()]}. + +-type af_remote_guard_call() :: + {'call', anno(), + {'remote', anno(), af_lit_atom('erlang'), af_atom()}, + [af_guard_test()]}. + +-type af_pattern() :: af_literal() + | af_match(af_pattern()) + | af_variable() + | af_tuple(af_pattern()) + | af_nil() + | af_cons(af_pattern()) + | af_bin(af_pattern()) + | af_binary_op(af_pattern()) + | af_unary_op(af_pattern()) + | af_record_access(af_pattern()) + | af_record_index() + | af_map_pattern(). + +-type af_record_index() :: + {'record_index', anno(), record_name(), af_field_name()}. + +-type af_record_access(T) :: + {'record', anno(), record_name(), [af_record_field(T)]}. + +-type af_record_field(T) :: {'record_field', anno(), af_field_name(), T}. + +-type af_map_pattern() :: + {'map', anno(), [af_map_field_exact(abstract_expr)]}. % FIXME? + +-type abstract_type() :: af_annotated_type() + | af_atom() + | af_bitstring_type() + | af_empty_list_type() + | af_fun_type() + | af_integer_range_type() + | af_map_type() + | af_predefined_type() + | af_record_type() + | af_remote_type() + | af_singleton_integer_type() + | af_tuple_type() + | af_type_union() + | af_type_variable() + | af_user_defined_type(). + +-type af_annotated_type() :: + {'ann_type', anno(), [af_anno() | abstract_type()]}. % [Var, Type] + +-type af_anno() :: af_variable(). + +-type af_bitstring_type() :: + {'type', anno(), 'binary', [af_singleton_integer_type()]}. + +-type af_empty_list_type() :: {'type', anno(), 'nil', []}. + +-type af_fun_type() :: {'type', anno(), 'fun', []} + | {'type', anno(), 'fun', [{'type', anno(), 'any'} | + abstract_type()]} + | {'type', anno(), 'fun', af_function_type()}. + +-type af_integer_range_type() :: + {'type', anno(), 'range', [af_singleton_integer_type()]}. + +-type af_map_type() :: {'type', anno(), 'map', 'any'} + | {'type', anno(), 'map', [af_map_pair_type()]}. + +-type af_map_pair_type() :: + {'type', anno(), 'map_field_assoc', [abstract_type()]}. + +-type af_predefined_type() :: + {'type', anno(), type_name(), [abstract_type()]}. + +-type af_record_type() :: + {'type', anno(), 'record', [(Name :: af_atom()) % [Name, T1, ... Tk] + | af_record_field_type()]}. + +-type af_record_field_type() :: + {'type', anno(), 'field_type', [(Name :: af_atom()) | + abstract_type()]}. % [Name, Type] + +-type af_remote_type() :: + {'remote_type', anno(), [(Module :: af_atom()) | + (TypeName :: af_atom()) | + [abstract_type()]]}. % [Module, Name, [T]] + +-type af_tuple_type() :: {'type', anno(), 'tuple', 'any'} + | {'type', anno(), 'tuple', [abstract_type()]}. + +-type af_type_union() :: {'type', anno(), 'union', [abstract_type()]}. + +-type af_type_variable() :: {'var', anno(), atom()}. % except '_' + +-type af_user_defined_type() :: + {'user_type', anno(), type_name(), [abstract_type()]}. + +-type af_function_type_list() :: [af_constrained_function_type() | + af_function_type()]. + +-type af_constrained_function_type() :: + {'type', anno(), 'bounded_fun', [af_function_type() | % [Ft, Fc] + af_function_constraint()]}. + +-type af_function_type() :: + {'type', anno(), 'fun', + [{'type', anno(), 'product', [abstract_type()]} | abstract_type()]}. + +-type af_function_constraint() :: [af_constraint()]. + +-type af_constraint() :: {'type', anno(), 'constraint', + af_lit_atom('is_subtype'), + [af_type_variable() | abstract_type()]}. % [V, T] + +-type af_singleton_integer_type() :: af_integer() + | af_unary_op(af_singleton_integer_type()) + | af_binary_op(af_singleton_integer_type()). + +-type af_literal() :: af_atom() | af_integer() | af_float() | af_string(). + +-type af_atom() :: af_lit_atom(atom()). + +-type af_lit_atom(A) :: {'atom', anno(), A}. + +-type af_integer() :: {'integer', anno(), non_neg_integer()}. + +-type af_float() :: {'float', anno(), float()}. + +-type af_string() :: {'string', anno(), string()}. + +-type af_match(T) :: {'match', anno(), af_pattern(), T}. + +-type af_variable() :: {'var', anno(), atom()}. % | af_anon_variable() + +%-type af_anon_variable() :: {'var', anno(), '_'}. + +-type af_tuple(T) :: {'tuple', anno(), [T]}. + +-type af_nil() :: {'nil', anno()}. + +-type af_cons(T) :: {'cons', anno(), T, T}. + +-type af_bin(T) :: {'bin', anno(), [af_binelement(T)]}. + +-type af_binelement(T) :: {'bin_element', + anno(), + T, + af_binelement_size(), + type_specifier_list()}. + +-type af_binelement_size() :: 'default' | abstract_expr(). + +-type af_binary_op(T) :: {'op', anno(), binary_op(), T, T}. + +-type binary_op() :: '/' | '*' | 'div' | 'rem' | 'band' | 'and' | '+' | '-' + | 'bor' | 'bxor' | 'bsl' | 'bsr' | 'or' | 'xor' | '++' + | '--' | '==' | '/=' | '=<' | '<' | '>=' | '>' | '=:=' + | '=/='. + +-type af_unary_op(T) :: {'op', anno(), unary_op(), T}. + +-type unary_op() :: '+' | '*' | 'bnot' | 'not'. + +%% See also lib/stdlib/{src/erl_bits.erl,include/erl_bits.hrl}. +-type type_specifier_list() :: 'default' | [type_specifier(), ...]. + +-type type_specifier() :: type() + | signedness() + | endianness() + | unit(). + +-type type() :: 'integer' + | 'float' + | 'binary' + | 'bytes' + | 'bitstring' + | 'bits' + | 'utf8' + | 'utf16' + | 'utf32'. + +-type signedness() :: 'signed' | 'unsigned'. + +-type endianness() :: 'big' | 'little' | 'native'. + +-type unit() :: {'unit', 1..256}. + +-type record_name() :: atom(). + +-type af_field_name() :: af_atom(). + +-type function_name() :: atom(). + +-type type_name() :: atom(). + +%% End of Abstract Format %% XXX. To be refined. --type abstract_clause() :: term(). --type abstract_expr() :: term(). --type abstract_form() :: term(). -type error_description() :: term(). -type error_info() :: {erl_anno:line(), module(), error_description()}. -type token() :: erl_scan:token(). @@ -634,14 +1036,8 @@ build_type_spec({Kind,Aa}, {SpecFun, TypeSpecs}) {atom, _, Fun} -> {Fun, find_arity_from_specs(TypeSpecs)}; {{atom,_, Mod}, {atom,_, Fun}} -> - {Mod,Fun,find_arity_from_specs(TypeSpecs)}; - {{atom, _, Fun}, {integer, _, Arity}} -> - %% Old style spec. Allow this for now. - {Fun,Arity}; - {{atom,_, Mod}, {atom, _, Fun}, {integer, _, Arity}} -> - %% Old style spec. Allow this for now. - {Mod,Fun,Arity} - end, + {Mod,Fun,find_arity_from_specs(TypeSpecs)} + end, {attribute,Aa,Kind,{NewSpecFun, TypeSpecs}}. find_arity_from_specs([Spec|_]) -> @@ -1093,11 +1489,16 @@ type_preop_prec('-') -> {600,700}; type_preop_prec('bnot') -> {600,700}; type_preop_prec('#') -> {700,800}. +-type erl_parse_tree() :: abstract_clause() + | abstract_expr() + | abstract_form() + | abstract_type(). + -spec map_anno(Fun, Abstr) -> NewAbstr when Fun :: fun((Anno) -> Anno), Anno :: erl_anno:anno(), - Abstr :: abstract_form() | abstract_expr(), - NewAbstr :: abstract_form() | abstract_expr(). + Abstr :: erl_parse_tree(), + NewAbstr :: erl_parse_tree(). map_anno(F0, Abstr) -> F = fun(A, Acc) -> {F0(A), Acc} end, @@ -1110,8 +1511,8 @@ map_anno(F0, Abstr) -> Acc0 :: term(), AccIn :: term(), AccOut :: term(), - Abstr :: abstract_form() | abstract_expr(), - NewAbstr :: abstract_form() | abstract_expr(). + Abstr :: erl_parse_tree(), + NewAbstr :: erl_parse_tree(). fold_anno(F0, Acc0, Abstr) -> F = fun(A, Acc) -> {A, F0(A, Acc)} end, @@ -1125,26 +1526,26 @@ fold_anno(F0, Acc0, Abstr) -> Acc1 :: term(), AccIn :: term(), AccOut :: term(), - Abstr :: abstract_form() | abstract_expr(), - NewAbstr :: abstract_form() | abstract_expr(). + Abstr :: erl_parse_tree(), + NewAbstr :: erl_parse_tree(). mapfold_anno(F, Acc0, Abstr) -> modify_anno1(Abstr, Acc0, F). -spec new_anno(Term) -> Abstr when Term :: term(), - Abstr :: abstract_form() | abstract_expr(). + Abstr :: erl_parse_tree(). new_anno(Term) -> map_anno(fun erl_anno:new/1, Term). -spec anno_to_term(Abstr) -> term() when - Abstr :: abstract_form() | abstract_expr(). + Abstr :: erl_parse_tree(). anno_to_term(Abstract) -> map_anno(fun erl_anno:to_term/1, Abstract). --spec anno_from_term(Term) -> abstract_form() | abstract_expr() when +-spec anno_from_term(Term) -> erl_parse_tree() when Term :: term(). anno_from_term(Term) -> diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl index f7a969977a..c5177aca90 100644 --- a/lib/stdlib/src/erl_pp.erl +++ b/lib/stdlib/src/erl_pp.erl @@ -253,6 +253,8 @@ lattribute(import, Name, _Opts, _State) when is_list(Name) -> attr("import", [{var,a0(),pname(Name)}]); lattribute(import, {From,Falist}, _Opts, _State) -> attr("import",[{var,a0(),pname(From)},falist(Falist)]); +lattribute(export_type, Talist, _Opts, _State) -> + call({var,a0(),"-export_type"}, [falist(Talist)], 0, options(none)); lattribute(optional_callbacks, Falist, Opts, _State) -> ArgL = try falist(Falist) catch _:_ -> abstract(Falist, Opts) @@ -321,7 +323,6 @@ ltype({type,_,'fun',[{type,_,any},_]}=FunType, _) -> ltype({type,_Line,'fun',[{type,_,product,_},_]}=FunType, _) -> [fun_type(['fun',$(], FunType),$)]; ltype({type,Line,T,Ts}, _) -> - %% Compatibility. Before 18.0. simple_type({atom,Line,T}, Ts); ltype({user_type,Line,T,Ts}, _) -> simple_type({atom,Line,T}, Ts); @@ -346,16 +347,8 @@ map_type(Fs) -> map_pair_types(Fs) -> tuple_type(Fs, fun map_pair_type/2). -map_pair_type({type,_Line,map_field_assoc,[Ktype,Vtype]}, Prec) -> - map_assoc_typed(ltype(Ktype), Vtype, Prec). - -map_assoc_typed(B, {type,_,union,Ts}, Prec) -> - {first,[B,$\s],{seq,[],[],[],map_assoc_union_type(Ts, Prec)}}; -map_assoc_typed(B, Type, Prec) -> - {list,[{cstep,[B," =>"],ltype(Type, Prec)}]}. - -map_assoc_union_type([T|Ts], Prec) -> - [[leaf("=> "),ltype(T)] | ltypes(Ts, fun union_elem/2, Prec)]. +map_pair_type({type,_Line,map_field_assoc,[KType,VType]}, Prec) -> + {list,[{cstep,[ltype(KType, Prec),leaf(" =>")],ltype(VType, Prec)}]}. record_type(Name, Fields) -> {first,[record_name(Name)],field_types(Fields)}. @@ -370,9 +363,6 @@ typed(B, Type) -> {_L,_P,R} = type_inop_prec('::'), {list,[{cstep,[B,' ::'],ltype(Type, R)}]}. -union_elem(T, Prec) -> - [leaf(" | "),ltype(T, Prec)]. - tuple_type(Ts, F) -> {seq,${,$},[$,],ltypes(Ts, F, 0)}. @@ -399,6 +389,9 @@ guard_type(Before, Gs) -> Gl = {list,[{step,'when',expr_list(Gs, [$,], fun constraint/2, Opts)}]}, {list,[{step,Before,Gl}]}. +constraint({type,_Line,constraint,[{atom,_,is_subtype},[{var,_,_}=V,Type]]}, + _Opts) -> + typed(lexpr(V, options(none)), Type); constraint({type,_Line,constraint,[Tag,As]}, _Opts) -> simple_type(Tag, As). diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl index 284f2e5a2b..f510f61e9f 100644 --- a/lib/stdlib/src/io.erl +++ b/lib/stdlib/src/io.erl @@ -444,7 +444,7 @@ scan_erl_form(Io, Prompt, Pos0, Options) -> %% Parsing Erlang code. -type parse_ret() :: {'ok', - ExprList :: erl_parse:abstract_expr(), + ExprList :: [erl_parse:abstract_expr()], EndLocation :: location()} | {'eof', EndLocation :: location()} | {'error', @@ -631,41 +631,20 @@ io_requests(Pid, [], [Rs|Cont], Tail) -> io_requests(_Pid, [], [], _Tail) -> {false,[]}. - -bc_req(Pid,{Op,Enc,Param},MaybeConvert) -> - case net_kernel:dflag_unicode_io(Pid) of - true -> - {false,{Op,Enc,Param}}; - false -> - {MaybeConvert,{Op,Param}} - end; -bc_req(Pid,{Op,Enc,P,F},MaybeConvert) -> - case net_kernel:dflag_unicode_io(Pid) of - true -> - {false,{Op,Enc,P,F}}; - false -> - {MaybeConvert,{Op,P,F}} - end; -bc_req(Pid, {Op,Enc,M,F,A},MaybeConvert) -> +bc_req(Pid, Req0, MaybeConvert) -> case net_kernel:dflag_unicode_io(Pid) of true -> - {false,{Op,Enc,M,F,A}}; + %% The most common case. A modern i/o server. + {false,Req0}; false -> - {MaybeConvert,{Op,M,F,A}} - end; -bc_req(Pid, {Op,Enc,P,M,F,A},MaybeConvert) -> - case net_kernel:dflag_unicode_io(Pid) of - true -> - {false,{Op,Enc,P,M,F,A}}; - false -> - {MaybeConvert,{Op,P,M,F,A}} - end; -bc_req(Pid,{Op,Enc},MaybeConvert) -> - case net_kernel:dflag_unicode_io(Pid) of - true -> - {false,{Op, Enc}}; - false -> - {MaybeConvert,Op} + %% Backward compatibility only. Unlikely to ever happen. + case tuple_to_list(Req0) of + [Op,_Enc] -> + {MaybeConvert,Op}; + [Op,_Enc|T] -> + Req = list_to_tuple([Op|T]), + {MaybeConvert,Req} + end end. io_request(Pid, {write,Term}) -> diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index 90ef364d1a..960c70f255 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -639,6 +639,14 @@ obsolete_1(httpd_conf, is_file, 1) -> obsolete_1(httpd_conf, make_integer, 1) -> {deprecated, "deprecated; use erlang:list_to_integer/1 instead"}; +%% Added in OTP 19. + +obsolete_1(random, _, _) -> + {deprecated, "the 'random' module is deprecated; " + "use the 'rand' module instead"}; +obsolete_1(code, rehash, 0) -> + {deprecated, "deprecated because the code path cache feature has been removed"}; + obsolete_1(_, _, _) -> no. diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl index 9577d17a85..9f69cd5003 100644 --- a/lib/stdlib/src/qlc_pt.erl +++ b/lib/stdlib/src/qlc_pt.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2015. All Rights Reserved. +%% Copyright Ericsson AB 2004-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -200,7 +200,7 @@ exclude_integers_from_unique_line_numbers(Forms, NodeInfo) -> find_integers(Forms) -> F = fun(A) -> - Fs1 = erl_parse:map_anno(fun(_) -> A end, Forms), + Fs1 = map_anno(fun(_) -> A end, Forms), ordsets:from_list(integers(Fs1, [])) end, ordsets:to_list(ordsets:intersection(F(anno0()), F(anno1()))). @@ -319,13 +319,13 @@ badarg(Forms, State) -> E0. lc_nodes(E, NodeInfo) -> - erl_parse:map_anno(fun(Anno) -> - N = erl_anno:line(Anno), - [{N, Data}] = ets:lookup(NodeInfo, N), - NData = Data#{inside_lc => true}, - true = ets:insert(NodeInfo, {N, NData}), - Anno - end, E). + map_anno(fun(Anno) -> + N = erl_anno:line(Anno), + [{N, Data}] = ets:lookup(NodeInfo, N), + NData = Data#{inside_lc => true}, + true = ets:insert(NodeInfo, {N, NData}), + Anno + end, E). used_genvar_messages(MsL, S) -> [{File,[{Loc,?APIMOD,{used_generator_variable,V}}]} @@ -416,7 +416,7 @@ intro_anno(LC, Where, QId, NodeInfo) -> true = ets:insert(NodeInfo, {Location,Data}), Anno end, - erl_parse:map_anno(Fun, save_anno(LC, NodeInfo)). + map_anno(Fun, save_anno(LC, NodeInfo)). compile_errors(FormsNoShadows) -> case compile_forms(FormsNoShadows, []) of @@ -1650,7 +1650,7 @@ reset_anno(T) -> set_anno(T, anno0()). set_anno(T, A) -> - erl_parse:map_anno(fun(_L) -> A end, T). + map_anno(fun(_L) -> A end, T). -record(fstate, {state, bind_fun, imported}). @@ -2609,7 +2609,7 @@ save_anno(Abstr, NodeInfo) -> true = ets:insert(NodeInfo, Data), erl_anno:new(N) end, - erl_parse:map_anno(F, Abstr). + map_anno(F, Abstr). next_slot(T) -> I = ets:update_counter(T, var_n, 1), @@ -2633,7 +2633,7 @@ restore_anno(Abstr, NodeInfo) -> Anno end end, - erl_parse:map_anno(F, Abstr). + map_anno(F, Abstr). restore_loc(Location, #state{node_info = NodeInfo}) -> case ets:lookup(NodeInfo, Location) of @@ -2872,6 +2872,14 @@ var_mapfold(F, A0, [E0 | Es0]) -> var_mapfold(_F, A, E) -> {E, A}. +map_anno(F, AbstrList) when is_list(AbstrList) -> + [map_anno1(F, Abstr) || Abstr <- AbstrList]; +map_anno(F, Abstr) -> + map_anno1(F, Abstr). + +map_anno1(F, Abstr) -> + erl_parse:map_anno(F, Abstr). + family_list(L) -> sofs:to_external(family(L)). diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl index 8e8d0bc801..dc060e82d9 100644 --- a/lib/stdlib/src/rand.erl +++ b/lib/stdlib/src/rand.erl @@ -63,7 +63,7 @@ %% Return algorithm and seed so that RNG state can be recreated with seed/1 -spec export_seed() -> undefined | export_state(). export_seed() -> - case seed_get() of + case get(?SEED_DICT) of {#{type:=Alg}, Seed} -> {Alg, Seed}; _ -> undefined end. diff --git a/lib/stdlib/src/random.erl b/lib/stdlib/src/random.erl index 8b67cde56c..8b639dd0a7 100644 --- a/lib/stdlib/src/random.erl +++ b/lib/stdlib/src/random.erl @@ -18,6 +18,7 @@ %% %CopyrightEnd% %% -module(random). +-deprecated(module). %% Reasonable random number generator. %% The method is attributed to B. A. Wichmann and I. D. Hill diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl index f215a66812..ce1d9eb0ff 100644 --- a/lib/stdlib/src/shell.erl +++ b/lib/stdlib/src/shell.erl @@ -999,12 +999,7 @@ local_func(rl, [A], Bs0, _Shell, RT, Lf, Ef) -> {value,list_records(record_defs(RT, listify(Recs))),Bs}; local_func(rp, [A], Bs0, _Shell, RT, Lf, Ef) -> {[V],Bs} = expr_list([A], Bs0, Lf, Ef), - Cs = io_lib_pretty:print(V, ([{column, 1}, - {line_length, columns()}, - {depth, -1}, - {max_chars, ?CHAR_MAX}, - {record_print_fun, record_print_fun(RT)}] - ++ enc())), + Cs = pp(V, _Column=1, _Depth=-1, RT), io:requests([{put_chars, unicode, Cs}, nl]), {value,ok,Bs}; local_func(rr, [A], Bs0, _Shell, RT, Lf, Ef) -> @@ -1397,9 +1392,9 @@ get_history_and_results() -> {History, erlang:min(Results, History)}. pp(V, I, RT) -> - pp(V, I, RT, enc()). + pp(V, I, _Depth=?LINEMAX, RT). -pp(V, I, RT, Enc) -> +pp(V, I, D, RT) -> Strings = case application:get_env(stdlib, shell_strings) of {ok, false} -> @@ -1408,10 +1403,10 @@ pp(V, I, RT, Enc) -> true end, io_lib_pretty:print(V, ([{column, I}, {line_length, columns()}, - {depth, ?LINEMAX}, {max_chars, ?CHAR_MAX}, + {depth, D}, {max_chars, ?CHAR_MAX}, {strings, Strings}, {record_print_fun, record_print_fun(RT)}] - ++ Enc)). + ++ enc())). columns() -> case io:columns() of diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src index 5f61752655..04cdf31ada 100644 --- a/lib/stdlib/src/stdlib.appup.src +++ b/lib/stdlib/src/stdlib.appup.src @@ -18,9 +18,9 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max one major revision back - [{<<"2\\.5(\\.[0-9]+)*">>,[restart_new_emulator]}, %% OTP-18.0.* - {<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}], %% 17.0-17.5 + [{<<"2\\.[5-7](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + {<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}], % 17.0-17.5 %% Down to - max one major revision back - [{<<"2\\.5(\\.[0-9]+)*">>,[restart_new_emulator]}, %% OTP-18.0.* - {<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}] %% 17.0-17.5 + [{<<"2\\.[5-7](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + {<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}] % 17.0-17.5 }. diff --git a/lib/stdlib/test/base64_SUITE.erl b/lib/stdlib/test/base64_SUITE.erl index 75eebba6c6..f750145ef0 100644 --- a/lib/stdlib/test/base64_SUITE.erl +++ b/lib/stdlib/test/base64_SUITE.erl @@ -340,7 +340,7 @@ interleaved_ws_roundtrip_1([], Base64List, Bin, List) -> random_byte_list(0, Acc) -> Acc; random_byte_list(N, Acc) -> - random_byte_list(N-1, [random:uniform(255)|Acc]). + random_byte_list(N-1, [rand:uniform(255)|Acc]). make_big_binary(N) -> list_to_binary(mbb(N, [])). diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl index 70c946bdb9..8a2df2bf85 100644 --- a/lib/stdlib/test/binary_module_SUITE.erl +++ b/lib/stdlib/test/binary_module_SUITE.erl @@ -536,6 +536,12 @@ do_interesting(Module) -> ?line [<<3>>,<<6>>] = Module:split(<<1,2,3,4,5,6,7,8>>, [<<1>>,<<2>>,<<4>>,<<5>>,<<7>>,<<8>>], [global,trim_all]), + [<<>>] = binary:split(<<>>, <<",">>, []), + [] = binary:split(<<>>, <<",">>, [trim]), + [] = binary:split(<<>>, <<",">>, [trim_all]), + [] = binary:split(<<>>, <<",">>, [global,trim]), + [] = binary:split(<<>>, <<",">>, [global,trim_all]), + ?line badarg = ?MASK_ERROR( Module:replace(<<1,2,3,4,5,6,7,8>>, [<<4,5>>,<<7>>,<<8>>],<<99>>, @@ -710,7 +716,7 @@ do_interesting(Module) -> encode_decode(doc) -> ["test binary:encode_unsigned/1,2 and binary:decode_unsigned/1,2"]; encode_decode(Config) when is_list(Config) -> - ?line random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), ?line ok = encode_decode_loop({1,200},1000), % Need to be long enough % to create offheap binaries ok. @@ -817,7 +823,7 @@ copy(Config) when is_list(Config) -> ?line badarg = ?MASK_ERROR(binary:copy(<<1,2,3>>, 16#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)), ?line <<>> = binary:copy(<<>>,10000), - ?line random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), ?line ok = random_copy(3000), ?line erts_debug:set_internal_state(available_internal_state,true), ?line io:format("oldlimit: ~p~n", @@ -855,7 +861,7 @@ random_copy(0) -> ok; random_copy(N) -> Str = random_string({0,N}), - Num = random:uniform(N div 10+1), + Num = rand:uniform(N div 10+1), A = ?MASK_ERROR(binary:copy(Str,Num)), B = ?MASK_ERROR(binref:copy(Str,Num)), C = ?MASK_ERROR(binary:copy(make_unaligned(Str),Num)), @@ -896,7 +902,7 @@ bin_to_list(Config) when is_list(Config) -> ?line [5] = lists:nthtail(byte_size(X)-1,LX), ?line [0,5] = lists:nthtail(byte_size(X)-2,LX), ?line [0,5] = lists:nthtail(byte_size(Y)-2,LY), - ?line random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), ?line ok = random_bin_to_list(5000), ok. @@ -963,7 +969,7 @@ parts(Config) when is_list(Config) -> ?line badarg = ?MASK_ERROR(binary:part(Simple,{-1,0})), ?line badarg = ?MASK_ERROR(binary:part(Simple,{7,2})), ?line <<8>> = binary:part(Simple,{7,1}), - ?line random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), ?line random_parts(5000), ok. @@ -987,15 +993,15 @@ random_parts(N) -> random_parts(0,_) -> []; random_parts(X,N) -> - Pos = random:uniform(N), - Len = random:uniform((Pos * 12) div 10), + Pos = rand:uniform(N), + Len = rand:uniform((Pos * 12) div 10), [{Pos,Len} | random_parts(X-1,N)]. random_ref_comp(doc) -> ["Test pseudorandomly generated cases against reference imlementation"]; random_ref_comp(Config) when is_list(Config) -> put(success_counter,0), - random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), Nr = {1,40}, Hr = {30,1000}, I1 = 1500, @@ -1025,7 +1031,7 @@ random_ref_sr_comp(doc) -> ["Test pseudorandomly generated cases against reference imlementation of split and replace"]; random_ref_sr_comp(Config) when is_list(Config) -> put(success_counter,0), - random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), Nr = {1,40}, Hr = {30,1000}, I1 = 1500, @@ -1043,7 +1049,7 @@ random_ref_fla_comp(doc) -> ["Test pseudorandomly generated cases against reference imlementation of split and replace"]; random_ref_fla_comp(Config) when is_list(Config) -> ?line put(success_counter,0), - ?line random:seed({1271,769940,559934}), + rand:seed(exsplus, {1271,769940,559934}), ?line do_random_first_comp(5000,{1,1000}), ?line do_random_last_comp(5000,{1,1000}), ?line do_random_at_comp(5000,{1,1000}), @@ -1377,24 +1383,24 @@ one_random(N) -> random_number({Min,Max}) -> % Min and Max are *length* of number in % decimal positions - X = random:uniform(Max - Min + 1) + Min - 1, - list_to_integer([one_random_number(random:uniform(10)) || _ <- lists:seq(1,X)]). + X = rand:uniform(Max - Min + 1) + Min - 1, + list_to_integer([one_random_number(rand:uniform(10)) || _ <- lists:seq(1,X)]). random_length({Min,Max}) -> - random:uniform(Max - Min + 1) + Min - 1. + rand:uniform(Max - Min + 1) + Min - 1. random_string({Min,Max}) -> - X = random:uniform(Max - Min + 1) + Min - 1, - list_to_binary([one_random(random:uniform(68)) || _ <- lists:seq(1,X)]). + X = rand:uniform(Max - Min + 1) + Min - 1, + list_to_binary([one_random(rand:uniform(68)) || _ <- lists:seq(1,X)]). random_substring({Min,Max},Hay) -> - X = random:uniform(Max - Min + 1) + Min - 1, + X = rand:uniform(Max - Min + 1) + Min - 1, Y = byte_size(Hay), Z = if X > Y -> Y; true -> X end, PMax = Y - Z, - Pos = random:uniform(PMax + 1) - 1, + Pos = rand:uniform(PMax + 1) - 1, <<_:Pos/binary,Res:Z/binary,_/binary>> = Hay, Res. diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl index 7f5e06524a..b101054229 100644 --- a/lib/stdlib/test/dets_SUITE.erl +++ b/lib/stdlib/test/dets_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2014. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -53,7 +53,8 @@ simultaneous_open/1, insert_new/1, repair_continuation/1, otp_5487/1, otp_6206/1, otp_6359/1, otp_4738/1, otp_7146/1, otp_8070/1, otp_8856/1, otp_8898/1, otp_8899/1, otp_8903/1, - otp_8923/1, otp_9282/1, otp_11245/1, otp_11709/1]). + otp_8923/1, otp_9282/1, otp_11245/1, otp_11709/1, otp_13229/1, + otp_13260/1]). -export([dets_dirty_loop/0]). @@ -110,7 +111,8 @@ all() -> many_clients, otp_4906, otp_5402, simultaneous_open, insert_new, repair_continuation, otp_5487, otp_6206, otp_6359, otp_4738, otp_7146, otp_8070, otp_8856, otp_8898, - otp_8899, otp_8903, otp_8923, otp_9282, otp_11245, otp_11709 + otp_8899, otp_8903, otp_8923, otp_9282, otp_11245, otp_11709, + otp_13229, otp_13260 ]. groups() -> @@ -3988,6 +3990,66 @@ otp_11709(Config) when is_list(Config) -> _ = file:delete(File), ok. +otp_13229(doc) -> + ["OTP-13229. open_file() exits with badarg when given binary file name."]; +otp_13229(_Config) -> + F = <<"binfile.tab">>, + try dets:open_file(name, [{file, F}]) of + R -> + exit({open_succeeded, R}) + catch + error:badarg -> + ok + end. + +otp_13260(doc) -> + ["OTP-13260. Race when opening a table."]; +otp_13260(Config) -> + [ok] = lists:usort([otp_13260_1(Config) || _ <- lists:seq(1, 3)]), + ok. + +otp_13260_1(Config) -> + Tab = otp_13260, + File = filename(Tab, Config), + N = 20, + P = self(), + Pids = [spawn_link(fun() -> counter(P, Tab, File) end) || + _ <- lists:seq(1, N)], + Rs = rec(Pids), + true = lists:all(fun(R) -> is_integer(R) end, Rs), + wait_for_close(Tab). + +rec([]) -> + []; +rec([Pid | Pids]) -> + receive {Pid, R} -> + [R | rec(Pids)] + end. + +%% One may have to run the test several times to trigger the bug. +counter(P, Tab, File) -> + Key = key, + N = case catch dets:update_counter(Tab, Key, 1) of + {'EXIT', _} -> + {ok, Tab} = dets:open_file(Tab, [{file, File}]), + ok = dets:insert(Tab, {Key, 1}), + dets:update_counter(Tab, Key, 1); + N1 when is_integer(N1) -> + N1; + DetsBug -> + DetsBug + end, + P ! {self(), N}. + +wait_for_close(Tab) -> + case dets:info(Tab, owner) of + undefined -> + ok; + _ -> + timer:sleep(100), + wait_for_close(Tab) + end. + %% %% Parts common to several test cases %% diff --git a/lib/stdlib/test/dict_SUITE.erl b/lib/stdlib/test/dict_SUITE.erl index 648154ebbe..aff73b176d 100644 --- a/lib/stdlib/test/dict_SUITE.erl +++ b/lib/stdlib/test/dict_SUITE.erl @@ -108,7 +108,7 @@ iterate_1(M) -> M(empty, []). iterate_2(M) -> - random:seed(1, 2, 42), + rand:seed(exsplus, {1,2,42}), iter_tree(M, 1000). iter_tree(_M, 0) -> @@ -117,7 +117,7 @@ iter_tree(M, N) -> L = [{I, I} || I <- lists:seq(1, N)], T = M(from_list, L), L = lists:reverse(iterate_tree(M, T)), - R = random:uniform(N), + R = rand:uniform(N), KV = lists:reverse(iterate_tree_from(M, R, T)), KV = [P || P={K,_} <- L, K >= R], iter_tree(M, N-1). @@ -156,7 +156,7 @@ test_all(Tester) -> spawn_tester(M, Tester) -> Parent = self(), spawn_link(fun() -> - random:seed(1, 2, 42), + rand:seed(exsplus, {1,2,42}), S = Tester(M), Res = {M(size, S),lists:sort(M(to_list, S))}, Parent ! {result,self(),Res} @@ -194,12 +194,12 @@ rnd_list_1(0, Acc) -> Acc; rnd_list_1(N, Acc) -> Key = atomic_rnd_term(), - Value = random:uniform(100), + Value = rand:uniform(100), rnd_list_1(N-1, [{Key,Value}|Acc]). atomic_rnd_term() -> - case random:uniform(3) of - 1 -> list_to_atom(integer_to_list($\s+random:uniform(94))++"rnd"); - 2 -> random:uniform(); - 3 -> random:uniform(50)-37 + case rand:uniform(3) of + 1 -> list_to_atom(integer_to_list($\s+rand:uniform(94))++"rnd"); + 2 -> rand:uniform(); + 3 -> rand:uniform(50)-37 end. diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl index 199d2f193d..4c007e76ad 100644 --- a/lib/stdlib/test/epp_SUITE.erl +++ b/lib/stdlib/test/epp_SUITE.erl @@ -27,7 +27,7 @@ pmod/1, not_circular/1, skip_header/1, otp_6277/1, otp_7702/1, otp_8130/1, overload_mac/1, otp_8388/1, otp_8470/1, otp_8503/1, otp_8562/1, otp_8665/1, otp_8911/1, otp_10302/1, otp_10820/1, - otp_11728/1, encoding/1]). + otp_11728/1, encoding/1, extends/1]). -export([epp_parse_erl_form/2]). @@ -70,7 +70,7 @@ all() -> not_circular, skip_header, otp_6277, otp_7702, otp_8130, overload_mac, otp_8388, otp_8470, otp_8503, otp_8562, otp_8665, otp_8911, otp_10302, otp_10820, otp_11728, - encoding]. + encoding, extends]. groups() -> [{upcase_mac, [], [upcase_mac_1, upcase_mac_2]}, @@ -621,6 +621,10 @@ otp_8130(Config) when is_list(Config) -> " 2 end,\n" " 7),\n" " {2,7} =\n" + " ?M1(begin 1 = fun _Name () -> 1 end(),\n" + " 2 end,\n" + " 7),\n" + " {2,7} =\n" " ?M1(begin 1 = fun t0/0(),\n" " 2 end,\n" " 7),\n" @@ -645,6 +649,9 @@ otp_8130(Config) when is_list(Config) -> " ?M1(begin yes = try 1 of 1 -> yes after foo end,\n" " 2 end,\n" " 7),\n" + " {[42],7} =\n" + " ?M1([42],\n" + " 7),\n" "ok.\n">>, ok}, @@ -728,11 +735,16 @@ otp_8130(Config) when is_list(Config) -> {errors,[{{2,2},epp,{include,lib,"$apa/foo.hrl"}}],[]}}, - {otp_8130_c9, + {otp_8130_c9a, <<"-define(S, ?S).\n" "t() -> ?S.\n">>, {errors,[{{2,9},epp,{circular,'S', none}}],[]}}, + {otp_8130_c9b, + <<"-define(S(), ?S()).\n" + "t() -> ?S().\n">>, + {errors,[{{2,9},epp,{circular,'S', 0}}],[]}}, + {otp_8130_c10, <<"\n-file.">>, {errors,[{{2,2},epp,{bad,file}}],[]}}, @@ -799,6 +811,10 @@ otp_8130(Config) when is_list(Config) -> <<"\n-include(\"no such file.erl\").\n">>, {errors,[{{2,2},epp,{include,file,"no such file.erl"}}],[]}}, + {otp_8130_c25, + <<"\n-define(A.\n">>, + {errors,[{{2,2},epp,{bad,define}}],[]}}, + {otp_8130_7, <<"-record(b, {b}).\n" "-define(A, {{a,#b.b.\n" @@ -1476,6 +1492,20 @@ encoding(Config) when is_list(Config) -> epp_parse_file(ErlFile, [{default_encoding,utf8},extra]), ok. +extends(Config) -> + Cs = [{extends_c1, + <<"-extends(some.other.module).\n">>, + {errors,[{1,erl_parse,["syntax error before: ","'.'"]}],[]}}], + [] = compile(Config, Cs), + + Ts = [{extends_1, + <<"-extends(some_other_module).\n" + "t() -> {?BASE_MODULE,?BASE_MODULE_STRING}.\n">>, + {some_other_module,"some_other_module"}}], + + [] = run(Config, Ts), + ok. + check(Config, Tests) -> eval_tests(Config, fun check_test/2, Tests). @@ -1504,15 +1534,17 @@ eval_tests(Config, Fun, Tests) -> check_test(Config, Test) -> Filename = "epp_test.erl", - ?line PrivDir = ?config(priv_dir, Config), - ?line File = filename:join(PrivDir, Filename), - ?line ok = file:write_file(File, Test), - ?line case epp:parse_file(File, [PrivDir], []) of - {ok,Forms} -> - [E || E={error,_} <- Forms]; - {error,Error} -> - Error - end. + PrivDir = ?config(priv_dir, Config), + File = filename:join(PrivDir, Filename), + ok = file:write_file(File, Test), + case epp:parse_file(File, [PrivDir], []) of + {ok,Forms} -> + Errors = [E || E={error,_} <- Forms], + call_format_error([E || {error,E} <- Errors]), + Errors; + {error,Error} -> + Error + end. compile_test(Config, Test0) -> Test = [<<"-module(epp_test). -compile(export_all). ">>, Test0], diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index b9c4ad0a46..c21c4e61ee 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2013. All Rights Reserved. +%% Copyright Ericsson AB 1998-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -39,6 +39,7 @@ otp_7550/1, otp_8133/1, otp_10622/1, + otp_13228/1, funs/1, try_catch/1, eval_expr_5/1, @@ -83,7 +84,8 @@ all() -> pattern_expr, match_bin, guard_3, guard_4, guard_5, lc, simple_cases, unary_plus, apply_atom, otp_5269, otp_6539, otp_6543, otp_6787, otp_6977, otp_7550, - otp_8133, otp_10622, funs, try_catch, eval_expr_5, zero_width, + otp_8133, otp_10622, otp_13228, + funs, try_catch, eval_expr_5, zero_width, eep37, eep43]. groups() -> @@ -1042,6 +1044,13 @@ otp_10622(Config) when is_list(Config) -> ok. +otp_13228(doc) -> + ["OTP-13228. ERL-32: non-local function handler bug."]; +otp_13228(_Config) -> + LFH = {value, fun(foo, [io_fwrite]) -> worked end}, + EFH = {value, fun({io, fwrite}, [atom]) -> io_fwrite end}, + {value, worked, []} = parse_and_run("foo(io:fwrite(atom)).", LFH, EFH). + funs(doc) -> ["Simple cases, just to cover some code."]; funs(suite) -> @@ -1483,6 +1492,16 @@ eep43(Config) when is_list(Config) -> " #{ K1 := 1, K2 := 2, K3 := 3, {2,2} := 4} = Map " "end.", #{ 1 => 1, <<42:301>> => 2, {3,<<42:301>>} => 3, {2,2} => 4}), + check(fun () -> + X = key, + (fun(#{X := value}) -> true end)(#{X => value}) + end, + "begin " + " X = key, " + " (fun(#{X := value}) -> true end)(#{X => value}) " + "end.", + true), + error_check("[camembert]#{}.", {badmap,[camembert]}), error_check("[camembert]#{nonexisting:=v}.", {badmap,[camembert]}), error_check("#{} = 1.", {badmatch,1}), diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 6c07dc1ec6..c5e2e5609d 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2015. All Rights Reserved. +%% Copyright Ericsson AB 1999-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -65,7 +65,7 @@ too_many_arguments/1, basic_errors/1,bin_syntax_errors/1, predef/1, - maps/1,maps_type/1,otp_11851/1 + maps/1,maps_type/1,otp_11851/1,otp_11879/1,otp_13230/1 ]). % Default timetrap timeout (set in init_per_testcase). @@ -94,7 +94,7 @@ all() -> bif_clash, behaviour_basic, behaviour_multiple, otp_11861, otp_7550, otp_8051, format_warn, {group, on_load}, too_many_arguments, basic_errors, bin_syntax_errors, predef, - maps, maps_type, otp_11851]. + maps, maps_type, otp_11851, otp_11879, otp_13230]. groups() -> [{unused_vars_warn, [], @@ -1296,12 +1296,16 @@ unsized_binary_in_bin_gen_pattern(Config) when is_list(Config) -> Ts = [{unsized_binary_in_bin_gen_pattern, <<"t({bc,binary,Bin}) -> << <<X,Tail/binary>> || <<X,Tail/binary>> <= Bin >>; + t({bc,bytes,Bin}) -> + << <<X,Tail/binary>> || <<X,Tail/bytes>> <= Bin >>; t({bc,bits,Bin}) -> << <<X,Tail/bits>> || <<X,Tail/bits>> <= Bin >>; t({bc,bitstring,Bin}) -> << <<X,Tail/bits>> || <<X,Tail/bitstring>> <= Bin >>; t({lc,binary,Bin}) -> [ {X,Tail} || <<X,Tail/binary>> <= Bin ]; + t({lc,bytes,Bin}) -> + [ {X,Tail} || <<X,Tail/bytes>> <= Bin ]; t({lc,bits,Bin}) -> [ {X,Tail} || <<X,Tail/bits>> <= Bin ]; t({lc,bitstring,Bin}) -> @@ -1313,7 +1317,9 @@ unsized_binary_in_bin_gen_pattern(Config) when is_list(Config) -> {6,erl_lint,unsized_binary_in_bin_gen_pattern}, {8,erl_lint,unsized_binary_in_bin_gen_pattern}, {10,erl_lint,unsized_binary_in_bin_gen_pattern}, - {12,erl_lint,unsized_binary_in_bin_gen_pattern}], + {12,erl_lint,unsized_binary_in_bin_gen_pattern}, + {14,erl_lint,unsized_binary_in_bin_gen_pattern}, + {16,erl_lint,unsized_binary_in_bin_gen_pattern}], []}}], [] = run(Config, Ts), ok. @@ -3604,7 +3610,10 @@ bin_syntax_errors(Config) -> t(<<X/unit:8>>) -> X; t(<<X:7/float>>) -> X; t(<< <<_:8>> >>) -> ok; - t(<<(x ! y):8/integer>>) -> ok. + t(<<(x ! y):8/integer>>) -> ok; + t(X) -> + {<<X/binary-integer>>,<<X/signed-unsigned-integer>>, + <<X/little-big>>,<<X/unit:4-unit:8>>}. ">>, [], {error,[{1,erl_lint,illegal_bitsize}, @@ -3613,7 +3622,12 @@ bin_syntax_errors(Config) -> {4,erl_lint,{undefined_bittype,bad_type}}, {5,erl_lint,bittype_unit}, {7,erl_lint,illegal_pattern}, - {8,erl_lint,illegal_pattern}], + {8,erl_lint,illegal_pattern}, + {10,erl_lint,{bittype_mismatch,integer,binary,"type"}}, + {10,erl_lint,{bittype_mismatch,unsigned,signed,"sign"}}, + {11,erl_lint,{bittype_mismatch,8,4,"unit"}}, + {11,erl_lint,{bittype_mismatch,big,little,"endianness"}} + ], [{6,erl_lint,{bad_bitsize,"float"}}]}} ], [] = run(Config, Ts), @@ -3835,6 +3849,38 @@ otp_11851(Config) when is_list(Config) -> [] = run(Config, Ts), ok. +otp_11879(doc) -> + "OTP-11879: The -spec f/a :: (As) -> B; syntax removed, " + "and is_subtype/2 deprecated"; +otp_11879(_Config) -> + Fs = [{attribute,0,file,{"file.erl",0}}, + {attribute,0,module,m}, + {attribute,1,spec, + {{f,1}, + [{type,2,'fun',[{type,3,product,[{var,4,'V1'}, + {var,5,'V1'}]}, + {type,6,integer,[]}]}]}}, + {attribute,20,callback, + {{cb,21}, + [{type,22,'fun',[{type,23,product,[{var,24,'V1'}, + {var,25,'V1'}]}, + {type,6,integer,[]}]}]}}], + {error,[{"file.erl", + [{1,erl_lint,{spec_fun_undefined,{f,1}}}, + {2,erl_lint,spec_wrong_arity}, + {22,erl_lint,callback_wrong_arity}]}], + []} = compile:forms(Fs, [return,report]), + ok. + +otp_13230(doc) -> + "OTP-13230: -deprecated without -module"; +otp_13230(Config) when is_list(Config) -> + Abstr = <<"-deprecated([{frutt,0,next_version}]).">>, + {errors,[{1,erl_lint,undefined_module}, + {1,erl_lint,{bad_deprecated,{frutt,0}}}], + []} = run_test2(Config, Abstr, []), + ok. + run(Config, Tests) -> F = fun({N,P,Ws,E}, BadL) -> case catch run_test(Config, P, Ws) of @@ -3886,22 +3932,35 @@ run_test2(Conf, Test, Warnings0) -> %% is no reason to produce an output file since we are only %% interested in the errors and warnings. - %% Print warnings, call erl_lint:format_error/1. + %% Print warnings, call erl_lint:format_error/1. (But note that + %% the compiler will ignore failing calls to erl_lint:format_error/1.) compile:file(File, [binary,report|Opts]), case compile:file(File, [binary|Opts]) of - {ok, _M, Code, Ws} when is_binary(Code) -> warnings(File, Ws); - {error, [{File,Es}], []} -> {errors, Es, []}; - {error, [{File,Es}], [{File,Ws}]} -> {error, Es, Ws}; - {error, [{File,Es1},{File,Es2}], []} -> {errors2, Es1, Es2} + {ok, _M, Code, Ws} when is_binary(Code) -> + warnings(File, Ws); + {error, [{File,Es}], []} -> + {errors, call_format_error(Es), []}; + {error, [{File,Es}], [{File,Ws}]} -> + {error, call_format_error(Es), call_format_error(Ws)}; + {error, [{File,Es1},{File,Es2}], []} -> + {errors2, Es1, Es2} end. warnings(File, Ws) -> case lists:append([W || {F, W} <- Ws, F =:= File]) of - [] -> []; - L -> {warnings, L} + [] -> + []; + L -> + {warnings, call_format_error(L)} end. +call_format_error(L) -> + %% Smoke test of format_error/1 to make sure that no crashes + %% slip through. + _ = [Mod:format_error(Term) || {_,Mod,Term} <- L], + L. + fail() -> io:format("failed~n"), ?t:fail(). diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index 9bb193d865..8a128b3815 100644 --- a/lib/stdlib/test/erl_pp_SUITE.erl +++ b/lib/stdlib/test/erl_pp_SUITE.erl @@ -876,6 +876,9 @@ type_examples() -> {ex30,<<"-type t99() ::" "{t2(),'\\'t::4'(),t5(),t6(),t7(),t8(),t10(),t14()," "t15(),t20(),t21(), t22(),t25()}. ">>}, + %% Writing constraints as is_subtype(V, T) is not supported since + %% Erlang/OTP 19.0, but as long as the parser recognizes the + %% is_subtype(V, T) syntax, we need a few examples of the syntax. {ex31,<<"-spec t1(FooBar :: t99()) -> t99();" "(t2()) -> t2();" "('\\'t::4'()) -> '\\'t::4'() when is_subtype('\\'t::4'(), t24);" @@ -962,6 +965,9 @@ maps_syntax(Config) when is_list(Config) -> "-compile(export_all).\n" "-type t1() :: map().\n" "-type t2() :: #{ atom() => integer(), atom() => float() }.\n" + "-type u() :: #{a => (I :: integer()) | (A :: atom()),\n" + " (X :: atom()) | (Y :: atom()) =>\n" + " (I :: integer()) | (A :: atom())}.\n" "-spec f1(t1()) -> 'true'.\n" "f1(M) when is_map(M) -> true.\n" "-spec f2(t2()) -> integer().\n" @@ -997,18 +1003,10 @@ otp_8567(Config) when is_list(Config) -> "t() ->\n" " 3.\n" "\n" - "-spec(t1/1 :: (ot()) -> ot1()).\n" - "t1(A) ->\n" - " A.\n" - "\n" "-spec(t2 (ot()) -> ot1()).\n" "t2(A) ->\n" " A.\n" "\n" - "-spec(otp_8567:t3/1 :: (ot()) -> ot1()).\n" - "t3(A) ->\n" - " A.\n" - "\n" "-spec(otp_8567:t4 (ot()) -> ot1()).\n" "t4(A) ->\n" " A.\n">>, diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 1b80f555d7..3e63d19213 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -112,9 +112,8 @@ -define(m(A,B), ?line assert_eq(A,B)). init_per_testcase(Case, Config) -> - Seed = {S1,S2,S3} = random:seed0(), %now(), - random:seed(S1,S2,S3), - io:format("*** SEED: ~p ***\n", [Seed]), + rand:seed(exsplus), + io:format("*** SEED: ~p ***\n", [rand:export_seed()]), start_spawn_logger(), wait_for_test_procs(), %% Ensure previous case cleaned up Dog=test_server:timetrap(test_server:minutes(20)), @@ -1330,7 +1329,7 @@ drop_match() -> ets_match(Tab,Expr) -> - case random:uniform(2) of + case rand:uniform(2) of 1 -> ets:match(Tab,Expr); _ -> @@ -1339,14 +1338,14 @@ ets_match(Tab,Expr) -> match_chunked(Tab,Expr) -> match_chunked_collect(ets:match(Tab,Expr, - random:uniform(1999) + 1)). + rand:uniform(1999) + 1)). match_chunked_collect('$end_of_table') -> []; match_chunked_collect({Results, Continuation}) -> Results ++ match_chunked_collect(ets:match(Continuation)). ets_match_object(Tab,Expr) -> - case random:uniform(2) of + case rand:uniform(2) of 1 -> ets:match_object(Tab,Expr); _ -> @@ -1355,7 +1354,7 @@ ets_match_object(Tab,Expr) -> match_object_chunked(Tab,Expr) -> match_object_chunked_collect(ets:match_object(Tab,Expr, - random:uniform(1999) + 1)). + rand:uniform(1999) + 1)). match_object_chunked_collect('$end_of_table') -> []; match_object_chunked_collect({Results, Continuation}) -> @@ -1367,19 +1366,15 @@ random_test() -> ?line ReadDir = get(where_to_read), ?line WriteDir = get(where_to_write), ?line (catch file:make_dir(WriteDir)), - ?line Seed = case file:consult(filename:join([ReadDir, - "preset_random_seed.txt"])) of - {ok,[X]} -> - X; - _ -> - {A,B,C} = erlang:timestamp(), - random:seed(A,B,C), - get(random_seed) - end, - put(random_seed,Seed), - ?line {ok, F} = file:open(filename:join([WriteDir, - "last_random_seed.txt"]), - [write]), + case file:consult(filename:join([ReadDir,"preset_random_seed.txt"])) of + {ok,[X]} -> + rand:seed(X); + _ -> + rand:seed(exsplus) + end, + Seed = rand:export_seed(), + {ok,F} = file:open(filename:join([WriteDir,"last_random_seed.txt"]), + [write]), io:format(F,"~p. ~n",[Seed]), file:close(F), io:format("Random seed ~p written to ~s, copy to ~s to rerun with " @@ -1401,7 +1396,7 @@ do_random_test() -> end, 5000), ?line io:format("~nData inserted~n"), ?line do_n_times(fun() -> - ?line I = random:uniform(25), + I = rand:uniform(25), ?line Key = create_random_string(I) ++ '_', ?line L1 = ets_match_object(OrdSet,{Key,'_'}), ?line L2 = lists:sort(ets_match_object(Set,{Key,'_'})), @@ -1961,7 +1956,7 @@ evil_update_counter(Config) when is_list(Config) -> gb_sets:module_info(), math:module_info(), ordsets:module_info(), - random:module_info(), + rand:module_info(), repeat_for_opts(evil_update_counter_do). @@ -1995,7 +1990,7 @@ evil_counter(I,Opts) -> 1 -> 16#12345678FFFFFFFF; 2 -> 16#7777777777FFFFFFFF863648726743 end, - Start = Start0 + random:uniform(100000), + Start = Start0 + rand:uniform(100000), ets:insert(T, {dracula,Start}), Iter = 40000, End = Start + Iter, @@ -4645,11 +4640,11 @@ create_random_string(0) -> []; create_random_string(OfLength) -> - C = case random:uniform(2) of + C = case rand:uniform(2) of 1 -> - (random:uniform($Z - $A + 1) - 1) + $A; + (rand:uniform($Z - $A + 1) - 1) + $A; _ -> - (random:uniform($z - $a + 1) - 1) + $a + (rand:uniform($z - $a + 1) - 1) + $a end, [C | create_random_string(OfLength - 1)]. @@ -4660,7 +4655,7 @@ create_random_tuple(OfLength) -> end,create_random_string(OfLength))). create_partly_bound_tuple(OfLength) -> - case random:uniform(2) of + case rand:uniform(2) of 1 -> create_partly_bound_tuple1(OfLength); _ -> @@ -4669,14 +4664,14 @@ create_partly_bound_tuple(OfLength) -> create_partly_bound_tuple1(OfLength) -> T0 = create_random_tuple(OfLength), - I = random:uniform(OfLength), + I = rand:uniform(OfLength), setelement(I,T0,'$1'). set_n_random_elements(T0,0,_,_) -> T0; set_n_random_elements(T0,N,OfLength,GenFun) -> - I = random:uniform(OfLength), + I = rand:uniform(OfLength), What = GenFun(I), case element(I,T0) of What -> @@ -4690,12 +4685,12 @@ make_dollar_atom(I) -> list_to_atom([$$] ++ integer_to_list(I)). create_partly_bound_tuple2(OfLength) -> T0 = create_random_tuple(OfLength), - I = random:uniform(OfLength - 1), + I = rand:uniform(OfLength - 1), set_n_random_elements(T0,I,OfLength,fun make_dollar_atom/1). create_partly_bound_tuple3(OfLength) -> T0 = create_random_tuple(OfLength), - I = random:uniform(OfLength - 1), + I = rand:uniform(OfLength - 1), set_n_random_elements(T0,I,OfLength,fun(_) -> '_' end). do_n_times(_,0) -> @@ -5058,11 +5053,12 @@ meta_wb_do(Opts) -> io:format("Colliding names = ~p\n",[Names]), F = fun(0,_,_) -> ok; - (N,Tabs,Me) -> Name1 = lists:nth(random:uniform(Len),Names), - Name2 = lists:nth(random:uniform(Len),Names), - Op = element(random:uniform(3),OpFuns), - NTabs = Op(Name1, Name2, Tabs, Opts), - Me(N-1,NTabs,Me) + (N,Tabs,Me) -> + Name1 = lists:nth(rand:uniform(Len), Names), + Name2 = lists:nth(rand:uniform(Len), Names), + Op = element(rand:uniform(3),OpFuns), + NTabs = Op(Name1, Name2, Tabs, Opts), + Me(N-1, NTabs, Me) end, F(Len*100, [], F), @@ -5328,7 +5324,7 @@ smp_insert(suite) -> []; smp_insert(Config) when is_list(Config) -> ets_new(smp_insert,[named_table,public,{write_concurrency,true}]), InitF = fun(_) -> ok end, - ExecF = fun(_) -> true = ets:insert(smp_insert,{random:uniform(10000)}) + ExecF = fun(_) -> true = ets:insert(smp_insert,{rand:uniform(10000)}) end, FiniF = fun(_) -> ok end, run_workers(InitF,ExecF,FiniF,100000), @@ -5579,10 +5575,10 @@ smp_select_delete(Config) when is_list(Config) -> Zeros = erlang:make_tuple(Mod,0), InitF = fun(_) -> Zeros end, ExecF = fun(Diffs0) -> - case random:uniform(20) of + case rand:uniform(20) of 1 -> Mod = 17, - Eq = random:uniform(Mod) - 1, + Eq = rand:uniform(Mod) - 1, Deleted = ets:select_delete(T, [{{'_', '$1'}, [{'=:=', {'rem', '$1', Mod}, Eq}], @@ -5591,7 +5587,7 @@ smp_select_delete(Config) when is_list(Config) -> element(Eq+1,Diffs0) - Deleted), Diffs1; _ -> - Key = random:uniform(10000), + Key = rand:uniform(10000), Eq = Key rem Mod, ?line case ets:insert_new(T,{Key,Key}) of true -> @@ -5795,7 +5791,7 @@ run_workers_do(InitF,ExecF,FiniF,Laps, Exclude) -> N when (N > Exclude) -> N - Exclude end, io:format("smp starting ~p workers\n",[NumOfProcs]), - Seeds = [{ProcN,random:uniform(9999)} || ProcN <- lists:seq(1,NumOfProcs)], + Seeds = [{ProcN,rand:uniform(9999)} || ProcN <- lists:seq(1,NumOfProcs)], Parent = self(), Pids = [my_spawn_link(fun()-> worker(Seed,InitF,ExecF,FiniF,Laps,Parent,NumOfProcs) end) || Seed <- Seeds], @@ -5806,7 +5802,7 @@ run_workers_do(InitF,ExecF,FiniF,Laps, Exclude) -> worker({ProcN,Seed}, InitF, ExecF, FiniF, Laps, Parent, NumOfProcs) -> io:format("smp worker ~p, seed=~p~n",[self(),Seed]), - random:seed(Seed,Seed,Seed), + rand:seed(exsplus, {Seed,Seed,Seed}), State1 = InitF([ProcN, NumOfProcs]), State2 = worker_loop(Laps, ExecF, State1), Result = FiniF(State2), diff --git a/lib/stdlib/test/ets_tough_SUITE.erl b/lib/stdlib/test/ets_tough_SUITE.erl index c6f24fc670..8a7f2b1ec2 100644 --- a/lib/stdlib/test/ets_tough_SUITE.erl +++ b/lib/stdlib/test/ets_tough_SUITE.erl @@ -92,7 +92,7 @@ ex1_sub(Config) -> ok. prep(Config) -> - random:seed(), + rand:seed(exsplus), put(dump_ticket,none), DumpDir = filename:join(?config(priv_dir,Config), "ets_tough"), file:make_dir(DumpDir), @@ -221,19 +221,19 @@ random_class() -> random_element(Classes). random_key() -> - random:uniform(8). + rand:uniform(8). random_value() -> - case random:uniform(5) of + case rand:uniform(5) of 1 -> ok; 2 -> {data,random_key()}; 3 -> {foo,bar,random_class()}; - 4 -> random:uniform(1000); + 4 -> rand:uniform(1000); 5 -> {recursive,random_value()} end. random_element(T) -> - I = random:uniform(tuple_size(T)), + I = rand:uniform(tuple_size(T)), element(I,T). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl index 01b798faef..c39ff842ee 100644 --- a/lib/stdlib/test/filelib_SUITE.erl +++ b/lib/stdlib/test/filelib_SUITE.erl @@ -318,7 +318,7 @@ same_lists(Expected0, Actual0, BaseDir) -> mkfiles([H|T], Dir) -> Name = filename:join(Dir, H), - Garbage = [31+random:uniform(95) || _ <- lists:seq(1, random:uniform(1024))], + Garbage = [31+rand:uniform(95) || _ <- lists:seq(1, rand:uniform(1024))], file:write_file(Name, Garbage), [Name|mkfiles(T, Dir)]; mkfiles([], _) -> []. diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl index a0f7fd2744..bd68c93779 100644 --- a/lib/stdlib/test/lists_SUITE.erl +++ b/lib/stdlib/test/lists_SUITE.erl @@ -1677,8 +1677,7 @@ check_stab(L, U, S, US, SS) -> %%% Element 3 in the tuple is the position of the tuple in the list. biglist(N) -> - {A, B, C} = get_seed(), - random:seed(A, B, C), + rand:seed(exsplus), biglist(N, []). biglist(0, L) -> @@ -1694,8 +1693,7 @@ biglist(N, L) -> %%% No sequence number. ubiglist(N) -> - {A, B, C} = get_seed(), - random:seed(A, B, C), + rand:seed(exsplus), ubiglist(N, []). ubiglist(0, L) -> @@ -1719,8 +1717,7 @@ urandom_tuple(N, I) -> %%% sequence number. bigfunlist(N) -> - {A, B, C} = get_seed(), - random:seed(A, B, C), + rand:seed(exsplus), bigfunlist_1(N). bigfunlist_1(N) when N < 30000 -> % Now (R8) max 32000 different pids. @@ -1754,21 +1751,13 @@ make_fun(Pid) -> fun_pid(Fun) -> erlang:fun_info(Fun, pid). -get_seed() -> - case random:seed() of - undefined -> - erlang:timestamp(); - Tuple -> - Tuple - end. - random_tuple(N, Seq) -> R1 = randint(N), R2 = randint(N), {R1, R2, Seq}. randint(N) -> - trunc(random:uniform() * N). + trunc(rand:uniform() * N). %% The first "duplicate" is kept. no_dups([]) -> @@ -1830,8 +1819,7 @@ sort_loop_1(Pid) -> end. sloop(N) -> - {A, B, C} = get_seed(), - random:seed(A, B, C), + rand:seed(exsplus), sloop(N, #state{}). sloop(N, S) -> diff --git a/lib/stdlib/test/queue_SUITE.erl b/lib/stdlib/test/queue_SUITE.erl index c965a8b218..5165ac3a3a 100644 --- a/lib/stdlib/test/queue_SUITE.erl +++ b/lib/stdlib/test/queue_SUITE.erl @@ -470,7 +470,7 @@ oops(suite) -> oops(Config) when is_list(Config) -> ?line N = 3142, ?line Optab = optab(), - ?line Seed0 = random:seed0(), + ?line Seed0 = rand:seed(exsplus, {1,2,4}), ?line {Is,Seed} = random_list(N, tuple_size(Optab), Seed0, []), ?line io:format("~p ", [Is]), ?line QA = queue:new(), @@ -562,20 +562,20 @@ args([], _, Seed, R) -> args([q|Ts], [Q|Qs]=Qss, Seed, R) -> args(Ts, if Qs =:= [] -> Qss; true -> Qs end, Seed, [Q|R]); args([l|Ts], Qs, Seed0, R) -> - {N,Seed1} = random:uniform_s(17, Seed0), + {N,Seed1} = rand:uniform_s(17, Seed0), {L,Seed} = random_list(N, 4711, Seed1, []), args(Ts, Qs, Seed, [L|R]); args([t|Ts], Qs, Seed0, R) -> - {T,Seed} = random:uniform_s(4711, Seed0), + {T,Seed} = rand:uniform_s(4711, Seed0), args(Ts, Qs, Seed, [T|R]); args([n|Ts], Qs, Seed0, R) -> - {N,Seed} = random:uniform_s(17, Seed0), + {N,Seed} = rand:uniform_s(17, Seed0), args(Ts, Qs, Seed, [N|R]). random_list(0, _, Seed, R) -> {R,Seed}; random_list(N, M, Seed0, R) -> - {X,Seed} = random:uniform_s(M, Seed0), + {X,Seed} = rand:uniform_s(M, Seed0), random_list(N-1, M, Seed, [X|R]). call(Func, As) -> diff --git a/lib/stdlib/test/rand_SUITE.erl b/lib/stdlib/test/rand_SUITE.erl index 111bf620de..03b5ce1a25 100644 --- a/lib/stdlib/test/rand_SUITE.erl +++ b/lib/stdlib/test/rand_SUITE.erl @@ -126,6 +126,9 @@ seed_1(Alg) -> false = (S1 =:= rand:seed_s(Alg)), %% Negative integers works _ = rand:seed_s(Alg, {-1,-1,-1}), + %% Check that export_seed/1 returns 'undefined' if there is no seed + erase(rand_seed), + undefined = rand:export_seed(), %% Other term do not work {'EXIT', _} = (catch rand:seed_s(foobar, os:timestamp())), diff --git a/lib/stdlib/test/random_iolist.erl b/lib/stdlib/test/random_iolist.erl index 9a0f034e72..6da7da04de 100644 --- a/lib/stdlib/test/random_iolist.erl +++ b/lib/stdlib/test/random_iolist.erl @@ -36,7 +36,7 @@ run2(Iter,Fun1,Fun2) -> compare2(Iter,Fun1,Fun2). random_byte() -> - random:uniform(256) - 1. + rand:uniform(256) - 1. random_list(0,Acc) -> Acc; @@ -45,7 +45,7 @@ random_list(N,Acc) -> random_binary(N) -> B = list_to_binary(random_list(N,[])), - case {random:uniform(2),size(B)} of + case {rand:uniform(2),size(B)} of {2,M} when M > 1 -> S = M-1, <<_:3,C:S/binary,_:5>> = B, @@ -57,7 +57,7 @@ random_list(N) -> random_list(N,[]). front() -> - case random:uniform(10) of + case rand:uniform(10) of 10 -> false; _ -> @@ -65,7 +65,7 @@ front() -> end. any_type() -> - case random:uniform(10) of + case rand:uniform(10) of 1 -> list; 2 -> @@ -77,7 +77,7 @@ any_type() -> end. tail_type() -> - case random:uniform(5) of + case rand:uniform(5) of 1 -> list; 2 -> @@ -90,9 +90,9 @@ random_length(N) -> UpperLimit = 255, case N of M when M > UpperLimit -> - random:uniform(UpperLimit+1) - 1; + rand:uniform(UpperLimit+1) - 1; _ -> - random:uniform(N+1) - 1 + rand:uniform(N+1) - 1 end. random_iolist(0,Acc) -> @@ -139,7 +139,7 @@ random_iolist(N) -> standard_seed() -> - random:seed(1201,855653,380975). + rand:seed(exsplus, {1201,855653,380975}). do_comp(List,F1,F2) -> X = F1(List), diff --git a/lib/stdlib/test/random_unicode_list.erl b/lib/stdlib/test/random_unicode_list.erl index ecafe42318..3bc86a8430 100644 --- a/lib/stdlib/test/random_unicode_list.erl +++ b/lib/stdlib/test/random_unicode_list.erl @@ -85,7 +85,7 @@ int_to_utf32_little(I) -> id(I) -> I. random_char() -> - case random:uniform(16#10FFFF+1) - 1 of + case rand:uniform(16#10FFFF+1) - 1 of X when X >= 16#D800, X =< 16#DFFF -> random_char(); @@ -116,13 +116,13 @@ random_binary(N,Enc) -> int_to(Enc,X) end, L)), - case {random:uniform(3),size(B)} of + case {rand:uniform(3),size(B)} of {2,M} when M > 1 -> B2 = id(<<1:3,B/binary,1:5>>), <<_:3,C:M/binary,_:5>> = B2, C; {3,M} when M > 1 -> - X = random:uniform(M+1)-1, + X = rand:uniform(M+1)-1, <<B1:X/binary,B2/binary>> = B, [B1,B2]; _ -> @@ -132,7 +132,7 @@ random_list(N) -> random_list(N,[]). front() -> - case random:uniform(10) of + case rand:uniform(10) of 10 -> false; _ -> @@ -140,7 +140,7 @@ front() -> end. any_type() -> - case random:uniform(10) of + case rand:uniform(10) of 1 -> list; 2 -> @@ -152,7 +152,7 @@ any_type() -> end. tail_type() -> - case random:uniform(5) of + case rand:uniform(5) of 1 -> list; 2 -> @@ -165,9 +165,9 @@ random_length(N) -> UpperLimit = 255, case N of M when M > UpperLimit -> - random:uniform(UpperLimit+1) - 1; + rand:uniform(UpperLimit+1) - 1; _ -> - random:uniform(N+1) - 1 + rand:uniform(N+1) - 1 end. random_unicode_list(0,Acc,_Enc) -> @@ -214,7 +214,7 @@ random_unicode_list(N,Enc) -> standard_seed() -> - random:seed(1201,855653,380975). + rand:seed(exsplus, {1201,855653,380975}). do_comp(List,F1,F2) -> X = F1(List), diff --git a/lib/stdlib/test/run_pcre_tests.erl b/lib/stdlib/test/run_pcre_tests.erl index 1fdc777470..b7d1df39b8 100644 --- a/lib/stdlib/test/run_pcre_tests.erl +++ b/lib/stdlib/test/run_pcre_tests.erl @@ -1083,7 +1083,7 @@ dumponesplit(F,{RE,Line,O,TS}) -> %% Generate replacement tests from indatafile, %% you will need perl on the machine gen_repl_test(OneFile) -> - random:seed(1219,687731,62804), + rand:seed(exsplus, {1219,687731,62804}), {ok,Bin} = file:read_file(OneFile), Lines = splitfile(0,Bin,1), Structured = stru(Lines), @@ -1237,15 +1237,15 @@ btr(_) -> ranchar() -> - case random:uniform(10) of + case rand:uniform(10) of 9 -> $&; 10 -> <<"\\1">>; N when N < 5 -> - random:uniform($Z-$A)+$A-1; + rand:uniform($Z-$A)+$A-1; M when M < 9 -> - random:uniform($z-$a)+$a-1 + rand:uniform($z-$a)+$a-1 end. ranstring() -> - iolist_to_binary([ranchar() || _ <- lists:duplicate(random:uniform(20),0) ]). + iolist_to_binary([ranchar() || _ <- lists:duplicate(rand:uniform(20),0) ]). diff --git a/lib/stdlib/test/select_SUITE.erl b/lib/stdlib/test/select_SUITE.erl index ead64ffc75..6796676179 100644 --- a/lib/stdlib/test/select_SUITE.erl +++ b/lib/stdlib/test/select_SUITE.erl @@ -212,11 +212,10 @@ init_random(Config) -> {ok,[X]} -> X; _ -> - {A,B,C} = erlang:timestamp(), - random:seed(A,B,C), - get(random_seed) + rand:seed(exsplus), + rand:export_seed() end, - put(random_seed,Seed), + rand:seed(Seed), {ok, F} = file:open(filename:join([WriteDir, "last_random_seed2.txt"]), [write]), io:format(F,"~p. ~n",[Seed]), @@ -224,11 +223,11 @@ init_random(Config) -> ok. create_random_key(N,Type) -> - gen_key(random:uniform(N),Type). + gen_key(rand:uniform(N),Type). create_pb_key(N,list) -> - X = random:uniform(N), - case random:uniform(4) of + X = rand:uniform(N), + case rand:uniform(4) of 3 -> {[X, X+1, '_'], fun([Z,Z1,P1]) -> [Z,Z1,P1] =:= [X,X+1,P1] end}; 2 -> {[X, '_', '_'], fun([Z,P1,P2]) -> [Z,P1,P2] =:= [X,P1,P2] end}; @@ -237,14 +236,14 @@ create_pb_key(N,list) -> _ -> {[X, '$1', '$2'], fun([Z,P1,P2]) -> [Z,P1,P2] =:= [X,P1,P2] end} end; create_pb_key(N, tuple) -> - X = random:uniform(N), - case random:uniform(2) of + X = rand:uniform(N), + case rand:uniform(2) of 1 -> {{X, X+1, '$1'},fun({Z,Z1,P1}) -> {Z,Z1,P1} =:= {X,X+1,P1} end}; _ -> {{X, '$1', '$2'},fun({Z,P1,P2}) -> {Z,P1,P2} =:= {X,P1,P2} end} end; create_pb_key(N, complex) -> - X = random:uniform(N), - case random:uniform(2) of + X = rand:uniform(N), + case rand:uniform(2) of 1 -> {{[X, X+1], '$1'}, fun({[Z,Z1],P1}) -> {[Z,Z1],P1} =:= {[X,X+1],P1} end}; _ -> {{[X, '$1'], '$2'},fun({[Z,P1],P2}) -> diff --git a/lib/stdlib/test/sets_SUITE.erl b/lib/stdlib/test/sets_SUITE.erl index 972a812072..e7fc5595a9 100644 --- a/lib/stdlib/test/sets_SUITE.erl +++ b/lib/stdlib/test/sets_SUITE.erl @@ -107,9 +107,9 @@ add_element_del([H|T], M, S, Del, []) -> add_element_del(T, M, M(add_element, {H,S}), Del, [H]); add_element_del([H|T], M, S0, Del, Inserted) -> S1 = M(add_element, {H,S0}), - case random:uniform(3) of + case rand:uniform(3) of 1 -> - OldEl = lists:nth(random:uniform(length(Inserted)), Inserted), + OldEl = lists:nth(rand:uniform(length(Inserted)), Inserted), S = M(del_element, {OldEl,S1}), add_element_del(T, M, S, [OldEl|Del], [H|Inserted]); _ -> @@ -438,7 +438,7 @@ iterate_1(M) -> M(empty, []). iterate_2(M) -> - random:seed(1, 2, 42), + rand:seed(exsplus, {1,2,42}), iter_set(M, 1000). iter_set(_M, 0) -> @@ -447,7 +447,7 @@ iter_set(M, N) -> L = [I || I <- lists:seq(1, N)], T = M(from_list, L), L = lists:reverse(iterate_set(M, T)), - R = random:uniform(N), + R = rand:uniform(N), S = lists:reverse(iterate_set(M, R, T)), S = [E || E <- L, E >= R], iter_set(M, N-1). @@ -481,7 +481,7 @@ sets_mods() -> test_all(Tester) -> Res = [begin - random:seed(1, 2, 42), + rand:seed(exsplus, {1,2,42}), S = Tester(M), {M(size, S),lists:sort(M(to_list, S))} end || M <- sets_mods()], @@ -492,7 +492,7 @@ test_all([{Low,High}|T], Tester) -> test_all([Sz|T], Tester) when is_integer(Sz) -> List = rnd_list(Sz), Res = [begin - random:seed(19, 2, Sz), + rand:seed(exsplus, {19,2,Sz}), S = Tester(List, M), {M(size, S),lists:sort(M(to_list, S))} end || M <- sets_mods()], @@ -512,10 +512,10 @@ rnd_list(Sz) -> rnd_list_1(Sz, []). atomic_rnd_term() -> - case random:uniform(3) of - 1 -> list_to_atom(integer_to_list($\s+random:uniform(94))++"rnd"); - 2 -> random:uniform(); - 3 -> random:uniform(50)-37 + case rand:uniform(3) of + 1 -> list_to_atom(integer_to_list($\s+rand:uniform(94))++"rnd"); + 2 -> rand:uniform(); + 3 -> rand:uniform(50)-37 end. rnd_list_1(0, Acc) -> Acc; @@ -543,7 +543,7 @@ remove_some(List0, P) -> end. remove_some([H|T], P, Acc) -> - case random:uniform() of + case rand:uniform() of F when F < P -> %Remove. remove_some(T, P, Acc); _ -> diff --git a/lib/stdlib/test/timer_SUITE.erl b/lib/stdlib/test/timer_SUITE.erl index 057d82fb65..10dcfad76f 100644 --- a/lib/stdlib/test/timer_SUITE.erl +++ b/lib/stdlib/test/timer_SUITE.erl @@ -80,8 +80,6 @@ report_result(Error) -> ?line test_server:fail(Error). big_test(N) -> C = start_collect(), system_time(), system_time(), system_time(), - random:seed(erlang:timestamp()), - random:uniform(100),random:uniform(100),random:uniform(100), big_loop(C, N, []), @@ -127,17 +125,17 @@ big_loop(C, N, Pids) -> after 0 -> %% maybe start an interval timer test - Pids1 = maybe_start_i_test(Pids, C, random:uniform(4)), + Pids1 = maybe_start_i_test(Pids, C, rand:uniform(4)), %% start 1-4 "after" tests - Pids2 = start_after_test(Pids1, C, random:uniform(4)), + Pids2 = start_after_test(Pids1, C, rand:uniform(4)), %%Pids2=Pids1, %% wait a little while - timer:sleep(random:uniform(200)*3), + timer:sleep(rand:uniform(200)*3), %% spawn zero, one or two nrev to get some load ;-/ - Pids3 = start_nrev(Pids2, random:uniform(100)), + Pids3 = start_nrev(Pids2, rand:uniform(100)), big_loop(C, N-1, Pids3) end. @@ -148,20 +146,20 @@ start_nrev(Pids, N) when N < 25 -> start_nrev(Pids, N) when N < 75 -> [spawn_link(timer_SUITE, do_nrev, [1])|Pids]; start_nrev(Pids, _N) -> - NrevPid1 = spawn_link(timer_SUITE, do_nrev, [random:uniform(1000)*10]), + NrevPid1 = spawn_link(timer_SUITE, do_nrev, [rand:uniform(1000)*10]), NrevPid2 = spawn_link(timer_SUITE, do_nrev, [1]), [NrevPid1,NrevPid2|Pids]. start_after_test(Pids, C, 1) -> - TO1 = random:uniform(100)*47, + TO1 = rand:uniform(100)*47, [s_a_t(C, TO1)|Pids]; start_after_test(Pids, C, 2) -> - TO1 = random:uniform(100)*47, - TO2 = TO1 div random:uniform(3) + 101, + TO1 = rand:uniform(100)*47, + TO2 = TO1 div rand:uniform(3) + 101, [s_a_t(C, TO1),s_a_t(C, TO2)|Pids]; start_after_test(Pids, C, N) -> - TO1 = random:uniform(100)*47, + TO1 = rand:uniform(100)*47, start_after_test([s_a_t(C, TO1)|Pids], C, N-1). s_a_t(C, TimeOut) -> @@ -187,8 +185,8 @@ a_t(C, TimeOut) -> maybe_start_i_test(Pids, C, 1) -> %% ok do it - TOI = random:uniform(53)*49, - CountI = random:uniform(10) + 3, % at least 4 times + TOI = rand:uniform(53)*49, + CountI = rand:uniform(10) + 3, % at least 4 times [spawn_link(timer_SUITE, i_t, [C, TOI, CountI])|Pids]; maybe_start_i_test(Pids, _C, _) -> Pids. diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk index 3387d74e57..39b44c9104 100644 --- a/lib/stdlib/vsn.mk +++ b/lib/stdlib/vsn.mk @@ -1 +1 @@ -STDLIB_VSN = 2.6 +STDLIB_VSN = 2.7 |