diff options
Diffstat (limited to 'lib/stdlib')
47 files changed, 1516 insertions, 1666 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/erl_scan.xml b/lib/stdlib/doc/src/erl_scan.xml index 342f491dd0..ee0d6b6033 100644 --- a/lib/stdlib/doc/src/erl_scan.xml +++ b/lib/stdlib/doc/src/erl_scan.xml @@ -40,39 +40,15 @@ </description> <datatypes> <datatype> - <name name="attribute_info"></name> - </datatype> - <datatype> - <name name="attributes"></name> - </datatype> - <datatype> - <name name="attributes_data"></name> - </datatype> - <datatype> <name name="category"></name> </datatype> <datatype> - <name name="column"></name> - </datatype> - <datatype> <name name="error_description"></name> </datatype> <datatype> <name name="error_info"></name> </datatype> <datatype> - <name name="info_line"></name> - </datatype> - <datatype> - <name name="info_location"></name> - </datatype> - <datatype> - <name name="line"></name> - </datatype> - <datatype> - <name name="location"></name> - </datatype> - <datatype> <name name="option"></name> </datatype> <datatype> @@ -88,9 +64,6 @@ <name name="token"></name> </datatype> <datatype> - <name name="token_info"></name> - </datatype> - <datatype> <name name="tokens"></name> </datatype> <datatype> @@ -122,25 +95,23 @@ <anno>StartLocation</anno>, [])</c>.</p> <p><c><anno>StartLocation</anno></c> indicates the initial location when scanning starts. If <c><anno>StartLocation</anno></c> is a line, - <c>attributes()</c> as well as <c><anno>EndLocation</anno></c> and + <c>Anno</c> as well as <c><anno>EndLocation</anno></c> and <c><anno>ErrorLocation</anno></c> will be lines. If <c><anno>StartLocation</anno></c> is a pair of a line and a column - <c>attributes()</c> takes the form of an opaque compound + <c>Anno</c> takes the form of an opaque compound data type, and <c><anno>EndLocation</anno></c> and <c><anno>ErrorLocation</anno></c> will be pairs of a line and a column. The <em>token - attributes</em> contain information about the column and the + annotations</em> contain information about the column and the line where the token begins, as well as the text of the token (if the <c>text</c> option is given), all of which can - be accessed by calling <seealso - marker="#token_info/1">token_info/1,2</seealso>, <seealso - marker="#attributes_info/1">attributes_info/1,2</seealso>, + be accessed by calling <seealso marker="#column/1">column/1</seealso>, <seealso marker="#line/1">line/1</seealso>, <seealso marker="#location/1">location/1</seealso>, and <seealso marker="#text/1">text/1</seealso>.</p> <p>A <em>token</em> is a tuple containing information about - syntactic category, the token attributes, and the actual + syntactic category, the token annotations, and the actual terminal symbol. For punctuation characters (e.g. <c>;</c>, <c>|</c>) and reserved words, the category and the symbol coincide, and the token is represented by a two-tuple. @@ -172,7 +143,7 @@ <item><p>Short for <c>[return_comments, return_white_spaces]</c>.</p> </item> <tag><c>text</c></tag> - <item><p>Include the token's text in the token attributes. The + <item><p>Include the token's text in the token annotation. The text is the part of the input corresponding to the token.</p> </item> </taglist> @@ -306,150 +277,6 @@ </desc> </func> <func> - <name name="token_info" arity="1"/> - <fsummary>Return information about a token</fsummary> - <desc> - <p>Returns a list containing information about the token - <c><anno>Token</anno></c>. The order of the - <c><anno>TokenInfoTuple</anno></c>s is not - defined. See <seealso - marker="#token_info/2">token_info/2</seealso> for - information about specific - <c><anno>TokenInfoTuple</anno></c>s.</p> - <p>Note that if <c>token_info(Token, TokenItem)</c> returns - <c>undefined</c> for some <c>TokenItem</c>, the - item is not included in <c><anno>TokenInfo</anno></c>.</p> - </desc> - </func> - <func> - <name name="token_info" arity="2" clause_i="1"/> - <name name="token_info" arity="2" clause_i="2"/> - <fsummary>Return information about a token</fsummary> - <type name="token_item"/> - <type name="attribute_item"/> - <desc> - <p>Returns a list containing information about the token - <c><anno>Token</anno></c>. If one single - <c><anno>TokenItem</anno></c> is given the returned value is - the corresponding - <c>TokenInfoTuple</c>, or <c>undefined</c> if the - <c>TokenItem</c> has no value. If a list of - <c><anno>TokenItem</anno></c>s is given the result is a list of - <c><anno>TokenInfoTuple</anno></c>. The - <c><anno>TokenInfoTuple</anno></c>s will - appear with the corresponding <c><anno>TokenItem</anno></c>s in - the same order as the <c><anno>TokenItem</anno></c>s - appear in the list of <c>TokenItem</c>s. - <c><anno>TokenItem</anno></c>s with no value are not included - in the list of <c><anno>TokenInfoTuple</anno></c>.</p> - <p>The following <c><anno>TokenInfoTuple</anno></c>s with corresponding - <c><anno>TokenItem</anno></c>s are valid:</p> - <taglist> - <tag><c>{category, </c><seealso marker="#type-category"> - category()</seealso><c>}</c></tag> - <item><p>The category of the token.</p> - </item> - <tag><c>{column, </c><seealso marker="#type-column"> - column()</seealso><c>}</c></tag> - <item><p>The column where the token begins.</p> - </item> - <tag><c>{length, integer() > 0}</c></tag> - <item><p>The length of the token's text.</p> - </item> - <tag><c>{line, </c><seealso marker="#type-line"> - line()</seealso><c>}</c></tag> - <item><p>The line where the token begins.</p> - </item> - <tag><c>{location, </c><seealso marker="#type-location"> - location()</seealso><c>}</c></tag> - <item><p>The line and column where the token begins, or - just the line if the column unknown.</p> - </item> - <tag><c>{symbol, </c><seealso marker="#type-symbol"> - symbol()</seealso><c>}</c></tag> - <item><p>The token's symbol.</p> - </item> - <tag><c>{text, string()}</c></tag> - <item><p>The token's text.</p> - </item> - </taglist> - </desc> - </func> - <func> - <name name="attributes_info" arity="1"/> - <fsummary>Return information about token attributes</fsummary> - <desc> - <p>Returns a list containing information about the token - attributes <c><anno>Attributes</anno></c>. The order of the - <c><anno>AttributeInfoTuple</anno></c>s is not defined. - See <seealso - marker="#attributes_info/2">attributes_info/2</seealso> for - information about specific - <c><anno>AttributeInfoTuple</anno></c>s.</p> - <p>Note that if <c>attributes_info(Token, AttributeItem)</c> - returns <c>undefined</c> for some <c>AttributeItem</c> in - the list above, the item is not included in - <c><anno>AttributesInfo</anno></c>.</p> - </desc> - </func> - <func> - <name name="attributes_info" arity="2" clause_i="1"/> - <name name="attributes_info" arity="2" clause_i="2"/> - <fsummary>Return information about a token attributes</fsummary> - <type name="attribute_item"/> - <desc> - <p>Returns a list containing information about the token - attributes <c><anno>Attributes</anno></c>. If one single - <c><anno>AttributeItem</anno></c> is given the returned value is the - corresponding <c><anno>AttributeInfoTuple</anno></c>, - or <c>undefined</c> if the <c><anno>AttributeItem</anno></c> - has no value. If a list of <c><anno>AttributeItem</anno></c> - is given the result is a list of - <c><anno>AttributeInfoTuple</anno></c>. - The <c><anno>AttributeInfoTuple</anno></c>s - will appear with the corresponding <c><anno>AttributeItem</anno></c>s - in the same order as the <c><anno>AttributeItem</anno></c>s - appear in the list of <c><anno>AttributeItem</anno></c>s. - <c><anno>AttributeItem</anno></c>s with no - value are not included in the list of - <c><anno>AttributeInfoTuple</anno></c>.</p> - <p>The following <c><anno>AttributeInfoTuple</anno></c>s with - corresponding <c><anno>AttributeItem</anno></c>s are valid:</p> - <taglist> - <tag><c>{column, </c><seealso marker="#type-column"> - column()</seealso><c>}</c></tag> - <item><p>The column where the token begins.</p> - </item> - <tag><c>{length, integer() > 0}</c></tag> - <item><p>The length of the token's text.</p> - </item> - <tag><c>{line, </c><seealso marker="#type-line"> - line()</seealso><c>}</c></tag> - <item><p>The line where the token begins.</p> - </item> - <tag><c>{location, </c><seealso marker="#type-location"> - location()</seealso><c>}</c></tag> - <item><p>The line and column where the token begins, or - just the line if the column unknown.</p> - </item> - <tag><c>{text, string()}</c></tag> - <item><p>The token's text.</p> - </item> - </taglist> - </desc> - </func> - <func> - <name name="set_attribute" arity="3"/> - <fsummary>Set a token attribute value</fsummary> - <desc> - <p>Sets the value of the <c>line</c> attribute of the token - attributes <c><anno>Attributes</anno></c>.</p> - <p>The <c><anno>SetAttributeFun</anno></c> is called with the value of - the <c>line</c> attribute, and is to return the new value of - the <c>line</c> attribute.</p> - </desc> - </func> - <func> <name name="format_error" arity="1"/> <fsummary>Format an error descriptor</fsummary> <desc> diff --git a/lib/stdlib/examples/erl_id_trans.erl b/lib/stdlib/examples/erl_id_trans.erl index 529ae30862..c2e345763a 100644 --- a/lib/stdlib/examples/erl_id_trans.erl +++ b/lib/stdlib/examples/erl_id_trans.erl @@ -18,11 +18,11 @@ %% -module(erl_id_trans). -%% A identity transformer of Erlang abstract syntax. +%% An identity transformer of Erlang abstract syntax. %% This module only traverses legal Erlang code. This is most noticeable %% in guards where only a limited number of expressions are allowed. -%% N.B. if this module is to be used as a basis for tranforms then +%% N.B. if this module is to be used as a basis for transforms then %% all the error cases must be handled otherwise this module just crashes! -export([parse_transform/2]). @@ -53,6 +53,17 @@ form({attribute,Line,export,Es0}) -> form({attribute,Line,import,{Mod,Is0}}) -> Is1 = farity_list(Is0), {attribute,Line,import,{Mod,Is1}}; +form({attribute,Line,export_type,Es0}) -> + Es1 = farity_list(Es0), + {attribute,Line,export_type,Es1}; +form({attribute,Line,optional_callbacks,Es0}) -> + try farity_list(Es0) of + Es1 -> + {attribute,Line,optional_callbacks,Es1} + catch + _:_ -> + {attribute,Line,optional_callbacks,Es0} + end; form({attribute,Line,compile,C}) -> {attribute,Line,compile,C}; form({attribute,Line,record,{Name,Defs0}}) -> @@ -60,14 +71,28 @@ form({attribute,Line,record,{Name,Defs0}}) -> {attribute,Line,record,{Name,Defs1}}; form({attribute,Line,asm,{function,N,A,Code}}) -> {attribute,Line,asm,{function,N,A,Code}}; +form({attribute,Line,type,{N,T,Vs}}) -> + T1 = type(T), + Vs1 = variable_list(Vs), + {attribute,Line,type,{N,T1,Vs1}}; +form({attribute,Line,opaque,{N,T,Vs}}) -> + T1 = type(T), + Vs1 = variable_list(Vs), + {attribute,Line,opaque,{N,T1,Vs1}}; +form({attribute,Line,spec,{{N,A},FTs}}) -> + FTs1 = function_type_list(FTs), + {attribute,Line,spec,{{N,A},FTs1}}; +form({attribute,Line,spec,{{M,N,A},FTs}}) -> + FTs1 = function_type_list(FTs), + {attribute,Line,spec,{{M,N,A},FTs1}}; +form({attribute,Line,callback,{{N,A},FTs}}) -> + FTs1 = function_type_list(FTs), + {attribute,Line,callback,{{N,A},FTs1}}; form({attribute,Line,Attr,Val}) -> %The general attribute. {attribute,Line,Attr,Val}; form({function,Line,Name0,Arity0,Clauses0}) -> {Name,Arity,Clauses} = function(Name0, Arity0, Clauses0), {function,Line,Name,Arity,Clauses}; -% Mnemosyne, ignore... -form({rule,Line,Name,Arity,Body}) -> - {rule,Line,Name,Arity,Body}; % Dont dig into this %% Extra forms from the parser. form({error,E}) -> {error,E}; form({warning,W}) -> {warning,W}; @@ -79,6 +104,12 @@ farity_list([{Name,Arity}|Fas]) -> [{Name,Arity}|farity_list(Fas)]; farity_list([]) -> []. +%% -type variable_list([Var]) -> [Var] + +variable_list([{var,Line,Var}|Vs]) -> + [{var,Line,Var}|variable_list(Vs)]; +variable_list([]) -> []. + %% -type record_defs([RecDef]) -> [RecDef]. %% N.B. Field names are full expressions here but only atoms are allowed %% by the *parser*! @@ -88,6 +119,16 @@ record_defs([{record_field,Line,{atom,La,A},Val0}|Is]) -> [{record_field,Line,{atom,La,A},Val1}|record_defs(Is)]; record_defs([{record_field,Line,{atom,La,A}}|Is]) -> [{record_field,Line,{atom,La,A}}|record_defs(Is)]; +record_defs([{typed_record_field,{record_field,Line,{atom,La,A},Val0},Type}| + Is]) -> + Val1 = expr(Val0), + Type1 = type(Type), + [{typed_record_field,{record_field,Line,{atom,La,A},Val1},Type1}| + record_defs(Is)]; +record_defs([{typed_record_field,{record_field,Line,{atom,La,A}},Type}|Is]) -> + Type1 = type(Type), + [{typed_record_field,{record_field,Line,{atom,La,A}},Type1}| + record_defs(Is)]; record_defs([]) -> []. %% -type function(atom(), integer(), [Clause]) -> {atom(),integer(),[Clause]}. @@ -196,9 +237,9 @@ pattern_grp([]) -> bit_types([]) -> []; -bit_types([Atom | Rest]) when atom(Atom) -> +bit_types([Atom | Rest]) when is_atom(Atom) -> [Atom | bit_types(Rest)]; -bit_types([{Atom, Integer} | Rest]) when atom(Atom), integer(Integer) -> +bit_types([{Atom, Integer} | Rest]) when is_atom(Atom), is_integer(Integer) -> [{Atom, Integer} | bit_types(Rest)]. @@ -226,7 +267,7 @@ pattern_fields([]) -> []. %% -type guard([GuardTest]) -> [GuardTest]. -guard([G0|Gs]) when list(G0) -> +guard([G0|Gs]) when is_list(G0) -> [guard0(G0) | guard(Gs)]; guard(L) -> guard0(L). @@ -547,3 +588,97 @@ fun_clauses([C0|Cs]) -> C1 = clause(C0), [C1|fun_clauses(Cs)]; fun_clauses([]) -> []. + +function_type_list([{type,Line,bounded_fun,[Ft,Fc]}|Fts]) -> + Ft1 = function_type(Ft), + Fc1 = function_constraint(Fc), + [{type,Line,bounded_fun,[Ft1,Fc1]}|function_type_list(Fts)]; +function_type_list([Ft|Fts]) -> + [function_type(Ft)|function_type_list(Fts)]; +function_type_list([]) -> []. + +function_type({type,Line,'fun',[{type,Lt,product,As},B]}) -> + As1 = type_list(As), + B1 = type(B), + {type,Line,'fun',[{type,Lt,product,As1},B1]}. + +function_constraint([C|Cs]) -> + C1 = constraint(C), + [C1|function_constraint(Cs)]; +function_constraint([]) -> []. + +constraint({type,Line,constraint,[{atom,L,A},[V,T]]}) -> + V1 = type(V), + T1 = type(T), + {type,Line,constraint,[{atom,L,A},[V1,T1]]}. + +type({ann_type,Line,[{var,Lv,V},T]}) -> + T1 = type(T), + {ann_type,Line,[{var,Lv,V},T1]}; +type({atom,Line,A}) -> + {atom,Line,A}; +type({integer,Line,I}) -> + {integer,Line,I}; +type({op,Line,Op,T}) -> + T1 = type(T), + {op,Line,Op,T1}; +type({op,Line,Op,L,R}) -> + L1 = type(L), + R1 = type(R), + {op,Line,Op,L1,R1}; +type({type,Line,binary,[M,N]}) -> + M1 = type(M), + N1 = type(N), + {type,Line,binary,[M1,N1]}; +type({type,Line,'fun',[]}) -> + {type,Line,'fun',[]}; +type({type,Line,'fun',[{type,Lt,any},B]}) -> + B1 = type(B), + {type,Line,'fun',[{type,Lt,any},B1]}; +type({type,Line,range,[L,H]}) -> + L1 = type(L), + H1 = type(H), + {type,Line,range,[L1,H1]}; +type({type,Line,map,any}) -> + {type,Line,map,any}; +type({type,Line,map,Ps}) -> + Ps1 = map_pair_types(Ps), + {type,Line,map,Ps1}; +type({type,Line,record,[{atom,La,N}|Fs]}) -> + Fs1 = field_types(Fs), + {type,Line,record,[{atom,La,N}|Fs1]}; +type({remote_type,Line,[{atom,Lm,M},{atom,Ln,N},As]}) -> + As1 = type_list(As), + {remote_type,Line,[{atom,Lm,M},{atom,Ln,N},As1]}; +type({type,Line,tuple,any}) -> + {type,Line,tuple,any}; +type({type,Line,tuple,Ts}) -> + Ts1 = type_list(Ts), + {type,Line,tuple,Ts1}; +type({type,Line,union,Ts}) -> + Ts1 = type_list(Ts), + {type,Line,union,Ts1}; +type({var,Line,V}) -> + {var,Line,V}; +type({user_type,Line,N,As}) -> + As1 = type_list(As), + {user_type,Line,N,As1}; +type({type,Line,N,As}) -> + As1 = type_list(As), + {type,Line,N,As1}. + +map_pair_types([{type,Line,map_field_assoc,[K,V]}|Ps]) -> + K1 = type(K), + V1 = type(V), + [{type,Line,map_field_assoc,[K1,V1]}|map_pair_types(Ps)]; +map_pair_types([]) -> []. + +field_types([{type,Line,field_type,[{atom,La,A},T]}|Fs]) -> + T1 = type(T), + [{type,Line,field_type,[{atom,La,A},T1]}|field_types(Fs)]; +field_types([]) -> []. + +type_list([T|Ts]) -> + T1 = type(T), + [T1|type_list(Ts)]; +type_list([]) -> []. diff --git a/lib/stdlib/include/erl_bits.hrl b/lib/stdlib/include/erl_bits.hrl index 8405a55d55..2a54587a17 100644 --- a/lib/stdlib/include/erl_bits.hrl +++ b/lib/stdlib/include/erl_bits.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% Copyright Ericsson AB 1999-2015. 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. @@ -26,10 +26,10 @@ -type bt_unit() :: 1..256. -record(bittype, { - type :: bt_type(), - unit :: bt_unit(), %% element unit - sign :: bt_sign(), - endian :: bt_endian() + type :: bt_type() | 'undefined', + unit :: bt_unit() | 'undefined', %% element unit + sign :: bt_sign() | 'undefined', + endian :: bt_endian() | 'undefined' }). -record(bitdefault, { diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl index 503a2b416f..00cd1221fa 100644 --- a/lib/stdlib/src/beam_lib.erl +++ b/lib/stdlib/src/beam_lib.erl @@ -872,7 +872,7 @@ mandatory_chunks() -> %%% can use it. %%% ==================================================================== --record(state, {crypto_key_f :: crypto_fun()}). +-record(state, {crypto_key_f :: crypto_fun() | 'undefined'}). -define(CRYPTO_KEY_SERVER, beam_lib__crypto_key_server). @@ -975,9 +975,7 @@ handle_call({get_crypto_key, What}, From, #state{crypto_key_f=F}=S) -> handle_call({crypto_key_fun, F}, {_,_} = From, S) -> case S#state.crypto_key_f of undefined -> - %% Don't allow tuple funs here. (They weren't allowed before, - %% so there is no reason to allow them now.) - if is_function(F), is_function(F, 1) -> + if is_function(F, 1) -> {Result, Fun, Reply} = case catch F(init) of ok -> diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl index af00410572..fb0c395d70 100644 --- a/lib/stdlib/src/binary.erl +++ b/lib/stdlib/src/binary.erl @@ -20,7 +20,7 @@ -module(binary). %% %% Implemented in this module: --export([split/2,split/3,replace/3,replace/4]). +-export([replace/3,replace/4]). -export_type([cp/0]). @@ -34,7 +34,8 @@ decode_unsigned/2, encode_unsigned/1, encode_unsigned/2, first/1, last/1, list_to_bin/1, longest_common_prefix/1, longest_common_suffix/1, match/2, match/3, matches/2, - matches/3, part/2, part/3, referenced_byte_size/1]). + matches/3, part/2, part/3, referenced_byte_size/1, + split/2, split/3]). -spec at(Subject, Pos) -> byte() when Subject :: binary(), @@ -198,19 +199,13 @@ part(_, _, _) -> referenced_byte_size(_) -> erlang:nif_error(undef). -%%% End of BIFs. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% split -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -spec split(Subject, Pattern) -> Parts when Subject :: binary(), Pattern :: binary() | [binary()] | cp(), Parts :: [binary()]. -split(H,N) -> - split(H,N,[]). +split(_, _) -> + erlang:nif_error(undef). -spec split(Subject, Pattern, Options) -> Parts when Subject :: binary(), @@ -219,53 +214,10 @@ split(H,N) -> Option :: {scope, part()} | trim | global | trim_all, Parts :: [binary()]. -split(Haystack,Needles,Options) -> - try - {Part,Global,Trim,TrimAll} = - get_opts_split(Options,{no,false,false,false}), - Moptlist = case Part of - no -> - []; - {A,B} -> - [{scope,{A,B}}] - end, - MList = if - Global -> - binary:matches(Haystack,Needles,Moptlist); - true -> - case binary:match(Haystack,Needles,Moptlist) of - nomatch -> []; - Match -> [Match] - end - end, - do_split(Haystack,MList,0,Trim,TrimAll) - catch - _:_ -> - erlang:error(badarg) - end. - -do_split(H,[],N,true,_) when N >= byte_size(H) -> - []; -do_split(H,[],N,_,true) when N >= byte_size(H) -> - []; -do_split(H,[],N,_,_) -> - [binary:part(H,{N,byte_size(H)-N})]; -do_split(H,[{A,B}|T],N,Trim,TrimAll) -> - case binary:part(H,{N,A-N}) of - <<>> when TrimAll == true -> - do_split(H,T,A+B,Trim,TrimAll); - <<>> -> - Rest = do_split(H,T,A+B,Trim,TrimAll), - case {Trim, Rest} of - {true,[]} -> - []; - _ -> - [<<>> | Rest] - end; - Oth -> - [Oth | do_split(H,T,A+B,Trim,TrimAll)] - end. +split(_, _, _) -> + erlang:nif_error(undef). +%%% End of BIFs. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% replace @@ -352,19 +304,6 @@ splitat(H,N,[I|T]) -> %% Simple helper functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -get_opts_split([],{Part,Global,Trim,TrimAll}) -> - {Part,Global,Trim,TrimAll}; -get_opts_split([{scope,{A,B}} | T],{_Part,Global,Trim,TrimAll}) -> - get_opts_split(T,{{A,B},Global,Trim,TrimAll}); -get_opts_split([global | T],{Part,_Global,Trim,TrimAll}) -> - get_opts_split(T,{Part,true,Trim,TrimAll}); -get_opts_split([trim | T],{Part,Global,_Trim,TrimAll}) -> - get_opts_split(T,{Part,Global,true,TrimAll}); -get_opts_split([trim_all | T],{Part,Global,Trim,_TrimAll}) -> - get_opts_split(T,{Part,Global,Trim,true}); -get_opts_split(_,_) -> - throw(badopt). - get_opts_replace([],{Part,Global,Insert}) -> {Part,Global,Insert}; get_opts_replace([{scope,{A,B}} | T],{_Part,Global,Insert}) -> diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl index 2d037ff795..bf22949870 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 d3124ac593..be7c2ec346 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()]. @@ -49,7 +49,8 @@ -define(DEFAULT_ENCODING, utf8). %% Epp state record. --record(epp, {file :: file:io_device(), %Current file +-record(epp, {file :: file:io_device() + | 'undefined', %Current file location=1, %Current location delta=0 :: non_neg_integer(), %Offset from Location (-file) name="" :: file:name(), %Current file name @@ -57,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) @@ -264,20 +258,7 @@ parse_file(Ifile, Options) -> parse_file(Epp) -> case parse_erl_form(Epp) of {ok,Form} -> - case Form of - {attribute,La,record,{Record, Fields}} -> - case normalize_typed_record_fields(Fields) of - {typed, NewFields} -> - [{attribute, La, record, {Record, NewFields}}, - {attribute, La, type, - {{record, Record}, Fields, []}} - |parse_file(Epp)]; - not_typed -> - [Form|parse_file(Epp)] - end; - _ -> - [Form|parse_file(Epp)] - end; + [Form|parse_file(Epp)]; {error,E} -> [{error,E}|parse_file(Epp)]; {eof,Location} -> @@ -549,7 +530,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}) @@ -560,18 +542,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} @@ -580,28 +562,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}. @@ -615,7 +590,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), @@ -667,7 +644,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 @@ -688,7 +666,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). @@ -719,9 +697,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 @@ -796,91 +773,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); @@ -888,10 +822,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 @@ -901,11 +854,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}}), @@ -923,23 +882,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}}}), @@ -1006,17 +965,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) -> @@ -1024,17 +983,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) -> @@ -1102,7 +1061,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, @@ -1190,40 +1150,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) -> @@ -1231,7 +1193,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), @@ -1240,23 +1202,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 @@ -1295,7 +1257,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. @@ -1368,19 +1330,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_anno.erl b/lib/stdlib/src/erl_anno.erl index 143318aa55..d32c34dabd 100644 --- a/lib/stdlib/src/erl_anno.erl +++ b/lib/stdlib/src/erl_anno.erl @@ -33,7 +33,7 @@ -export_type([anno_term/0]). --define(LN(L), is_integer(L)). +-define(LN(L), is_integer(L), L >= 0). -define(COL(C), (is_integer(C) andalso C >= 1)). %% Location. @@ -52,13 +52,13 @@ | {'record', record()} | {'text', string()}. --type anno() :: location() | [annotation(), ...]. +-opaque anno() :: location() | [annotation(), ...]. -type anno_term() :: term(). -type column() :: pos_integer(). -type generated() :: boolean(). -type filename() :: file:filename_all(). --type line() :: integer(). +-type line() :: non_neg_integer(). -type location() :: line() | {line(), column()}. -type record() :: boolean(). -type text() :: string(). @@ -90,9 +90,13 @@ to_term(Anno) -> -ifdef(DEBUG). from_term(Term) when is_list(Term) -> Term; +from_term(Line) when is_integer(Line), Line < 0 -> % Before OTP 19 + set_generated(true, new(-Line)); from_term(Term) -> [{location, Term}]. -else. +from_term(Line) when is_integer(Line), Line < 0 -> % Before OTP 19 + set_generated(true, new(-Line)); from_term(Term) -> Term. -endif. @@ -198,18 +202,11 @@ file(Anno) -> Anno :: anno(). generated(Line) when ?ALINE(Line) -> - Line =< 0; + false; generated({Line, Column}) when ?ALINE(Line), ?ACOLUMN(Column) -> - Line =< 0; + false; generated(Anno) -> - _ = anno_info(Anno, generated, false), - {location, Location} = lists:keyfind(location, 1, Anno), - case Location of - {Line, _Column} -> - Line =< 0; - Line -> - Line =< 0 - end. + anno_info(Anno, generated, false). -spec line(Anno) -> line() when Anno :: anno(). @@ -226,18 +223,11 @@ line(Anno) -> Anno :: anno(). location(Line) when ?ALINE(Line) -> - abs(Line); -location({Line, Column}) when ?ALINE(Line), ?ACOLUMN(Column) -> - {abs(Line), Column}; + Line; +location({Line, Column}=Location) when ?ALINE(Line), ?ACOLUMN(Column) -> + Location; location(Anno) -> - case anno_info(Anno, location) of - Line when Line < 0 -> - -Line; - {Line, Column} when Line < 0 -> - {-Line, Column}; - Location -> - Location - end. + anno_info(Anno, location). -spec record(Anno) -> record() when Anno :: anno(). @@ -270,31 +260,8 @@ set_file(File, Anno) -> Generated :: generated(), Anno :: anno(). -set_generated(true, Line) when ?ALINE(Line) -> - -abs(Line); -set_generated(false, Line) when ?ALINE(Line) -> - abs(Line); -set_generated(true, {Line, Column}) when ?ALINE(Line), - ?ACOLUMN(Column) -> - {-abs(Line),Column}; -set_generated(false, {Line, Column}) when ?ALINE(Line), - ?ACOLUMN(Column) -> - {abs(Line),Column}; set_generated(Generated, Anno) -> - _ = set(generated, Generated, Anno), - {location, Location} = lists:keyfind(location, 1, Anno), - NewLocation = - case Location of - {Line, Column} when Generated -> - {-abs(Line), Column}; - {Line, Column} when not Generated -> - {abs(Line), Column}; - Line when Generated -> - -abs(Line); - Line when not Generated -> - abs(Line) - end, - lists:keyreplace(location, 1, Anno, {location, NewLocation}). + set(generated, Generated, Anno). -spec set_line(Line, Anno) -> Anno when Line :: line(), @@ -313,38 +280,17 @@ set_line(Line, Anno) -> Anno :: anno(). set_location(Line, L) when ?ALINE(L), ?LLINE(Line) -> - new_location(fix_line(Line, L)); + new_location(Line); set_location(Line, {L, Column}) when ?ALINE(L), ?ACOLUMN(Column), ?LLINE(Line) -> - new_location(fix_line(Line, L)); + new_location(Line); set_location({L, C}=Loc, Line) when ?ALINE(Line), ?LLINE(L), ?LCOLUMN(C) -> - new_location(fix_location(Loc, Line)); + new_location(Loc); set_location({L, C}=Loc, {Line, Column}) when ?ALINE(Line), ?ACOLUMN(Column), ?LLINE(L), ?LCOLUMN(C) -> - new_location(fix_location(Loc, Line)); + new_location(Loc); set_location(Location, Anno) -> - _ = set(location, Location, Anno), - {location, OldLocation} = lists:keyfind(location, 1, Anno), - NewLocation = - case {Location, OldLocation} of - {{_Line, _Column}=Loc, {L, _C}} -> - fix_location(Loc, L); - {Line, {L, _C}} -> - fix_line(Line, L); - {{_Line, _Column}=Loc, L} -> - fix_location(Loc, L); - {Line, L} -> - fix_line(Line, L) - end, - lists:keyreplace(location, 1, Anno, {location, NewLocation}). - -fix_location({Line, Column}, OldLine) -> - {fix_line(Line, OldLine), Column}. - -fix_line(Line, OldLine) when OldLine < 0, Line > 0 -> - -Line; -fix_line(Line, _OldLine) -> - Line. + set(location, Location, Anno). -spec set_record(Record, Anno) -> Anno when Record :: record(), @@ -383,7 +329,7 @@ set_anno(Item, Value, Anno) -> _ -> lists:keyreplace(Item, 1, Anno, {Item, Value}) end, - simplify(R) + reset_simplify(R) end. reset(Anno, Item) -> diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl index bcfeef7321..9c0a7fb7d5 100644 --- a/lib/stdlib/src/erl_expand_records.erl +++ b/lib/stdlib/src/erl_expand_records.erl @@ -33,8 +33,6 @@ vcount=0, % Variable counter imports=[], % Imports records=dict:new(), % Record definitions - trecords=sets:new(), % Typed records - uses_types=false, % Are there -spec or -type in the module strict_ra=[], % strict record accesses checked_ra=[] % successfully accessed records }). @@ -47,45 +45,18 @@ %% erl_lint without errors. module(Fs0, Opts0) -> Opts = compiler_options(Fs0) ++ Opts0, - TRecs = typed_records(Fs0), - UsesTypes = uses_types(Fs0), - St0 = #exprec{compile = Opts, trecords = TRecs, uses_types = UsesTypes}, + St0 = #exprec{compile = Opts}, {Fs,_St} = forms(Fs0, St0), Fs. compiler_options(Forms) -> lists:flatten([C || {attribute,_,compile,C} <- Forms]). -typed_records(Fs) -> - typed_records(Fs, sets:new()). - -typed_records([{attribute,_L,type,{{record, Name},_Defs,[]}} | Fs], Trecs) -> - typed_records(Fs, sets:add_element(Name, Trecs)); -typed_records([_|Fs], Trecs) -> - typed_records(Fs, Trecs); -typed_records([], Trecs) -> - Trecs. - -uses_types([{attribute,_L,spec,_}|_]) -> true; -uses_types([{attribute,_L,type,_}|_]) -> true; -uses_types([{attribute,_L,opaque,_}|_]) -> true; -uses_types([_|Fs]) -> uses_types(Fs); -uses_types([]) -> false. - -forms([{attribute,L,record,{Name,Defs}} | Fs], St0) -> +forms([{attribute,_,record,{Name,Defs}}=Attr | Fs], St0) -> NDefs = normalise_fields(Defs), St = St0#exprec{records=dict:store(Name, NDefs, St0#exprec.records)}, {Fs1, St1} = forms(Fs, St), - %% Check if we need to keep the record information for usage in types. - case St#exprec.uses_types of - true -> - case sets:is_element(Name, St#exprec.trecords) of - true -> {Fs1, St1}; - false -> {[{attribute,L,type,{{record,Name},Defs,[]}}|Fs1], St1} - end; - false -> - {Fs1, St1} - end; + {[Attr | Fs1], St1}; forms([{attribute,L,import,Is} | Fs0], St0) -> St1 = import(Is, St0), {Fs,St2} = forms(Fs0, St1), @@ -513,7 +484,6 @@ lc_tq(Line, [F0 | Qs0], St0) -> lc_tq(_Line, [], St0) -> {[],St0#exprec{checked_ra = []}}. - %% normalise_fields([RecDef]) -> [Field]. %% Normalise the field definitions to always have a default value. If %% none has been given then use 'undefined'. diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index 62b3169a6c..4ca9a609a8 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -31,12 +31,8 @@ -export([is_guard_expr/1]). -export([bool_option/4,value_option/3,value_option/7]). --export([modify_line/2]). - -import(lists, [member/2,map/2,foldl/3,foldr/3,mapfoldl/3,all/2,reverse/1]). --deprecated([{modify_line, 2, next_major_release}]). - %% bool_option(OnOpt, OffOpt, Default, Options) -> boolean(). %% value_option(Flag, Default, Options) -> Value. %% value_option(Flag, Default, OnOpt, OnVal, OffOpt, OffVal, Options) -> @@ -79,7 +75,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) -> %%-define(DEBUGF(X,Y), io:format(X, Y)). -define(DEBUGF(X,Y), void). --type line() :: erl_anno:line(). % a convenient alias +-type line() :: erl_anno:anno(). % a convenient alias -type fa() :: {atom(), arity()}. % function+arity -type ta() :: {atom(), arity()}. % type+arity @@ -238,6 +234,9 @@ format_error({removed, MFA, ReplacementMFA, Rel}) -> "use ~s", [format_mfa(MFA), Rel, format_mfa(ReplacementMFA)]); format_error({removed, MFA, String}) when is_list(String) -> io_lib:format("~s: ~s", [format_mfa(MFA), String]); +format_error({removed_type, MNA, ReplacementMNA, Rel}) -> + io_lib:format("the type ~s was removed in ~s; use ~s instead", + [format_mna(MNA), Rel, format_mna(ReplacementMNA)]); format_error({obsolete_guard, {F, A}}) -> io_lib:format("~p/~p obsolete", [F, A]); format_error({too_many_arguments,Arity}) -> @@ -361,6 +360,9 @@ format_error({redefine_type, {TypeName, Arity}}) -> [TypeName, gen_type_paren(Arity)]); format_error({type_syntax, Constr}) -> io_lib:format("bad ~w type", [Constr]); +format_error(old_abstract_code) -> + io_lib:format("abstract code generated before Erlang/OTP 19.0 and " + "having typed record fields cannot be compiled", []); format_error({redefine_spec, {M, F, A}}) -> io_lib:format("spec for ~w:~w/~w already defined", [M, F, A]); format_error({redefine_spec, {F, A}}) -> @@ -374,9 +376,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 @@ -416,6 +418,9 @@ format_mfa({M, F, A}) when is_integer(A) -> format_mf(M, F, ArityString) when is_atom(M), is_atom(F) -> atom_to_list(M) ++ ":" ++ atom_to_list(F) ++ "/" ++ ArityString. +format_mna({M, N, A}) when is_integer(A) -> + atom_to_list(M) ++ ":" ++ atom_to_list(N) ++ gen_type_paren(A). + format_where(L) when is_integer(L) -> io_lib:format("(line ~p)", [L]); format_where({L,C}) when is_integer(L), is_integer(C) -> @@ -694,7 +699,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). @@ -1136,7 +1146,7 @@ check_untyped_records(Forms, St0) -> RecNames = dict:fetch_keys(St0#lint.records), %% these are the records with field(s) containing type info TRecNames = [Name || - {attribute,_,type,{{record,Name},Fields,_}} <- Forms, + {attribute,_,record,{Name,Fields}} <- Forms, lists:all(fun ({typed_record_field,_,_}) -> true; (_) -> false end, Fields)], @@ -1146,7 +1156,8 @@ check_untyped_records(Forms, St0) -> [] -> St; % exclude records with no fields [_|_] -> add_warning(L, {untyped_record, N}, St) end - end, St0, RecNames -- TRecNames); + end, St0, ordsets:subtract(ordsets:from_list(RecNames), + ordsets:from_list(TRecNames))); false -> St0 end. @@ -2436,7 +2447,10 @@ record_def(Line, Name, Fs0, St0) -> true -> add_error(Line, {redefine_record,Name}, St0); false -> {Fs1,St1} = def_fields(normalise_fields(Fs0), Name, St0), - St1#lint{records=dict:store(Name, {Line,Fs1}, St1#lint.records)} + St2 = St1#lint{records=dict:store(Name, {Line,Fs1}, + St1#lint.records)}, + Types = [T || {typed_record_field, _, T} <- Fs0], + check_type({type, nowarn(), product, Types}, St2) end. %% def_fields([RecDef], RecordName, State) -> {[DefField],State}. @@ -2639,11 +2653,6 @@ find_field(_F, []) -> error. %% Attr :: 'type' | 'opaque' %% Checks that a type definition is valid. -type_def(_Attr, _Line, {record, _RecName}, Fields, [], St0) -> - %% The record field names and such are checked in the record format. - %% We only need to check the types. - Types = [T || {typed_record_field, _, T} <- Fields], - check_type({type, nowarn(), product, Types}, St0); type_def(Attr, Line, TypeName, ProtoType, Args, St0) -> TypeDefs = St0#lint.types, Arity = length(Args), @@ -2806,6 +2815,8 @@ check_type({user_type, L, TypeName, Args}, SeenVars, St) -> lists:foldl(fun(T, {AccSeenVars, AccSt}) -> check_type(T, AccSeenVars, AccSt) end, {SeenVars, St1}, Args); +check_type([{typed_record_field,Field,_T}|_], SeenVars, St) -> + {SeenVars, add_error(element(2, Field), old_abstract_code, St)}; check_type(I, SeenVars, St) -> case erl_eval:partial_eval(I) of {integer,_ILn,_Integer} -> {SeenVars, St}; @@ -2876,7 +2887,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. @@ -2890,7 +2901,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. @@ -2927,7 +2939,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]} -> @@ -2935,18 +2947,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() -> @@ -2988,9 +2998,10 @@ add_missing_spec_warnings(Forms, St0, Type) -> [{FA,L} || {function,L,F,A,_} <- Forms, not lists:member(FA = {F,A}, Specs)]; exported -> - Exps = gb_sets:to_list(St0#lint.exports) -- pseudolocals(), + Exps0 = gb_sets:to_list(St0#lint.exports) -- pseudolocals(), + Exps = Exps0 -- Specs, [{FA,L} || {function,L,F,A,_} <- Forms, - member(FA = {F,A}, Exps -- Specs)] + member(FA = {F,A}, Exps)] end, foldl(fun ({FA,L}, St) -> add_warning(L, {missing_spec,FA}, St) @@ -3003,7 +3014,9 @@ check_unused_types(Forms, #lint{usage=Usage, types=Ts, exp_types=ExpTs}=St) -> L = gb_sets:to_list(ExpTs) ++ dict:fetch_keys(D), UsedTypes = gb_sets:from_list(L), FoldFun = - fun(Type, #typeinfo{line = FileLine}, AccSt) -> + fun({{record, _}=_Type, 0}, _, AccSt) -> + AccSt; % Before Erlang/OTP 19.0 + (Type, #typeinfo{line = FileLine}, AccSt) -> case loc(FileLine, AccSt) of {FirstFile, _} -> case gb_sets:is_member(Type, UsedTypes) of @@ -3190,8 +3203,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 -> @@ -3485,13 +3498,6 @@ vt_no_unused(Vt) -> [V || {_,{_,U,_L}}=V <- Vt, U =/= unused]. copy_expr(Expr, Anno) -> erl_parse:map_anno(fun(_A) -> Anno end, Expr). -%% modify_line(Form, Fun) -> Form -%% modify_line(Expression, Fun) -> Expression -%% Applies Fun to each line number occurrence. - -modify_line(T, F0) -> - erl_parse:map_anno(F0, T). - %% Check a record_info call. We have already checked that it is not %% shadowed by an import. @@ -3574,6 +3580,8 @@ deprecated_type(L, M, N, As, St) -> false -> St end; + {removed, Replacement, Rel} -> + add_warning(L, {removed_type, {M,N,NAs}, Replacement, Rel}, St); no -> St end. diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index e82282421e..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'}. @@ -525,23 +521,424 @@ Erlang code. -export([type_inop_prec/1,type_preop_prec/1]). -export([map_anno/2, fold_anno/3, mapfold_anno/3, new_anno/1, anno_to_term/1, anno_from_term/1]). --export([set_line/2,get_attribute/2,get_attributes/1]). - --deprecated([{set_line, 2, next_major_release}, - {get_attribute, 2, next_major_release}, - {get_attributes, 1, next_major_release}]). %% The following directive is needed for (significantly) faster compilation %% of the generated .erl file by the HiPE compiler. Please do not remove. -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(). @@ -639,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|_]) -> @@ -795,31 +1186,11 @@ record_fields([{match,_Am,{atom,Aa,A},Expr}|Fields]) -> [{record_field,Aa,{atom,Aa,A},Expr}|record_fields(Fields)]; record_fields([{typed,Expr,TypeInfo}|Fields]) -> [Field] = record_fields([Expr]), - TypeInfo1 = - case Expr of - {match, _, _, _} -> TypeInfo; %% If we have an initializer. - {atom, Aa, _} -> - case has_undefined(TypeInfo) of - false -> - lift_unions(abstract2(undefined, Aa), TypeInfo); - true -> - TypeInfo - end - end, - [{typed_record_field,Field,TypeInfo1}|record_fields(Fields)]; + [{typed_record_field,Field,TypeInfo}|record_fields(Fields)]; record_fields([Other|_Fields]) -> ret_err(?anno(Other), "bad record field"); record_fields([]) -> []. -has_undefined({atom,_,undefined}) -> - true; -has_undefined({ann_type,_,[_,T]}) -> - has_undefined(T); -has_undefined({type,_,union,Ts}) -> - lists:any(fun has_undefined/1, Ts); -has_undefined(_) -> - false. - term(Expr) -> try normalise(Expr) catch _:_R -> ret_err(?anno(Expr), "bad attribute") @@ -1118,33 +1489,16 @@ type_preop_prec('-') -> {600,700}; type_preop_prec('bnot') -> {600,700}; type_preop_prec('#') -> {700,800}. -%%% [Experimental]. The parser just copies the attributes of the -%%% scanner tokens to the abstract format. This design decision has -%%% been hidden to some extent: use set_line() and get_attribute() to -%%% access the second element of (almost all) of the abstract format -%%% tuples. A typical use is to negate line numbers to prevent the -%%% compiler from emitting warnings and errors. The second element can -%%% (of course) be set to any value, but then these functions no -%%% longer apply. To get all present attributes as a property list -%%% get_attributes() should be used. - --compile({nowarn_deprecated_function,{erl_scan,set_attribute,3}}). -set_line(L, F) -> - erl_scan:set_attribute(line, L, F). - --compile({nowarn_deprecated_function,{erl_scan,attributes_info,2}}). -get_attribute(L, Name) -> - erl_scan:attributes_info(L, Name). - --compile({nowarn_deprecated_function,{erl_scan,attributes_info,1}}). -get_attributes(L) -> - erl_scan:attributes_info(L). +-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, @@ -1157,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, @@ -1172,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_scan.erl b/lib/stdlib/src/erl_scan.erl index d2f53816b8..47223b129c 100644 --- a/lib/stdlib/src/erl_scan.erl +++ b/lib/stdlib/src/erl_scan.erl @@ -52,25 +52,15 @@ %%% External exports -export([string/1,string/2,string/3,tokens/3,tokens/4, - format_error/1,reserved_word/1, - token_info/1,token_info/2, - attributes_info/1,attributes_info/2,set_attribute/3]). + format_error/1,reserved_word/1]). -export([column/1,end_location/1,line/1,location/1,text/1, category/1,symbol/1]). --deprecated([{attributes_info, 1, next_major_release}, - {attributes_info, 2, next_major_release}, - {set_attribute, 3, next_major_release}, - {token_info, 1, next_major_release}, - {token_info, 2, next_major_release}]). - %%% Private -export([continuation_location/1]). -export_type([error_info/0, - line/0, - location/0, options/0, return_cont/0, token/0, @@ -85,29 +75,18 @@ -define(ALINE(L), is_integer(L)). -define(STRING(S), is_list(S)). -define(RESWORDFUN(F), is_function(F, 1)). --define(SETATTRFUN(F), is_function(F, 1)). -type category() :: atom(). --type column() :: pos_integer(). % Deprecated --type line() :: integer(). % Deprecated --type location() :: line() | {line(),column()}. % Deprecated -type resword_fun() :: fun((atom()) -> boolean()). -type option() :: 'return' | 'return_white_spaces' | 'return_comments' | 'text' | {'reserved_word_fun', resword_fun()}. -type options() :: option() | [option()]. -type symbol() :: atom() | float() | integer() | string(). --type info_line() :: integer() | term(). --type attributes_data() - :: [{'column', column()} | {'line', info_line()} | {'text', string()}] - | {line(), column()}. -%% The fact that {line(),column()} is a possible attributes() type -%% is hidden. --type attributes() :: line() | attributes_data(). --type token() :: {category(), attributes(), symbol()} - | {category(), attributes()}. +-type token() :: {category(), Anno :: erl_anno:anno(), symbol()} + | {category(), Anno :: erl_anno:anno()}. -type tokens() :: [token()]. -type error_description() :: term(). --type error_info() :: {location(), module(), error_description()}. +-type error_info() :: {erl_anno:location(), module(), error_description()}. %%% Local record. -record(erl_scan, @@ -136,8 +115,8 @@ format_error(Other) -> String :: string(), Return :: {'ok', Tokens :: tokens(), EndLocation} | {'error', ErrorInfo :: error_info(), ErrorLocation}, - EndLocation :: location(), - ErrorLocation :: location(). + EndLocation :: erl_anno:location(), + ErrorLocation :: erl_anno:location(). string(String) -> string(String, 1, []). @@ -145,9 +124,9 @@ string(String) -> String :: string(), Return :: {'ok', Tokens :: tokens(), EndLocation} | {'error', ErrorInfo :: error_info(), ErrorLocation}, - StartLocation :: location(), - EndLocation :: location(), - ErrorLocation :: location(). + StartLocation :: erl_anno:location(), + EndLocation :: erl_anno:location(), + ErrorLocation :: erl_anno:location(). string(String, StartLocation) -> string(String, StartLocation, []). @@ -156,9 +135,9 @@ string(String, StartLocation) -> Options :: options(), Return :: {'ok', Tokens :: tokens(), EndLocation} | {'error', ErrorInfo :: error_info(), ErrorLocation}, - StartLocation :: location(), - EndLocation :: location(), - ErrorLocation :: location(). + StartLocation :: erl_anno:location(), + EndLocation :: erl_anno:location(), + ErrorLocation :: erl_anno:location(). string(String, Line, Options) when ?STRING(String), ?ALINE(Line) -> string1(String, options(Options), Line, no_col, []); string(String, {Line,Column}, Options) when ?STRING(String), @@ -167,20 +146,23 @@ string(String, {Line,Column}, Options) when ?STRING(String), string1(String, options(Options), Line, Column, []). -type char_spec() :: string() | 'eof'. --type cont_fun() :: fun((char_spec(), #erl_scan{}, line(), column(), +-type cont_fun() :: fun((char_spec(), #erl_scan{}, + erl_anno:line(), erl_anno:column(), tokens(), any()) -> any()). -opaque return_cont() :: {erl_scan_continuation, - string(), column(), tokens(), line(), + string(), erl_anno:column(), tokens(), + erl_anno:line(), #erl_scan{}, any(), cont_fun()}. --type tokens_result() :: {'ok', Tokens :: tokens(), EndLocation :: location()} - | {'eof', EndLocation :: location()} +-type tokens_result() :: {'ok', Tokens :: tokens(), + EndLocation :: erl_anno:location()} + | {'eof', EndLocation :: erl_anno:location()} | {'error', ErrorInfo :: error_info(), - EndLocation :: location()}. + EndLocation :: erl_anno:location()}. -spec tokens(Continuation, CharSpec, StartLocation) -> Return when Continuation :: return_cont() | [], CharSpec :: char_spec(), - StartLocation :: location(), + StartLocation :: erl_anno:location(), Return :: {'done',Result :: tokens_result(),LeftOverChars :: char_spec()} | {'more', Continuation1 :: return_cont()}. tokens(Cont, CharSpec, StartLocation) -> @@ -189,7 +171,7 @@ tokens(Cont, CharSpec, StartLocation) -> -spec tokens(Continuation, CharSpec, StartLocation, Options) -> Return when Continuation :: return_cont() | [], CharSpec :: char_spec(), - StartLocation :: location(), + StartLocation :: erl_anno:location(), Options :: options(), Return :: {'done',Result :: tokens_result(),LeftOverChars :: char_spec()} | {'more', Continuation1 :: return_cont()}. @@ -257,155 +239,6 @@ symbol({_Category,_Anno,Symbol}) -> symbol(T) -> erlang:error(badarg, [T]). --type attribute_item() :: 'column' | 'length' | 'line' - | 'location' | 'text'. --type info_location() :: location() | term(). --type attribute_info() :: {'column', column()}| {'length', pos_integer()} - | {'line', info_line()} - | {'location', info_location()} - | {'text', string()}. --type token_item() :: 'category' | 'symbol' | attribute_item(). --type token_info() :: {'category', category()} | {'symbol', symbol()} - | attribute_info(). - --spec token_info(Token) -> TokenInfo when - Token :: token(), - TokenInfo :: [TokenInfoTuple :: token_info()]. -token_info(Token) -> - Items = [category,column,length,line,symbol,text], % undefined order - token_info(Token, Items). - --spec token_info(Token, TokenItem) -> TokenInfoTuple | 'undefined' when - Token :: token(), - TokenItem :: token_item(), - TokenInfoTuple :: token_info(); - (Token, TokenItems) -> TokenInfo when - Token :: token(), - TokenItems :: [TokenItem :: token_item()], - TokenInfo :: [TokenInfoTuple :: token_info()]. -token_info(_Token, []) -> - []; -token_info(Token, [Item|Items]) when is_atom(Item) -> - case token_info(Token, Item) of - undefined -> - token_info(Token, Items); - TokenInfo when is_tuple(TokenInfo) -> - [TokenInfo|token_info(Token, Items)] - end; -token_info({Category,_Attrs}, category=Item) -> - {Item,Category}; -token_info({Category,_Attrs,_Symbol}, category=Item) -> - {Item,Category}; -token_info({Category,_Attrs}, symbol=Item) -> - {Item,Category}; -token_info({_Category,_Attrs,Symbol}, symbol=Item) -> - {Item,Symbol}; -token_info({_Category,Attrs}, Item) -> - attributes_info(Attrs, Item); -token_info({_Category,Attrs,_Symbol}, Item) -> - attributes_info(Attrs, Item). - --spec attributes_info(Attributes) -> AttributesInfo when - Attributes :: attributes(), - AttributesInfo :: [AttributeInfoTuple :: attribute_info()]. -attributes_info(Attributes) -> - Items = [column,length,line,text], % undefined order - attributes_info(Attributes, Items). - --spec attributes_info - (Attributes, AttributeItem) -> AttributeInfoTuple | 'undefined' when - Attributes :: attributes(), - AttributeItem :: attribute_item(), - AttributeInfoTuple :: attribute_info(); - (Attributes, AttributeItems) -> AttributeInfo when - Attributes :: attributes(), - AttributeItems :: [AttributeItem :: attribute_item()], - AttributeInfo :: [AttributeInfoTuple :: attribute_info()]. -attributes_info(_Attrs, []) -> - []; -attributes_info(Attrs, [A|As]) when is_atom(A) -> - case attributes_info(Attrs, A) of - undefined -> - attributes_info(Attrs, As); - AttributeInfo when is_tuple(AttributeInfo) -> - [AttributeInfo|attributes_info(Attrs, As)] - end; -attributes_info({Line,Column}, column=Item) when ?ALINE(Line), - ?COLUMN(Column) -> - {Item,Column}; -attributes_info(Line, column) when ?ALINE(Line) -> - undefined; -attributes_info(Attrs, column=Item) -> - case attr_info(Attrs, Item) of - undefined -> - case erl_anno:column(Attrs) of - undefined -> - undefined; - Column -> - {Item,Column} - end; - T -> - T - end; -attributes_info(Attrs, length=Item) -> - case attributes_info(Attrs, text) of - undefined -> - undefined; - {text,Text} -> - {Item,length(Text)} - end; -attributes_info(Line, line=Item) when ?ALINE(Line) -> - {Item,Line}; -attributes_info({Line,Column}, line=Item) when ?ALINE(Line), - ?COLUMN(Column) -> - {Item,Line}; -attributes_info(Attrs, line=Item) -> - case attr_info(Attrs, Item) of - undefined -> - case attr_info(Attrs, location) of - {location,{Line,_Column}} -> - {Item,Line}; - {location,Line} -> - {Item,Line}; - undefined -> - undefined - end; - T -> - T - end; -attributes_info({Line,Column}=Location, location=Item) when ?ALINE(Line), - ?COLUMN(Column) -> - {Item,Location}; -attributes_info(Line, location=Item) when ?ALINE(Line) -> - {Item,Line}; -attributes_info(Attrs, location=Item) -> - {line,Line} = attributes_info(Attrs, line), - case attributes_info(Attrs, column) of - undefined -> - %% If set_attribute() has assigned a term such as {17,42} - %% to 'line', then Line will look like {Line,Column}. One - %% should not use 'location' but 'line' and 'column' in - %% such special cases. - {Item,Line}; - {column,Column} -> - {Item,{Line,Column}} - end; -attributes_info({Line,Column}, text) when ?ALINE(Line), ?COLUMN(Column) -> - undefined; -attributes_info(Line, text) when ?ALINE(Line) -> - undefined; -attributes_info(Attrs, text=Item) -> - attr_info(Attrs, Item); -attributes_info(T1, T2) -> - erlang:error(badarg, [T1,T2]). - --spec set_attribute(AttributeItem, Attributes, SetAttributeFun) -> Attributes when - AttributeItem :: 'line', - Attributes :: attributes(), - SetAttributeFun :: fun((info_line()) -> info_line()). -set_attribute(Tag, Attributes, Fun) when ?SETATTRFUN(Fun) -> - set_attr(Tag, Attributes, Fun). - %%% %%% Local functions %%% @@ -471,62 +304,6 @@ expand_opt(return, Os) -> expand_opt(O, Os) -> [O|Os]. -attr_info(Attrs, Item) -> - try lists:keyfind(Item, 1, Attrs) of - {_Item, _Value} = T -> - T; - false -> - undefined - catch - _:_ -> - erlang:error(badarg, [Attrs, Item]) - end. - --spec set_attr('line', attributes(), fun((line()) -> line())) -> attributes(). - -set_attr(line, Line, Fun) when ?ALINE(Line) -> - Ln = Fun(Line), - if - ?ALINE(Ln) -> - Ln; - true -> - [{line,Ln}] - end; -set_attr(line, {Line,Column}, Fun) when ?ALINE(Line), ?COLUMN(Column) -> - Ln = Fun(Line), - if - ?ALINE(Ln) -> - {Ln,Column}; - true -> - [{line,Ln},{column,Column}] - end; -set_attr(line=Tag, Attrs, Fun) when is_list(Attrs) -> - case lists:keyfind(Tag, 1, Attrs) of - {line,Line} -> - case lists:keyreplace(Tag, 1, Attrs, {line,Fun(Line)}) of - [{line,Ln}] when ?ALINE(Ln) -> - Ln; - As -> - As - end; - false -> - {location, Location} = lists:keyfind(location, 1, Attrs), - Ln = case Location of - {Line,Column} when ?ALINE(Line), ?COLUMN(Column) -> - {Fun(Line),Column}; - _ -> - Fun(Location) - end, - case lists:keyreplace(location, 1, Attrs, {location,Ln}) of - [{location,Ln}] when ?ALINE(Ln) -> - Ln; - As -> - As - end - end; -set_attr(T1, T2, T3) -> - erlang:error(badarg, [T1,T2,T3]). - tokens1(Cs, St, Line, Col, Toks, Fun, Any) when ?STRING(Cs); Cs =:= eof -> case Fun(Cs, St, Line, Col, Toks, Any) of {more,{Cs0,Ncol,Ntoks,Nline,Nany,Nfun}} -> diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl index 41b49f4a86..b8ce311c35 100644 --- a/lib/stdlib/src/escript.erl +++ b/lib/stdlib/src/escript.erl @@ -38,7 +38,7 @@ -record(state, {file :: file:filename(), module :: module(), forms_or_bin, - source :: source(), + source :: source() | 'undefined', n_errors :: non_neg_integer(), mode :: mode(), exports_main :: boolean(), @@ -49,9 +49,9 @@ -type emu_args() :: string(). -record(sections, {type, - shebang :: shebang(), - comment :: comment(), - emu_args :: emu_args(), + shebang :: shebang() | 'undefined', + comment :: comment() | 'undefined', + emu_args :: emu_args() | 'undefined', body}). -record(extract_options, {compile_source}). diff --git a/lib/stdlib/src/file_sorter.erl b/lib/stdlib/src/file_sorter.erl index 0d50392b96..3aeaff8dc4 100644 --- a/lib/stdlib/src/file_sorter.erl +++ b/lib/stdlib/src/file_sorter.erl @@ -307,7 +307,6 @@ options(Option) -> options([{format, Format} | L], Opts) when Format =:= binary; Format =:= term; - is_function(Format), is_function(Format, 1) -> options(L, Opts#opts{format = Format}); options([{format, binary_term} | L], Opts) -> @@ -326,7 +325,7 @@ options([{tmpdir, Dir} | L], Opts) -> FileName -> options(L, Opts#opts{tmpdir = {dir, FileName}}) end; -options([{order, Fun} | L], Opts) when is_function(Fun), is_function(Fun, 2) -> +options([{order, Fun} | L], Opts) when is_function(Fun, 2) -> options(L, Opts#opts{order = Fun}); options([{order, Order} | L], Opts) when Order =:= ascending; Order =:= descending -> @@ -411,7 +410,7 @@ merge_terms_fun(RFun) -> case RFun(read) of end_of_input -> eof; - {Objs, NRFun} when is_function(NRFun), is_function(NRFun, 1) -> + {Objs, NRFun} when is_function(NRFun, 1) -> {_, [], Ts, _} = fun_objs(Objs, [], 0, ?MAXSIZE, I, W), {{I, Ts, ?CHUNKSIZE}, merge_terms_fun(NRFun)}; Error -> @@ -427,13 +426,12 @@ merge_bins_fun(FileName) -> Fun(A) end. -wrap_output_terms(term, OutFun, _Z) when is_function(OutFun), - is_function(OutFun, 1) -> +wrap_output_terms(term, OutFun, _Z) when is_function(OutFun, 1) -> {fun_wterms(OutFun), true}; wrap_output_terms(term, File, Z) when File =/= undefined -> {file_wterms(name, File, Z++[write]), false}; wrap_output_terms(_Format, Output, _Z) -> - {Output, is_function(Output) and is_function(Output, 1)}. + {Output, is_function(Output, 1)}. binary_term_fun() -> fun binary_to_term/1. @@ -1311,8 +1309,7 @@ infun(W) -> {end_of_input, W1}; {end_of_input, Value} -> {end_of_input, W1#w{inout_value = {value, Value}}}; - {Objs, NFun} when is_function(NFun), - is_function(NFun, 1), + {Objs, NFun} when is_function(NFun, 1), is_list(Objs) -> {cont, W#w{in = NFun}, Objs}; Error -> @@ -1335,7 +1332,7 @@ outfun(A, W) -> try (W#w.out)(A) of Reply when A =:= close -> Reply; - NF when is_function(NF), is_function(NF, 1) -> + NF when is_function(NF, 1) -> W#w{out = NF}; Error -> error(Error, W1) @@ -1360,7 +1357,7 @@ is_keyposs([Bad | _]) -> is_keyposs(Bad) -> {badarg, Bad}. -is_input(Fun) when is_function(Fun), is_function(Fun, 1) -> +is_input(Fun) when is_function(Fun, 1) -> {true, Fun}; is_input(Files) -> is_files(Files). @@ -1380,7 +1377,7 @@ is_files([], L) -> is_files(Bad, _L) -> {badarg, Bad}. -maybe_output(Fun) when is_function(Fun), is_function(Fun, 1) -> +maybe_output(Fun) when is_function(Fun, 1) -> {true, Fun}; maybe_output(File) -> case read_file_info(File) of @@ -1589,7 +1586,6 @@ fun_rterms(InFun) -> (read) -> case InFun(read) of {Ts, NInFun} when is_list(Ts), - is_function(NInFun), is_function(NInFun, 1) -> {to_bin(Ts, []), fun_rterms(NInFun)}; Else -> @@ -1602,7 +1598,7 @@ fun_wterms(OutFun) -> OutFun(close); (L) -> case OutFun(wterms_arg(L)) of - NOutFun when is_function(NOutFun), is_function(NOutFun, 1) -> + NOutFun when is_function(NOutFun, 1) -> fun_wterms(NOutFun); Else -> Else 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/ms_transform.erl b/lib/stdlib/src/ms_transform.erl index b67b6f75d7..24b5fde1db 100644 --- a/lib/stdlib/src/ms_transform.erl +++ b/lib/stdlib/src/ms_transform.erl @@ -307,15 +307,18 @@ cleanup_filename({Old,OldRec,OldWarnings}) -> add_record_definition({Name,FieldList}) -> {KeyList,_} = lists:foldl( - fun({record_field,_,{atom,Line0,FieldName}},{L,C}) -> - {[{FieldName,C,{atom,Line0,undefined}}|L],C+1}; - ({record_field,_,{atom,_,FieldName},Def},{L,C}) -> - {[{FieldName,C,Def}|L],C+1} - end, + fun(F, {L,C}) -> {[record_field(F, C)|L],C+1} end, {[],2}, FieldList), put_records([{Name,KeyList}|get_records()]). +record_field({record_field,_,{atom,Line0,FieldName}}, C) -> + {FieldName,C,{atom,Line0,undefined}}; +record_field({record_field,_,{atom,_,FieldName},Def}, C) -> + {FieldName,C,Def}; +record_field({typed_record_field,Field,_Type}, C) -> + record_field(Field, C). + forms([F0|Fs0]) -> F1 = form(F0), Fs1 = forms(Fs0), diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index 9d394e19d7..0dc2626ae8 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -588,49 +588,40 @@ obsolete_1(asn1rt, utf8_list_to_binary, 1) -> %% Added in OTP 18. obsolete_1(core_lib, get_anno, 1) -> - {deprecated,{cerl,get_ann,1}}; + {removed,{cerl,get_ann,1},"19"}; obsolete_1(core_lib, set_anno, 2) -> - {deprecated,{cerl,set_ann,2}}; + {removed,{cerl,set_ann,2},"19"}; obsolete_1(core_lib, is_literal, 1) -> - {deprecated,{cerl,is_literal,1}}; + {removed,{cerl,is_literal,1},"19"}; obsolete_1(core_lib, is_literal_list, 1) -> - {deprecated,"deprecated; use lists:all(fun cerl:is_literal/1, L)" + {removed,"removed; use lists:all(fun cerl:is_literal/1, L)" " instead"}; obsolete_1(core_lib, literal_value, 1) -> - {deprecated,{core_lib,concrete,1}}; + {removed,{core_lib,concrete,1},"19"}; obsolete_1(erl_scan, set_attribute, 3) -> - {deprecated, - "deprecated (will be removed in OTP 19); use erl_anno:set_line/2 instead"}; + {removed,{erl_anno,set_line,2},"19.0"}; obsolete_1(erl_scan, attributes_info, 1) -> - {deprecated, - "deprecated (will be removed in OTP 19); use " + {removed,"removed in 19.0; use " "erl_anno:{column,line,location,text}/1 instead"}; obsolete_1(erl_scan, attributes_info, 2) -> - {deprecated, - "deprecated (will be removed in OTP 19); use " + {removed,"removed in 19.0; use " "erl_anno:{column,line,location,text}/1 instead"}; obsolete_1(erl_scan, token_info, 1) -> - {deprecated, - "deprecated (will be removed in OTP 19); use " + {removed,"removed in 19.0; use " "erl_scan:{category,column,line,location,symbol,text}/1 instead"}; obsolete_1(erl_scan, token_info, 2) -> - {deprecated, - "deprecated (will be removed in OTP 19); use " + {removed,"removed in 19.0; use " "erl_scan:{category,column,line,location,symbol,text}/1 instead"}; obsolete_1(erl_parse, set_line, 2) -> - {deprecated, - "deprecated (will be removed in OTP 19); use erl_anno:set_line/2 instead"}; + {removed,{erl_anno,set_line,2},"19.0"}; obsolete_1(erl_parse, get_attributes, 1) -> - {deprecated, - "deprecated (will be removed in OTP 19); use " + {removed,"removed in 19.0; use " "erl_anno:{column,line,location,text}/1 instead"}; obsolete_1(erl_parse, get_attribute, 2) -> - {deprecated, - "deprecated (will be removed in OTP 19); use " + {removed,"removed in 19.0; use " "erl_anno:{column,line,location,text}/1 instead"}; obsolete_1(erl_lint, modify_line, 2) -> - {deprecated, - "deprecated (will be removed in OTP 19); use erl_parse:map_anno/2 instead"}; + {removed,{erl_parse,map_anno,2},"19.0"}; obsolete_1(ssl, negotiated_next_protocol, 1) -> {deprecated,{ssl,negotiated_protocol,1}}; @@ -650,6 +641,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(overload, _, _) -> {deprecated, "deprecated; will be removed in OTP 19"}; @@ -705,6 +704,7 @@ is_snmp_agent_function(_, _) -> false. -spec obsolete_type(module(), atom(), arity()) -> 'no' | {tag(), string()} | {tag(), mfas(), release()}. +-dialyzer({no_match, obsolete_type/3}). obsolete_type(Module, Name, NumberOfVariables) -> case obsolete_type_1(Module, Name, NumberOfVariables) of {deprecated=Tag,{_,_,_}=Replacement} -> @@ -718,13 +718,10 @@ obsolete_type(Module, Name, NumberOfVariables) -> end. obsolete_type_1(erl_scan,column,0) -> - {deprecated, - "deprecated (will be removed in OTP 19); use erl_anno:column() instead"}; + {removed,{erl_anno,column,0},"19.0"}; obsolete_type_1(erl_scan,line,0) -> - {deprecated, - "deprecated (will be removed in OTP 19); use erl_anno:line() instead"}; + {removed,{erl_anno,line,0},"19.0"}; obsolete_type_1(erl_scan,location,0) -> - {deprecated, - "deprecated (will be removed in OTP 19); use erl_anno:location() instead"}; + {removed,{erl_anno,location,0},"19.0"}; obsolete_type_1(_,_,_) -> no. diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl index 1ae7c6cc25..b396ba7057 100644 --- a/lib/stdlib/src/qlc.erl +++ b/lib/stdlib/src/qlc.erl @@ -810,21 +810,21 @@ options(Options0, [Key | Keys], L) when is_list(Options0) -> {ok, U}; {pre_fun, U=undefined} -> {ok, U}; - {info_fun, Fun} when is_function(Fun), is_function(Fun, 1) -> + {info_fun, Fun} when is_function(Fun, 1) -> {ok, Fun}; - {pre_fun, Fun} when is_function(Fun), is_function(Fun, 1) -> + {pre_fun, Fun} when is_function(Fun, 1) -> {ok, Fun}; - {post_fun, Fun} when is_function(Fun), is_function(Fun, 0) -> + {post_fun, Fun} when is_function(Fun, 0) -> {ok, Fun}; - {lookup_fun, Fun} when is_function(Fun), is_function(Fun, 2) -> + {lookup_fun, Fun} when is_function(Fun, 2) -> {ok, Fun}; {max_lookup, Max} when is_integer(Max), Max >= 0 -> {ok, Max}; {max_lookup, infinity} -> {ok, -1}; - {format_fun, Fun} when is_function(Fun), is_function(Fun, 1) -> + {format_fun, Fun} when is_function(Fun, 1) -> {ok, Fun}; - {parent_fun, Fun} when is_function(Fun), is_function(Fun, 0) -> + {parent_fun, Fun} when is_function(Fun, 0) -> {ok, Fun}; {key_equality, KE='=='} -> {ok, KE}; @@ -887,7 +887,7 @@ options(Options0, [Key | Keys], L) when is_list(Options0) -> {depth, Depth} when Depth =:= infinity; is_integer(Depth), Depth >= 0 -> {ok, Depth}; - {order, Order} when is_function(Order), is_function(Order, 2); + {order, Order} when is_function(Order, 2); (Order =:= ascending); (Order =:= descending) -> {ok, Order}; diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl index 9577d17a85..e4b9768b12 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}). @@ -1914,9 +1914,9 @@ expand_pattern_records(P, State) -> expand_expr_records(E, State) -> RecordDefs = State#state.records, A = anno1(), - Forms = RecordDefs ++ [{function,A,foo,0,[{clause,A,[],[],[pe(E)]}]}], - [{function,_,foo,0,[{clause,_,[],[],[NE]}]}] = - erl_expand_records:module(Forms, [no_strict_record_tests]), + Forms0 = RecordDefs ++ [{function,A,foo,0,[{clause,A,[],[],[pe(E)]}]}], + Forms = erl_expand_records:module(Forms0, [no_strict_record_tests]), + {function,_,foo,0,[{clause,_,[],[],[NE]}]} = lists:last(Forms), NE. %% Partial evaluation. @@ -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/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 ce1d9eb0ff..82a3a2be4f 100644 --- a/lib/stdlib/src/shell.erl +++ b/lib/stdlib/src/shell.erl @@ -917,9 +917,9 @@ expand_records(UsedRecords, E0) -> RecordDefs = [Def || {_Name,Def} <- UsedRecords], L = erl_anno:new(1), E = prep_rec(E0), - Forms = RecordDefs ++ [{function,L,foo,0,[{clause,L,[],[],[E]}]}], - [{function,L,foo,0,[{clause,L,[],[],[NE]}]}] = - erl_expand_records:module(Forms, [strict_record_tests]), + Forms0 = RecordDefs ++ [{function,L,foo,0,[{clause,L,[],[],[E]}]}], + Forms = erl_expand_records:module(Forms0, [strict_record_tests]), + {function,L,foo,0,[{clause,L,[],[],[NE]}]} = lists:last(Forms), prep_rec(NE). prep_rec({value,_CommandN,_V}=Value) -> @@ -1081,6 +1081,8 @@ record_fields([{record_field,_,{atom,_,Field}} | Fs]) -> [Field | record_fields(Fs)]; record_fields([{record_field,_,{atom,_,Field},_} | Fs]) -> [Field | record_fields(Fs)]; +record_fields([{typed_record_field,Field,_Type} | Fs]) -> + record_fields([Field | Fs]); record_fields([]) -> []. diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl index 24fc8ce204..4e629a5e56 100644 --- a/lib/stdlib/src/slave.erl +++ b/lib/stdlib/src/slave.erl @@ -289,10 +289,7 @@ register_unique_name(Number) -> %% no need to use rsh. mk_cmd(Host, Name, Args, Waiter, Prog0) -> - Prog = case os:type() of - {ose,_} -> mk_ose_prog(Prog0); - _ -> quote_progname(Prog0) - end, + Prog = quote_progname(Prog0), BasicCmd = lists:concat([Prog, " -detached -noinput -master ", node(), " ", long_or_short(), Name, "@", Host, @@ -312,24 +309,6 @@ mk_cmd(Host, Name, Args, Waiter, Prog0) -> end end. -%% On OSE we have to pass the beam arguments directory to the slave -%% process. To find out what arguments that should be passed on we -%% make an assumption. All arguments after the last "--" should be -%% skipped. So given these arguments: -%% -Muycs256 -A 1 -- -root /mst/ -progname beam.debug.smp -- -home /mst/ -- -kernel inetrc '"/mst/inetrc.conf"' -- -name test@localhost -%% we send -%% -Muycs256 -A 1 -- -root /mst/ -progname beam.debug.smp -- -home /mst/ -- -kernel inetrc '"/mst/inetrc.conf"' -- -%% to the slave with whatever other args that are added in mk_cmd. -mk_ose_prog(Prog) -> - SkipTail = fun("--",[]) -> - ["--"]; - (_,[]) -> - []; - (Arg,Args) -> - [Arg," "|Args] - end, - [Prog,tl(lists:foldr(SkipTail,[],erlang:system_info(emu_args)))]. - %% This is an attempt to distinguish between spaces in the program %% path and spaces that separate arguments. The program is quoted to %% allow spaces in the path. diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl index cecdebd0c8..0400c845ab 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2014. All Rights Reserved. +%% Copyright Ericsson AB 1996-2015. 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. @@ -110,11 +110,13 @@ -define(SET, sets:set). -record(state, {name, - strategy :: strategy(), + strategy :: strategy() | 'undefined', children = [] :: [child_rec()], - dynamics :: ?DICT(pid(), list()) | ?SET(pid()), - intensity :: non_neg_integer(), - period :: pos_integer(), + dynamics :: {'dict', ?DICT(pid(), list())} + | {'set', ?SET(pid())} + | 'undefined', + intensity :: non_neg_integer() | 'undefined', + period :: pos_integer() | 'undefined', restarts = [], dynamic_restarts = 0 :: non_neg_integer(), module, @@ -579,7 +581,7 @@ handle_cast({try_again_restart,Pid}, #state{children=[Child]}=State) when ?is_simple(State) -> RT = Child#child.restart_type, RPid = restarting(Pid), - case dynamic_child_args(RPid, dynamics_db(RT, State#state.dynamics)) of + case dynamic_child_args(RPid, RT, State#state.dynamics) of {ok, Args} -> {M, F, _} = Child#child.mfargs, NChild = Child#child{pid = RPid, mfargs = {M, F, Args}}, @@ -737,7 +739,7 @@ handle_start_child(Child, State) -> restart_child(Pid, Reason, #state{children = [Child]} = State) when ?is_simple(State) -> RestartType = Child#child.restart_type, - case dynamic_child_args(Pid, dynamics_db(RestartType, State#state.dynamics)) of + case dynamic_child_args(Pid, RestartType, State#state.dynamics) of {ok, Args} -> {M, F, _} = Child#child.mfargs, NChild = Child#child{pid = Pid, mfargs = {M, F, Args}}, @@ -821,16 +823,18 @@ restart(simple_one_for_one, Child, State0) -> State#state.dynamics)), case do_start_child_i(M, F, A) of {ok, Pid} -> - NState = State#state{dynamics = ?DICTS:store(Pid, A, Dynamics)}, + DynamicsDb = {dict, ?DICTS:store(Pid, A, Dynamics)}, + NState = State#state{dynamics = DynamicsDb}, {ok, NState}; {ok, Pid, _Extra} -> - NState = State#state{dynamics = ?DICTS:store(Pid, A, Dynamics)}, + DynamicsDb = {dict, ?DICTS:store(Pid, A, Dynamics)}, + NState = State#state{dynamics = DynamicsDb}, {ok, NState}; {error, Error} -> NRestarts = State#state.dynamic_restarts + 1, + DynamicsDb = {dict, ?DICTS:store(restarting(OldPid), A, Dynamics)}, NState = State#state{dynamic_restarts = NRestarts, - dynamics = ?DICTS:store(restarting(OldPid), A, - Dynamics)}, + dynamics = DynamicsDb}, report_error(start_error, Error, Child, State#state.name), {try_again, NState} end; @@ -1113,31 +1117,32 @@ save_child(Child, #state{children = Children} = State) -> State#state{children = [Child |Children]}. save_dynamic_child(temporary, Pid, _, #state{dynamics = Dynamics} = State) -> - State#state{dynamics = ?SETS:add_element(Pid, dynamics_db(temporary, Dynamics))}; + DynamicsDb = dynamics_db(temporary, Dynamics), + State#state{dynamics = {set, ?SETS:add_element(Pid, DynamicsDb)}}; save_dynamic_child(RestartType, Pid, Args, #state{dynamics = Dynamics} = State) -> - State#state{dynamics = ?DICTS:store(Pid, Args, dynamics_db(RestartType, Dynamics))}. + DynamicsDb = dynamics_db(RestartType, Dynamics), + State#state{dynamics = {dict, ?DICTS:store(Pid, Args, DynamicsDb)}}. dynamics_db(temporary, undefined) -> ?SETS:new(); dynamics_db(_, undefined) -> ?DICTS:new(); -dynamics_db(_,Dynamics) -> - Dynamics. - -dynamic_child_args(Pid, Dynamics) -> - case ?SETS:is_set(Dynamics) of - true -> - {ok, undefined}; - false -> - ?DICTS:find(Pid, Dynamics) - end. +dynamics_db(_, {_Tag, DynamicsDb}) -> + DynamicsDb. + +dynamic_child_args(_Pid, temporary, _DynamicsDb) -> + {ok, undefined}; +dynamic_child_args(Pid, _RT, {dict, DynamicsDb}) -> + ?DICTS:find(Pid, DynamicsDb); +dynamic_child_args(_Pid, _RT, undefined) -> + error. state_del_child(#child{pid = Pid, restart_type = temporary}, State) when ?is_simple(State) -> NDynamics = ?SETS:del_element(Pid, dynamics_db(temporary, State#state.dynamics)), - State#state{dynamics = NDynamics}; + State#state{dynamics = {set, NDynamics}}; state_del_child(#child{pid = Pid, restart_type = RType}, State) when ?is_simple(State) -> NDynamics = ?DICTS:erase(Pid, dynamics_db(RType, State#state.dynamics)), - State#state{dynamics = NDynamics}; + State#state{dynamics = {dict, NDynamics}}; state_del_child(Child, State) -> NChildren = del_child(Child#child.name, State#state.children), State#state{children = NChildren}. @@ -1171,19 +1176,19 @@ split_child(_, [], After) -> get_child(Name, State) -> get_child(Name, State, false). + get_child(Pid, State, AllowPid) when AllowPid, is_pid(Pid) -> get_dynamic_child(Pid, State); get_child(Name, State, _) -> lists:keysearch(Name, #child.name, State#state.children). get_dynamic_child(Pid, #state{children=[Child], dynamics=Dynamics}) -> - DynamicsDb = dynamics_db(Child#child.restart_type, Dynamics), - case is_dynamic_pid(Pid, DynamicsDb) of + case is_dynamic_pid(Pid, Dynamics) of true -> {value, Child#child{pid=Pid}}; false -> RPid = restarting(Pid), - case is_dynamic_pid(RPid, DynamicsDb) of + case is_dynamic_pid(RPid, Dynamics) of true -> {value, Child#child{pid=RPid}}; false -> @@ -1194,13 +1199,12 @@ get_dynamic_child(Pid, #state{children=[Child], dynamics=Dynamics}) -> end end. -is_dynamic_pid(Pid, Dynamics) -> - case ?SETS:is_set(Dynamics) of - true -> - ?SETS:is_element(Pid, Dynamics); - false -> - ?DICTS:is_key(Pid, Dynamics) - end. +is_dynamic_pid(Pid, {dict, Dynamics}) -> + ?DICTS:is_key(Pid, Dynamics); +is_dynamic_pid(Pid, {set, Dynamics}) -> + ?SETS:is_element(Pid, Dynamics); +is_dynamic_pid(_Pid, undefined) -> + false. replace_child(Child, State) -> Chs = do_replace_child(Child, State#state.children), 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 35e587afcc..ad8829c471 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() -> @@ -4012,6 +4014,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 4e5df661b3..955b482313 100644 --- a/lib/stdlib/test/epp_SUITE.erl +++ b/lib/stdlib/test/epp_SUITE.erl @@ -25,9 +25,9 @@ upcase_mac_1/1, upcase_mac_2/1, variable_1/1, otp_4870/1, otp_4871/1, otp_5362/1, 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_8130/1, overload_mac/1, otp_8388/1, otp_8470/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]). @@ -68,9 +68,9 @@ all() -> [rec_1, {group, upcase_mac}, include_local, predef_mac, {group, variable}, otp_4870, otp_4871, otp_5362, pmod, not_circular, skip_header, otp_6277, otp_7702, otp_8130, - overload_mac, otp_8388, otp_8470, otp_8503, otp_8562, + overload_mac, otp_8388, otp_8470, 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" @@ -826,14 +842,14 @@ otp_8130(Config) when is_list(Config) -> "-define(a, 3.14).\n" "t() -> ?a.\n"), ?line {ok,Epp} = epp:open(File, []), - ?line ['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE','LINE', - 'MACHINE','MODULE','MODULE_STRING'] = macs(Epp), + PreDefMacs = macs(Epp), + ['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE','LINE', + 'MACHINE','MODULE','MODULE_STRING'] = PreDefMacs, ?line {ok,[{'-',_},{atom,_,file}|_]} = epp:scan_erl_form(Epp), ?line {ok,[{'-',_},{atom,_,module}|_]} = epp:scan_erl_form(Epp), ?line {ok,[{atom,_,t}|_]} = epp:scan_erl_form(Epp), ?line {eof,_} = epp:scan_erl_form(Epp), - ?line ['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE','LINE', - 'MACHINE','MODULE','MODULE_STRING',a] = macs(Epp), + [a] = macs(Epp) -- PreDefMacs, ?line epp:close(Epp), %% escript @@ -1214,23 +1230,8 @@ otp_8470(Config) when is_list(Config) -> ?line receive _ -> fail() after 0 -> ok end, ok. -otp_8503(doc) -> - ["OTP-8503. Record with no fields is considered typed."]; -otp_8503(suite) -> - []; -otp_8503(Config) when is_list(Config) -> - Dir = ?config(priv_dir, Config), - C = <<"-record(r, {}).">>, - ?line File = filename:join(Dir, "otp_8503.erl"), - ?line ok = file:write_file(File, C), - ?line {ok, List} = epp:parse_file(File, [], []), - ?line [_] = [F || {attribute,_,type,{{record,r},[],[]}}=F <- List], - file:delete(File), - ?line receive _ -> fail() after 0 -> ok end, - ok. - otp_8562(doc) -> - ["OTP-8503. Record with no fields is considered typed."]; + ["OTP-8562. Record with no fields is considered typed."]; otp_8562(suite) -> []; otp_8562(Config) when is_list(Config) -> @@ -1476,6 +1477,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 +1519,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], @@ -1528,8 +1545,11 @@ compile_test(Config, Test0) -> warnings(File, Ws) -> case lists:append([W || {F, W} <- Ws, F =:= File]) of - [] -> []; - L -> {warnings, L} + [] -> + []; + L -> + call_format_error(L), + {warnings, L} end. compile_file(File, Opts) -> @@ -1540,12 +1560,20 @@ compile_file(File, Opts) -> end. errs([{File,Es}|L], File) -> + call_format_error(Es), Es ++ errs(L, File); errs([_|L], File) -> errs(L, File); errs([], _File) -> []. +%% Smoke test and coverage of format_error/1. +call_format_error([{_,M,E}|T]) -> + _ = M:format_error(E), + call_format_error(T); +call_format_error([]) -> + ok. + epp_parse_file(File, Opts) -> case epp:parse_file(File, Opts) of {ok, Forms} -> diff --git a/lib/stdlib/test/erl_anno_SUITE.erl b/lib/stdlib/test/erl_anno_SUITE.erl index 66b02151a0..0369455846 100644 --- a/lib/stdlib/test/erl_anno_SUITE.erl +++ b/lib/stdlib/test/erl_anno_SUITE.erl @@ -34,7 +34,7 @@ init_per_testcase/2, end_per_testcase/2]). -export([new/1, is_anno/1, generated/1, end_location/1, file/1, - line/1, location/1, record/1, text/1, bad/1, neg_line/1]). + line/1, location/1, record/1, text/1, bad/1]). -export([parse_abstract/1, mapfold_anno/1]). @@ -43,7 +43,7 @@ all() -> groups() -> [{anno, [], [new, is_anno, generated, end_location, file, - line, location, record, text, bad, neg_line]}, + line, location, record, text, bad]}, {parse, [], [parse_abstract, mapfold_anno]}]. suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -229,74 +229,6 @@ bad(_Config) -> (catch erl_anno:record(bad)), % 1st arg not opaque ok. -neg_line(doc) -> - ["Test negative line numbers (OTP 18)"]; -neg_line(_Config) -> - neg_line1(false), - neg_line1(true), - ok. - -neg_line1(TextToo) -> - Minus8_0 = erl_anno:new(-8), - Plus8_0 = erl_anno:new(8), - Minus8C_0 = erl_anno:new({-8, 17}), - Plus8C_0 = erl_anno:new({8, 17}), - - [Minus8, Plus8, Minus8C, Plus8C] = - [case TextToo of - true -> - erl_anno:set_text("foo", A); - false -> - A - end || A <- [Minus8_0, Plus8_0, Minus8C_0, Plus8C_0]], - - tst(-3, erl_anno:set_location(3, Minus8)), - tst(-3, erl_anno:set_location(-3, Plus8)), - tst(-3, erl_anno:set_location(-3, Minus8)), - tst({-3,9}, erl_anno:set_location({3, 9}, Minus8)), - tst({-3,9}, erl_anno:set_location({-3, 9}, Plus8)), - tst({-3,9}, erl_anno:set_location({-3, 9}, Minus8)), - tst(-3, erl_anno:set_location(3, Minus8C)), - tst(-3, erl_anno:set_location(-3, Plus8C)), - tst(-3, erl_anno:set_location(-3, Minus8C)), - tst({-3,9}, erl_anno:set_location({3, 9}, Minus8C)), - tst({-3,9}, erl_anno:set_location({-3, 9}, Plus8C)), - tst({-3,9}, erl_anno:set_location({-3, 9}, Minus8C)), - - tst(-8, erl_anno:set_generated(true, Plus8)), - tst(-8, erl_anno:set_generated(true, Minus8)), - tst({-8,17}, erl_anno:set_generated(true, Plus8C)), - tst({-8,17}, erl_anno:set_generated(true, Minus8C)), - tst(8, erl_anno:set_generated(false, Plus8)), - tst(8, erl_anno:set_generated(false, Minus8)), - tst({8,17}, erl_anno:set_generated(false, Plus8C)), - tst({8,17}, erl_anno:set_generated(false, Minus8C)), - - tst(-3, erl_anno:set_line(3, Minus8)), - tst(-3, erl_anno:set_line(-3, Plus8)), - tst(-3, erl_anno:set_line(-3, Minus8)), - tst({-3,17}, erl_anno:set_line(3, Minus8C)), - tst({-3,17}, erl_anno:set_line(-3, Plus8C)), - tst({-3,17}, erl_anno:set_line(-3, Minus8C)), - ok. - -tst(Term, Anno) -> - ?format("Term: ~p\n", [Term]), - ?format("Anno: ~p\n", [Anno]), - case anno_to_term(Anno) of - Term -> - ok; - Else -> - case lists:keyfind(location, 1, Else) of - {location, Term} -> - ok; - _Else2 -> - ?format("Else2 ~p\n", [_Else2]), - io:format("expected ~p\n got ~p\n", [Term, Else]), - exit({Term, Else}) - end - end. - parse_abstract(doc) -> ["Test erl_parse:new_anno/1, erl_parse:anno_to_term/1" ", and erl_parse:anno_from_term/1"]; diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 375fb6bc93..8f0ac828ec 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -65,7 +65,8 @@ too_many_arguments/1, basic_errors/1,bin_syntax_errors/1, predef/1, - maps/1,maps_type/1,otp_11851/1,otp_12195/1, otp_13230/1 + maps/1,maps_type/1,otp_11851/1,otp_11879/1,otp_13230/1, + record_errors/1 ]). % Default timetrap timeout (set in init_per_testcase). @@ -94,7 +95,8 @@ 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, otp_12195, otp_13230]. + maps, maps_type, otp_11851, otp_11879, otp_13230, + record_errors]. groups() -> [{unused_vars_warn, [], @@ -1296,12 +1298,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 +1319,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. @@ -2599,6 +2607,23 @@ otp_5878(Config) when is_list(Config) -> ">>, ?line [] = run_test2(Config, UsedByType, [warn_unused_record]), + %% Abstract code generated by OTP 18. Note that the type info for + %% record fields has been put in a separate form. + OldAbstract = [{attribute,1,file,{"rec.erl",1}}, + {attribute,1,module,rec}, + {attribute,3,export,[{t,0}]}, + {attribute,7,record,{r,[{record_field,7,{atom,7,f}}]}}, + {attribute,7,type, + {{record,r}, + [{typed_record_field, + {record_field,7,{atom,7,f}}, + {type,7,union,[{atom,7,undefined},{type,7,atom,[]}]}}], + []}}, + {function,9,t,0,[{clause,9,[],[],[{record,10,r,[]}]}]}, + {eof,11}], + {error,[{"rec.erl",[{7,erl_lint,old_abstract_code}]}],[]} = + compile:forms(OldAbstract, [return, report]), + ok. otp_6885(doc) -> @@ -3843,38 +3868,27 @@ otp_11851(Config) when is_list(Config) -> [] = run(Config, Ts), ok. -otp_12195(doc) -> - "OTP-12195: Check obsolete types (tailor made for OTP 18)."; -otp_12195(Config) when is_list(Config) -> - Ts = [{otp_12195_1, - <<"-export_type([r1/0]). - -type r1() :: erl_scan:line() - | erl_scan:column() - | erl_scan:location() - | erl_anno:line().">>, - [], - {warnings,[{2,erl_lint, - {deprecated_type,{erl_scan,line,0}, - "deprecated (will be removed in OTP 19); " - "use erl_anno:line() instead"}}, - {3,erl_lint, - {deprecated_type,{erl_scan,column,0}, - "deprecated (will be removed in OTP 19); use " - "erl_anno:column() instead"}}, - {4,erl_lint, - {deprecated_type,{erl_scan,location,0}, - "deprecated (will be removed in OTP 19); " - "use erl_anno:location() instead"}}]}}, - {otp_12195_2, - <<"-export_type([r1/0]). - -compile(nowarn_deprecated_type). - -type r1() :: erl_scan:line() - | erl_scan:column() - | erl_scan:location() - | erl_anno:line().">>, - [], - []}], - [] = run(Config, Ts), +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) -> @@ -3886,6 +3900,17 @@ otp_13230(Config) when is_list(Config) -> []} = run_test2(Config, Abstr, []), ok. +record_errors(Config) when is_list(Config) -> + Ts = [{rec1, + <<"-record(r, {a,b}). + b() -> #r{a=foo,b=42,a=bar}. + u(R) -> R#r{a=1,b=2,a=2}. + ">>, + [], + {errors,[{2,erl_lint,{redefine_field,r,a}}, + {3,erl_lint,{redefine_field,r,a}}],[]}}], + run(Config, Ts). + run(Config, Tests) -> F = fun({N,P,Ws,E}, BadL) -> case catch run_test(Config, P, Ws) of diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index 92e2764c65..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);" @@ -928,7 +931,9 @@ otp_8522(Config) when is_list(Config) -> ?line {ok, _} = compile:file(FileName, [{outdir,?privdir},debug_info]), BF = filename("otp_8522", Config), ?line {ok, A} = beam_lib:chunks(BF, [abstract_code]), - ?line 5 = count_atom(A, undefined), + %% OTP-12719: Since 'undefined' is no longer added by the Erlang + %% Parser, the number of 'undefined' is 4. It used to be 5. + ?line 4 = count_atom(A, undefined), ok. count_atom(A, A) -> @@ -998,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">>, @@ -1065,7 +1062,7 @@ otp_9147(Config) when is_list(Config) -> ?line {ok, Bin} = file:read_file(PFileName), %% The parentheses around "F1 :: a | b" are new (bugfix). ?line true = - lists:member("-record(undef,{f1 :: undefined | (F1 :: a | b)}).", + lists:member("-record(undef,{f1 :: F1 :: a | b}).", string:tokens(binary_to_list(Bin), "\n")), ok. diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl index 12ea3d128c..db669aae99 100644 --- a/lib/stdlib/test/erl_scan_SUITE.erl +++ b/lib/stdlib/test/erl_scan_SUITE.erl @@ -191,8 +191,7 @@ otp_7810(Config) when is_list(Config) -> ?line ok = more_chars(), ?line ok = more_options(), - ?line ok = attributes_info(), - ?line ok = set_attribute(), + ?line ok = anno_info(), ok. @@ -269,7 +268,7 @@ punctuations() -> comments() -> ?line test("a %%\n b"), - {ok,[],1} = erl_scan_string("%"), + ?line {ok,[],1} = erl_scan_string("%"), ?line test("a %%\n b"), {ok,[{atom,{1,1},a},{atom,{2,2},b}],{2,3}} = erl_scan_string("a %%\n b", {1,1}), @@ -338,7 +337,7 @@ base_integers() -> erl_scan:string(Str) end || {BS,S} <- [{"3","3"},{"15","f"}, {"12","c"}] ], - {ok,[{integer,1,239},{'@',1}],1} = erl_scan_string("16#ef@"), + ?line {ok,[{integer,1,239},{'@',1}],1} = erl_scan_string("16#ef@"), {ok,[{integer,{1,1},239},{'@',{1,6}}],{1,7}} = erl_scan_string("16#ef@", {1,1}, []), {ok,[{integer,{1,1},14},{atom,{1,5},g@}],{1,7}} = @@ -387,20 +386,15 @@ dots() -> R2 = erl_scan_string(S, {1,1}, []) end || {S, R, R2} <- Dot], - ?line {ok,[{dot,_}=T1],{1,2}} = erl_scan:string(".", {1,1}, text), - ?line [{column,1},{length,1},{line,1},{text,"."}] = - erl_scan:token_info(T1, [column, length, line, text]), - ?line {ok,[{dot,_}=T2],{1,3}} = erl_scan:string(".%", {1,1}, text), - ?line [{column,1},{length,1},{line,1},{text,"."}] = - erl_scan:token_info(T2, [column, length, line, text]), - ?line {ok,[{dot,_}=T3],{1,6}} = + {ok,[{dot,_}=T1],{1,2}} = erl_scan:string(".", {1,1}, text), + [1, 1, "."] = token_info(T1), + {ok,[{dot,_}=T2],{1,3}} = erl_scan:string(".%", {1,1}, text), + [1, 1, "."] = token_info(T2), + {ok,[{dot,_}=T3],{1,6}} = erl_scan:string(".% öh", {1,1}, text), - ?line [{column,1},{length,1},{line,1},{text,"."}] = - erl_scan:token_info(T3, [column, length, line, text]), - ?line {error,{{1,2},erl_scan,char},{1,3}} = - erl_scan:string(".$", {1,1}), - ?line {error,{{1,2},erl_scan,char},{1,4}} = - erl_scan:string(".$\\", {1,1}), + [1, 1, "."] = token_info(T3), + {error,{{1,2},erl_scan,char},{1,3}} = erl_scan:string(".$", {1,1}), + {error,{{1,2},erl_scan,char},{1,4}} = erl_scan:string(".$\\", {1,1}), test_string(". ", [{dot,{1,1}}]), test_string(". ", [{dot,{1,1}}]), @@ -413,18 +407,18 @@ dots() -> test_string(".a", [{'.',{1,1}},{atom,{1,2},a}]), test_string("%. \n. ", [{dot,{2,1}}]), - ?line {more,C} = erl_scan:tokens([], "%. ",{1,1}, return), + {more,C} = erl_scan:tokens([], "%. ",{1,1}, return), {done,{ok,[{comment,{1,1},"%. "}, {white_space,{1,4},"\n"}, {dot,{2,1}}], {2,3}}, ""} = erl_scan_tokens(C, "\n. ", {1,1}, return), % any loc, any options - ?line [test_string(S, R) || - {S, R} <- [{".$\n", [{'.',{1,1}},{char,{1,2},$\n}]}, - {"$\\\n", [{char,{1,1},$\n}]}, - {"'\\\n'", [{atom,{1,1},'\n'}]}, - {"$\n", [{char,{1,1},$\n}]}] ], + [test_string(S, R) || + {S, R} <- [{".$\n", [{'.',{1,1}},{char,{1,2},$\n}]}, + {"$\\\n", [{char,{1,1},$\n}]}, + {"'\\\n'", [{atom,{1,1},'\n'}]}, + {"$\n", [{char,{1,1},$\n}]}] ], ok. chars() -> @@ -540,8 +534,8 @@ eof() -> %% A dot followed by eof is special: ?line {more, C} = erl_scan:tokens([], "a.", 1), - {done,{ok,[{atom,1,a},{dot,1}],1},eof} = erl_scan_tokens(C,eof,1), - {ok,[{atom,1,foo},{dot,1}],1} = erl_scan_string("foo."), + ?line {done,{ok,[{atom,1,a},{dot,1}],1},eof} = erl_scan_tokens(C,eof,1), + ?line {ok,[{atom,1,foo},{dot,1}],1} = erl_scan_string("foo."), %% With column. {more, CCol} = erl_scan:tokens([], "a.", {1,1}), @@ -655,145 +649,72 @@ options() -> ok. more_options() -> - ?line {ok,[{atom,A1,foo}],{19,20}} = + {ok,[{atom,_,foo}=T1],{19,20}} = erl_scan:string("foo", {19,17},[]), - ?line [{column,17},{line,19}] = erl_scan:attributes_info(A1), - ?line {done,{ok,[{atom,A2,foo},{dot,_}],{19,22}},[]} = + {19,17} = erl_scan:location(T1), + {done,{ok,[{atom,_,foo}=T2,{dot,_}],{19,22}},[]} = erl_scan:tokens([], "foo. ", {19,17}, [bad_opt]), % type error - ?line [{column,17},{line,19}] = erl_scan:attributes_info(A2), - ?line {ok,[{atom,A3,foo}],{19,20}} = + {19,17} = erl_scan:location(T2), + {ok,[{atom,_,foo}=T3],{19,20}} = erl_scan:string("foo", {19,17},[text]), - ?line [{column,17},{length,3},{line,19},{text,"foo"}] = - erl_scan:attributes_info(A3), + {19,17} = erl_scan:location(T3), + "foo" = erl_scan:text(T3), - ?line {ok,[{atom,A4,foo}],1} = erl_scan:string("foo", 1, [text]), - ?line [{length,3},{line,1},{text,"foo"}] = erl_scan:attributes_info(A4), + {ok,[{atom,_,foo}=T4],1} = erl_scan:string("foo", 1, [text]), + 1 = erl_scan:line(T4), + 1 = erl_scan:location(T4), + "foo" = erl_scan:text(T4), ok. token_info() -> - ?line {ok,[T1],_} = erl_scan:string("foo", {1,18}, [text]), + {ok,[T1],_} = erl_scan:string("foo", {1,18}, [text]), {'EXIT',{badarg,_}} = - (catch {foo, erl_scan:token_info(T1, foo)}), % type error - ?line {line,1} = erl_scan:token_info(T1, line), - ?line {column,18} = erl_scan:token_info(T1, column), - ?line {length,3} = erl_scan:token_info(T1, length), - ?line {text,"foo"} = erl_scan:token_info(T1, text), - ?line [{category,atom},{column,18},{length,3},{line,1}, - {symbol,foo},{text,"foo"}] = - erl_scan:token_info(T1), - ?line [{length,3},{column,18}] = - erl_scan:token_info(T1, [length, column]), - ?line [{location,{1,18}}] = - erl_scan:token_info(T1, [location]), - ?line {category,atom} = erl_scan:token_info(T1, category), - ?line [{symbol,foo}] = erl_scan:token_info(T1, [symbol]), - - ?line {ok,[T2],_} = erl_scan:string("foo", 1, []), - ?line {line,1} = erl_scan:token_info(T2, line), - ?line undefined = erl_scan:token_info(T2, column), - ?line undefined = erl_scan:token_info(T2, length), - ?line undefined = erl_scan:token_info(T2, text), - ?line {location,1} = erl_scan:token_info(T2, location), - ?line [{category,atom},{line,1},{symbol,foo}] = erl_scan:token_info(T2), - ?line [{line,1}] = erl_scan:token_info(T2, [length, line]), - - ?line {ok,[T3],_} = erl_scan:string("=", 1, []), - ?line [{line,1}] = erl_scan:token_info(T3, [column, line]), - ?line {category,'='} = erl_scan:token_info(T3, category), - ?line [{symbol,'='}] = erl_scan:token_info(T3, [symbol]), + (catch {foo, erl_scan:category(foo)}), % type error + {'EXIT',{badarg,_}} = + (catch {foo, erl_scan:symbol(foo)}), % type error + atom = erl_scan:category(T1), + foo = erl_scan:symbol(T1), + + {ok,[T2],_} = erl_scan:string("foo", 1, []), + 1 = erl_scan:line(T2), + undefined = erl_scan:column(T2), + undefined = erl_scan:text(T2), + 1 = erl_scan:location(T2), + + {ok,[T3],_} = erl_scan:string("=", 1, []), + '=' = erl_scan:category(T3), + '=' = erl_scan:symbol(T3), ok. -attributes_info() -> - ?line {'EXIT',_} = - (catch {foo,erl_scan:attributes_info(foo)}), % type error - [{line,18}] = erl_scan:attributes_info(erl_anno:new(18)), - {location,19} = - erl_scan:attributes_info(erl_anno:new(19), location), - ?line {ok,[{atom,A0,foo}],_} = erl_scan:string("foo", 19, [text]), - ?line {location,19} = erl_scan:attributes_info(A0, location), - - ?line {ok,[{atom,A3,foo}],_} = erl_scan:string("foo", {1,3}, [text]), - ?line {line,1} = erl_scan:attributes_info(A3, line), - ?line {column,3} = erl_scan:attributes_info(A3, column), - ?line {location,{1,3}} = erl_scan:attributes_info(A3, location), - ?line {text,"foo"} = erl_scan:attributes_info(A3, text), - - ?line {ok,[{atom,A4,foo}],_} = erl_scan:string("foo", 2, [text]), - ?line {line,2} = erl_scan:attributes_info(A4, line), - ?line undefined = erl_scan:attributes_info(A4, column), - ?line {location,2} = erl_scan:attributes_info(A4, location), - ?line {text,"foo"} = erl_scan:attributes_info(A4, text), - - ?line {ok,[{atom,A5,foo}],_} = erl_scan:string("foo", {1,3}, []), - ?line {line,1} = erl_scan:attributes_info(A5, line), - ?line {column,3} = erl_scan:attributes_info(A5, column), - ?line {location,{1,3}} = erl_scan:attributes_info(A5, location), - ?line undefined = erl_scan:attributes_info(A5, text), - - ?line undefined = erl_scan:attributes_info([], line), % type error +anno_info() -> + {'EXIT',_} = + (catch {foo,erl_scan:line(foo)}), % type error + {ok,[{atom,_,foo}=T0],_} = erl_scan:string("foo", 19, [text]), + 19 = erl_scan:location(T0), + 19 = erl_scan:end_location(T0), + + {ok,[{atom,_,foo}=T3],_} = erl_scan:string("foo", {1,3}, [text]), + 1 = erl_scan:line(T3), + 3 = erl_scan:column(T3), + {1,3} = erl_scan:location(T3), + {1,6} = erl_scan:end_location(T3), + "foo" = erl_scan:text(T3), + + {ok,[{atom,_,foo}=T4],_} = erl_scan:string("foo", 2, [text]), + 2 = erl_scan:line(T4), + undefined = erl_scan:column(T4), + 2 = erl_scan:location(T4), + "foo" = erl_scan:text(T4), + + {ok,[{atom,_,foo}=T5],_} = erl_scan:string("foo", {1,3}, []), + 1 = erl_scan:line(T5), + 3 = erl_scan:column(T5), + {1,3} = erl_scan:location(T5), + undefined = erl_scan:text(T5), ok. -set_attribute() -> - F = fun(Line) -> -Line end, - Anno2 = erl_anno:new(2), - A0 = erl_scan:set_attribute(line, Anno2, F), - {line, -2} = erl_scan:attributes_info(A0, line), - ?line {ok,[{atom,A1,foo}],_} = erl_scan:string("foo", {9,17}), - ?line A2 = erl_scan:set_attribute(line, A1, F), - ?line {line,-9} = erl_scan:attributes_info(A2, line), - ?line {location,{-9,17}} = erl_scan:attributes_info(A2, location), - ?line [{line,-9},{column,17}] = - erl_scan:attributes_info(A2, [line,column,text]), - - F2 = fun(Line) -> {17,Line} end, - ?line Attr1 = erl_scan:set_attribute(line, 2, F2), - ?line {line,{17,2}} = erl_scan:attributes_info(Attr1, line), - ?line undefined = erl_scan:attributes_info(Attr1, column), - ?line {location,{17,2}} = % a bit mixed up - erl_scan:attributes_info(Attr1, location), - - ?line A3 = erl_scan:set_attribute(line, A1, F2), - ?line {line,{17,9}} = erl_scan:attributes_info(A3, line), - ?line {location,{{17,9},17}} = erl_scan:attributes_info(A3, location), - ?line [{line,{17,9}},{column,17}] = - erl_scan:attributes_info(A3, [line,column,text]), - - ?line {ok,[{atom,A4,foo}],_} = erl_scan:string("foo", {9,17}, [text]), - ?line A5 = erl_scan:set_attribute(line, A4, F), - ?line {line,-9} = erl_scan:attributes_info(A5, line), - ?line {location,{-9,17}} = erl_scan:attributes_info(A5, location), - ?line [{line,-9},{column,17},{text,"foo"}] = - erl_scan:attributes_info(A5, [line,column,text]), - - ?line {ok,[{atom,A6,foo}],_} = erl_scan:string("foo", 11, [text]), - ?line A7 = erl_scan:set_attribute(line, A6, F2), - %% Incompatible with pre 18: - %% {line,{17,11}} = erl_scan:attributes_info(A7, line), - {line,17} = erl_scan:attributes_info(A7, line), - ?line {location,{17,11}} = % mixed up - erl_scan:attributes_info(A7, location), - %% Incompatible with pre 18: - %% [{line,{17,11}},{text,"foo"}] = - %% erl_scan:attributes_info(A7, [line,column,text]), - [{line,17},{column,11},{text,"foo"}] = - erl_scan:attributes_info(A7, [line,column,text]), - - ?line {'EXIT',_} = - (catch {foo, erl_scan:set_attribute(line, [], F2)}), % type error - ?line {'EXIT',{badarg,_}} = - (catch {foo, erl_scan:set_attribute(column, [], F2)}), % type error - - Attr10 = erl_anno:new(8), - Attr20 = erl_scan:set_attribute(line, Attr10, - fun(L) -> {nos,'X',L} end), - %% OTP-9412 - Attr30 = erl_scan:set_attribute(line, Attr20, - fun({nos,_V,VL}) -> VL end), - 8 = erl_anno:to_term(Attr30), - ok. - column_errors() -> ?line {error,{{1,1},erl_scan,{string,$',""}},{1,3}} = % $' erl_scan:string("'\\",{1,1}), @@ -892,14 +813,13 @@ unicode() -> erl_scan_string(Qs, 1), {ok,[Q2],{1,9}} = erl_scan:string("$\\x{aaa}", {1,1}, [text]), - [{category,char},{column,1},{length,8}, - {line,1},{symbol,16#aaa},{text,Qs}] = - erl_scan:token_info(Q2), + [{category,char},{column,1},{line,1},{symbol,16#aaa},{text,Qs}] = + token_info_long(Q2), U1 = "\"\\x{aaa}\"", - {ok,[{string,A1,[2730]}],{1,10}} = erl_scan:string(U1, {1,1}, [text]), - [{line,1},{column,1},{text,"\"\\x{aaa}\""}] = - erl_scan:attributes_info(A1, [line, column, text]), + {ok,[{string,_,[2730]}=T1],{1,10}} = erl_scan:string(U1, {1,1}, [text]), + {1,1} = erl_scan:location(T1), + "\"\\x{aaa}\"" = erl_scan:text(T1), {ok,[{string,1,[2730]}],1} = erl_scan_string(U1, 1), U2 = "\"\\x41\\x{fff}\\x42\"", @@ -1012,16 +932,13 @@ otp_10302(Config) when is_list(Config) -> Qs = "$\\x{aaa}", {ok,[{char,1,2730}],1} = erl_scan_string(Qs, 1), {ok,[Q2],{1,9}} = erl_scan:string(Qs,{1,1},[text]), - [{category,char},{column,1},{length,8}, - {line,1},{symbol,16#aaa},{text,Qs}] = - erl_scan:token_info(Q2), - - Tags = [category, column, length, line, symbol, text], + [{category,char},{column,1},{line,1},{symbol,16#aaa},{text,Qs}] = + token_info_long(Q2), U1 = "\"\\x{aaa}\"", {ok,[T1],{1,10}} = erl_scan:string(U1, {1,1}, [text]), - [{category,string},{column,1},{length,9},{line,1}, - {symbol,[16#aaa]},{text,U1}] = erl_scan:token_info(T1, Tags), + [{category,string},{column,1},{line,1},{symbol,[16#aaa]},{text,U1}] = + token_info_long(T1), U2 = "\"\\x41\\x{fff}\\x42\"", {ok,[{string,1,[65,4095,66]}],1} = erl_scan_string(U2, 1), @@ -1353,9 +1270,7 @@ test_wsc([], []) -> ok; test_wsc([Token|Tokens], [Token2|Tokens2]) -> [Text, Text2] = [Text || - {text, Text} <- - [erl_scan:token_info(T, text) || - T <- [Token, Token2]]], + Text <- [erl_scan:text(T) || T <- [Token, Token2]]], Sz = erts_debug:size(Text), Sz2 = erts_debug:size({Text, Text2}), IsCompacted = Sz2 < 2*Sz+erts_debug:size({a,a}), @@ -1394,7 +1309,7 @@ all_same(L, Char) -> newlines_first([]) -> ok; newlines_first([Token|Tokens]) -> - {text,Text} = erl_scan:token_info(Token, text), + Text = erl_scan:text(Token), Nnls = length([C || C <- Text, C =:= $\n]), OK = case Text of [$\n|_] -> @@ -1414,7 +1329,7 @@ select_tokens(Tokens, Tags) -> lists:filter(fun(T) -> lists:member(element(1, T), Tags) end, Tokens). simplify([Token|Tokens]) -> - {line,Line} = erl_scan:token_info(Token, line), + Line = erl_scan:line(Token), [setelement(2, Token, erl_anno:new(Line)) | simplify(Tokens)]; simplify([]) -> []. @@ -1423,17 +1338,31 @@ get_text(Tokens) -> lists:flatten( [T || Token <- Tokens, - ({text,T} = erl_scan:token_info(Token, text)) =/= []]). + (T = erl_scan:text(Token)) =/= []]). test_decorated_tokens(String, Tokens) -> ToksAttrs = token_attrs(Tokens), test_strings(ToksAttrs, String, 1, 1). token_attrs(Tokens) -> - [{L,C,Len,T} || + [{L,C,length(T),T} || Token <- Tokens, - ([{line,L},{column,C},{length,Len},{text,T}] = - erl_scan:token_info(Token, [line,column,length,text])) =/= []]. + ([C,L,T] = token_info(Token)) =/= []]. + +token_info(T) -> + Column = erl_scan:column(T), + Line = erl_scan:line(T), + Text = erl_scan:text(T), + [Column, Line, Text]. + +token_info_long(T) -> + Column = erl_scan:column(T), + Line = erl_scan:line(T), + Text = erl_scan:text(T), + Category = erl_scan:category(T), + Symbol = erl_scan:symbol(T), + [{category,Category},{column,Column},{line,Line}, + {symbol,Symbol},{text,Text}]. test_strings([], _S, Line, Column) -> {Line,Column}; @@ -1514,8 +1443,7 @@ consistent_attributes([Ts | TsL]) -> L = [T || T <- Ts, is_integer(element(2, T))], case L of [] -> - TagsL = [[Tag || {Tag,_} <- - erl_scan:attributes_info(element(2, T))] || + TagsL = [[Tag || {Tag,_} <- defined(token_info_long(T))] || T <- Ts], case lists:usort(TagsL) of [_] -> @@ -1531,6 +1459,9 @@ consistent_attributes([Ts | TsL]) -> Ts end. +defined(L) -> + [{T,V} || {T,V} <- L, V =/= undefined]. + family_list(L) -> sofs:to_external(family(L)). diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 30a158d9e1..39d9ddaaa7 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)), @@ -731,10 +730,6 @@ chk_normal_tab_struct_size() -> % ?line ok % end. --define(DB_TREE_STACK_NEED,50). % The static stack for a tree, in halfword pointers are two internal words - % so the stack gets twice as big --define(DB_HASH_SIZEOF_EXTSEG,260). % The segment size in words, in halfword this will be twice as large. - adjust_xmem([T1,T2,T3,T4], {A0,B0,C0,D0} = _Mem0) -> %% Adjust for 64-bit, smp, and os: %% Table struct size may differ. @@ -748,19 +743,7 @@ adjust_xmem([T1,T2,T3,T4], {A0,B0,C0,D0} = _Mem0) -> % end, TabDiff = ?TAB_STRUCT_SZ, - Mem1 = {A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff}, - - case {erlang:system_info({wordsize,internal}),erlang:system_info({wordsize,external})} of - %% Halfword, corrections for regular pointers occupying two internal words. - {4,8} -> - {A1,B1,C1,D1} = Mem1, - {A1+4*ets:info(T1, size)+?DB_TREE_STACK_NEED, - B1+3*ets:info(T2, size)+?DB_HASH_SIZEOF_EXTSEG, - C1+3*ets:info(T3, size)+?DB_HASH_SIZEOF_EXTSEG, - D1+3*ets:info(T4, size)+?DB_HASH_SIZEOF_EXTSEG}; - _ -> - Mem1 - end. + {A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff}. t_whitebox(doc) -> ["Diverse whitebox testes"]; @@ -1346,7 +1329,7 @@ drop_match() -> ets_match(Tab,Expr) -> - case random:uniform(2) of + case rand:uniform(2) of 1 -> ets:match(Tab,Expr); _ -> @@ -1355,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); _ -> @@ -1371,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}) -> @@ -1383,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 " @@ -1417,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,'_'})), @@ -1977,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). @@ -2011,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, @@ -4684,11 +4663,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)]. @@ -4699,7 +4678,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); _ -> @@ -4708,14 +4687,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 -> @@ -4729,12 +4708,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) -> @@ -5097,11 +5076,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), @@ -5367,7 +5347,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), @@ -5618,10 +5598,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}], @@ -5630,7 +5610,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 -> @@ -5834,7 +5814,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], @@ -5845,7 +5825,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/filename_SUITE.erl b/lib/stdlib/test/filename_SUITE.erl index fd47da8150..4372e77df9 100644 --- a/lib/stdlib/test/filename_SUITE.erl +++ b/lib/stdlib/test/filename_SUITE.erl @@ -97,20 +97,11 @@ absname(Config) when is_list(Config) -> ?line file:set_cwd(Cwd), ok; - Type -> - case Type of - {unix, _} -> - ?line ok = file:set_cwd("/usr"), - ?line "/usr/foo" = filename:absname(foo), - ?line "/usr/foo" = filename:absname("foo"), - ?line "/usr/../ebin" = filename:absname("../ebin"); - {ose, _} -> - ?line ok = file:set_cwd("/romfs"), - ?line "/romfs/foo" = filename:absname(foo), - ?line "/romfs/foo" = filename:absname("foo"), - ?line "/romfs/../ebin" = filename:absname("../ebin") - end, - + {unix, _} -> + ?line ok = file:set_cwd("/usr"), + ?line "/usr/foo" = filename:absname(foo), + ?line "/usr/foo" = filename:absname("foo"), + ?line "/usr/../ebin" = filename:absname("../ebin"), ?line file:set_cwd("/"), ?line "/foo" = filename:absname(foo), ?line "/foo" = filename:absname("foo"), @@ -494,18 +485,10 @@ absname_bin(Config) when is_list(Config) -> ?line file:set_cwd(Cwd), ok; - Type -> - case Type of - {unix,_} -> - ?line ok = file:set_cwd(<<"/usr">>), - ?line <<"/usr/foo">> = filename:absname(<<"foo">>), - ?line <<"/usr/../ebin">> = filename:absname(<<"../ebin">>); - {ose,_} -> - ?line ok = file:set_cwd(<<"/romfs">>), - ?line <<"/romfs/foo">> = filename:absname(<<"foo">>), - ?line <<"/romfs/../ebin">> = filename:absname(<<"../ebin">>) - end, - + {unix, _} -> + ?line ok = file:set_cwd(<<"/usr">>), + ?line <<"/usr/foo">> = filename:absname(<<"foo">>), + ?line <<"/usr/../ebin">> = filename:absname(<<"../ebin">>), ?line file:set_cwd(<<"/">>), ?line <<"/foo">> = filename:absname(<<"foo">>), ?line <<"/../ebin">> = filename:absname(<<"../ebin">>), 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/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl index f02e82b39c..5f2167b609 100644 --- a/lib/stdlib/test/ms_transform_SUITE.erl +++ b/lib/stdlib/test/ms_transform_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2011. All Rights Reserved. +%% Copyright Ericsson AB 2003-2015. 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. @@ -342,8 +342,8 @@ records(doc) -> records(Config) when is_list(Config) -> ?line setup(Config), ?line RD = <<"-record(t, {" - "t1 = []," - "t2 = foo," + "t1 = [] :: list()," + "t2 = foo :: atom()," "t3," "t4" "}).">>, 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/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/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl index a9dd6b5817..3fb1a5572d 100644 --- a/lib/stdlib/test/shell_SUITE.erl +++ b/lib/stdlib/test/shell_SUITE.erl @@ -393,7 +393,9 @@ records(Config) when is_list(Config) -> Test = filename:join(?config(priv_dir, Config), "test.erl"), Contents = <<"-module(test). - -record(state, {bin, reply, leader}). + -record(state, {bin :: binary(), + reply = no, + leader = some :: atom()}). -ifdef(test1). -record(test1, {f}). 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. |