diff options
Diffstat (limited to 'lib/stdlib/src')
| -rw-r--r-- | lib/stdlib/src/dets_utils.erl | 4 | ||||
| -rw-r--r-- | lib/stdlib/src/dets_v8.erl | 4 | ||||
| -rw-r--r-- | lib/stdlib/src/dets_v9.erl | 4 | ||||
| -rw-r--r-- | lib/stdlib/src/dict.erl | 4 | ||||
| -rw-r--r-- | lib/stdlib/src/digraph.erl | 6 | ||||
| -rw-r--r-- | lib/stdlib/src/epp.erl | 167 | ||||
| -rw-r--r-- | lib/stdlib/src/erl_expand_records.erl | 36 | ||||
| -rw-r--r-- | lib/stdlib/src/erl_lint.erl | 32 | ||||
| -rw-r--r-- | lib/stdlib/src/file_sorter.erl | 4 | ||||
| -rw-r--r-- | lib/stdlib/src/lists.erl | 4 | ||||
| -rw-r--r-- | lib/stdlib/src/ms_transform.erl | 13 | ||||
| -rw-r--r-- | lib/stdlib/src/otp_internal.erl | 14 | ||||
| -rw-r--r-- | lib/stdlib/src/qlc.erl | 4 | ||||
| -rw-r--r-- | lib/stdlib/src/qlc_pt.erl | 6 | ||||
| -rw-r--r-- | lib/stdlib/src/rand.erl | 6 | ||||
| -rw-r--r-- | lib/stdlib/src/shell.erl | 8 | ||||
| -rw-r--r-- | lib/stdlib/src/supervisor.erl | 63 | ||||
| -rw-r--r-- | lib/stdlib/src/unicode.erl | 4 | ||||
| -rw-r--r-- | lib/stdlib/src/zip.erl | 4 | 
19 files changed, 257 insertions, 130 deletions
| diff --git a/lib/stdlib/src/dets_utils.erl b/lib/stdlib/src/dets_utils.erl index 196158cd48..34a8ddddaa 100644 --- a/lib/stdlib/src/dets_utils.erl +++ b/lib/stdlib/src/dets_utils.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %%  -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-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. @@ -747,6 +747,8 @@ all_allocated([{X,Y} | L], _X0, Y0, A) when Y0 < X ->  all_allocated_as_list(Head) ->      all_allocated_as_list(all(get_freelists(Head)), 0, Head#head.base, []). +-dialyzer({no_improper_lists, all_allocated_as_list/4}). +  all_allocated_as_list([], _X0, _Y0, []) ->      [];  all_allocated_as_list([], _X0, _Y0, A) -> diff --git a/lib/stdlib/src/dets_v8.erl b/lib/stdlib/src/dets_v8.erl index 49126193b8..1bf53d91b1 100644 --- a/lib/stdlib/src/dets_v8.erl +++ b/lib/stdlib/src/dets_v8.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-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. @@ -36,6 +36,8 @@  %% For backward compatibility.  -export([sz2pos/1]). +-dialyzer(no_improper_lists). +  -compile({inline, [{sz2pos,1},{scan_skip,7}]}).  -compile({inline, [{skip_bytes,5}, {get_segp,1}]}).  -compile({inline, [{wl_lookup,5}]}). diff --git a/lib/stdlib/src/dets_v9.erl b/lib/stdlib/src/dets_v9.erl index 361780c776..6c406fc03a 100644 --- a/lib/stdlib/src/dets_v9.erl +++ b/lib/stdlib/src/dets_v9.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %%  -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-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. @@ -34,6 +34,8 @@  -export([cache_segps/3]). +-dialyzer(no_improper_lists). +  -compile({inline, [{max_objsize,1},{maxobjsize,1}]}).  -compile({inline, [{write_segment_file,6}]}).   -compile({inline, [{sz2pos,1},{adjsz,1}]}). diff --git a/lib/stdlib/src/dict.erl b/lib/stdlib/src/dict.erl index 6ce3710f87..f921e28ef6 100644 --- a/lib/stdlib/src/dict.erl +++ b/lib/stdlib/src/dict.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %%  -%% Copyright Ericsson AB 2000-2014. All Rights Reserved. +%% Copyright Ericsson AB 2000-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. @@ -333,6 +333,8 @@ update_counter(Key, Incr, D0) when is_number(Incr) ->  			D0, Slot),      maybe_expand(D1, Ic). +-dialyzer({no_improper_lists, counter_bkt/3}). +  counter_bkt(Key, I, [?kv(Key,Val)|Bkt]) ->      {[?kv(Key,Val+I)|Bkt],0};  counter_bkt(Key, I, [Other|Bkt0]) -> diff --git a/lib/stdlib/src/digraph.erl b/lib/stdlib/src/digraph.erl index e51e560542..8a4df95027 100644 --- a/lib/stdlib/src/digraph.erl +++ b/lib/stdlib/src/digraph.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. @@ -338,6 +338,8 @@ edge(G, E) ->  %%  -spec new_edge_id(graph()) -> edge(). +-dialyzer({no_improper_lists, new_edge_id/1}). +  new_edge_id(G) ->      NT = G#digraph.ntab,      [{'$eid', K}] = ets:lookup(NT, '$eid'), @@ -350,6 +352,8 @@ new_edge_id(G) ->  %%  -spec new_vertex_id(graph()) -> vertex(). +-dialyzer({no_improper_lists, new_vertex_id/1}). +  new_vertex_id(G) ->      NT = G#digraph.ntab,      [{'$vid', K}] = ets:lookup(NT, '$vid'), diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl index 45f616bb02..936c095aef 100644 --- a/lib/stdlib/src/epp.erl +++ b/lib/stdlib/src/epp.erl @@ -46,6 +46,10 @@  -type tokens() :: [erl_scan:token()].  -type used() :: {name(), argspec()}. +-type function_name_type() :: 'undefined' +			    | {atom(),non_neg_integer()} +			    | tokens(). +  -define(DEFAULT_ENCODING, utf8).  %% Epp state record. @@ -63,7 +67,8 @@                uses = #{}			%Macro use structure  	            :: #{name() => [{argspec(), [used()]}]},                default_encoding = ?DEFAULT_ENCODING :: source_encoding(), -	      pre_opened = false :: boolean() +	      pre_opened = false :: boolean(), +	      fname = [] :: function_name_type()  	     }).  %% open(Options) @@ -205,6 +210,10 @@ format_error({include,W,F}) ->      io_lib:format("can't find include ~s \"~s\"", [W,F]);  format_error({illegal,How,What}) ->      io_lib:format("~s '-~s'", [How,What]); +format_error({illegal_function,Macro}) -> +    io_lib:format("?~s can only be used within a function", [Macro]); +format_error({illegal_function_usage,Macro}) -> +    io_lib:format("?~s must not begin a form", [Macro]);  format_error({'NYI',What}) ->      io_lib:format("not yet implemented '~s'", [What]);  format_error(E) -> file:format_error(E). @@ -258,20 +267,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} -> @@ -558,6 +554,8 @@ predef_macros(File) ->      Machine = list_to_atom(erlang:system_info(machine)),      Anno = line1(),      Defs = [{'FILE', 	           {none,[{string,Anno,File}]}}, +	    {'FUNCTION_NAME',      undefined}, +	    {'FUNCTION_ARITY',     undefined},  	    {'LINE',		   {none,[{integer,Anno,1}]}},  	    {'MODULE',	           undefined},  	    {'MODULE_STRING',      undefined}, @@ -768,7 +766,7 @@ scan_toks([{'-',_Lh},{atom,_Le,elif}=Elif|Toks], From, St) ->  scan_toks([{'-',_Lh},{atom,_Le,endif}=Endif|Toks], From, St) ->      scan_endif(Toks, Endif, From, St);  scan_toks([{'-',_Lh},{atom,_Lf,file}=FileToken|Toks0], From, St) -> -    case catch expand_macros(Toks0, {St#epp.macs, St#epp.uses}) of +    case catch expand_macros(Toks0, St) of  	Toks1 when is_list(Toks1) ->              scan_file(Toks1, FileToken, From, St);  	{error,ErrL,What} -> @@ -776,7 +774,7 @@ scan_toks([{'-',_Lh},{atom,_Lf,file}=FileToken|Toks0], From, St) ->  	    wait_req_scan(St)      end;  scan_toks(Toks0, From, St) -> -    case catch expand_macros(Toks0, {St#epp.macs, St#epp.uses}) of +    case catch expand_macros(Toks0, St#epp{fname=Toks0}) of  	Toks1 when is_list(Toks1) ->  	    epp_reply(From, {ok,Toks1}),  	    wait_req_scan(St#epp{macs=scan_module(Toks1, St#epp.macs)}); @@ -1158,24 +1156,24 @@ macro_expansion([T|Ts], _Anno0) ->      [T|macro_expansion(Ts, T)];  macro_expansion([], Anno0) -> throw({error,loc(Anno0),premature_end}). -%% expand_macros(Tokens, Macros) +%% expand_macros(Tokens, St)  %% expand_macro(Tokens, MacroToken, RestTokens)  %%  Expand the macros in a list of tokens, making sure that an expansion  %%  gets the same location as the macro call. -expand_macros(MacT, M, Toks, Ms0) -> -    {Ms,U} = Ms0, +expand_macros(MacT, M, Toks, St) -> +    #epp{macs=Ms,uses=U} = St,      Lm = loc(MacT),      Tinfo = element(2, MacT),      case expand_macro1(Lm, M, Toks, Ms) of  	{ok,{none,Exp}} ->  	    check_uses([{M,none}], [], U, Lm), -	    Toks1 = expand_macros(expand_macro(Exp, Tinfo, [], #{}), Ms0), -	    expand_macros(Toks1++Toks, Ms0); +	    Toks1 = expand_macros(expand_macro(Exp, Tinfo, [], #{}), St), +	    expand_macros(Toks1++Toks, St);  	{ok,{As,Exp}} ->  	    check_uses([{M,length(As)}], [], U, Lm),  	    {Bs,Toks1} = bind_args(Toks, Lm, M, As, #{}), -	    expand_macros(expand_macro(Exp, Tinfo, Toks1, Bs), Ms0) +	    expand_macros(expand_macro(Exp, Tinfo, Toks1, Bs), St)      end.  expand_macro1(Lm, M, Toks, Ms) -> @@ -1224,16 +1222,32 @@ get_macro_uses({M,Arity}, U) ->  %% 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(MacT, M, Toks, Ms); +expand_macros([{'?',_Lq},{atom,_Lm,M}=MacT|Toks], St) -> +    expand_macros(MacT, M, Toks, St);  %% Special macros -expand_macros([{'?',_Lq},{var,Lm,'LINE'}=Tok|Toks], Ms) -> +expand_macros([{'?',_Lq},{var,Lm,'FUNCTION_NAME'}=Token|Toks], St0) -> +    St = update_fun_name(Token, St0), +    case St#epp.fname of +	undefined -> +	    [{'?',_Lq},Token]; +	{Name,_} -> +	    [{atom,Lm,Name}] +    end ++ expand_macros(Toks, St); +expand_macros([{'?',_Lq},{var,Lm,'FUNCTION_ARITY'}=Token|Toks], St0) -> +    St = update_fun_name(Token, St0), +    case St#epp.fname of +	undefined -> +	    [{'?',_Lq},Token]; +	{_,Arity} -> +	    [{integer,Lm,Arity}] +    end ++ expand_macros(Toks, St); +expand_macros([{'?',_Lq},{var,Lm,'LINE'}=Tok|Toks], St) ->      Line = erl_scan:line(Tok), -    [{integer,Lm,Line}|expand_macros(Toks, Ms)]; -expand_macros([{'?',_Lq},{var,_Lm,M}=MacT|Toks], Ms) -> -    expand_macros(MacT, M, Toks, Ms); +    [{integer,Lm,Line}|expand_macros(Toks, St)]; +expand_macros([{'?',_Lq},{var,_Lm,M}=MacT|Toks], St) -> +    expand_macros(MacT, M, Toks, St);  %% Illegal macros -expand_macros([{'?',_Lq},Token|_Toks], _Ms) -> +expand_macros([{'?',_Lq},Token|_Toks], _St) ->      T = case erl_scan:text(Token) of              Text when is_list(Text) ->                  Text; @@ -1242,9 +1256,9 @@ expand_macros([{'?',_Lq},Token|_Toks], _Ms) ->                  io_lib:write(Symbol)          end,      throw({error,loc(Token),{call,[$?|T]}}); -expand_macros([T|Ts], Ms) -> -    [T|expand_macros(Ts, Ms)]; -expand_macros([], _Ms) -> []. +expand_macros([T|Ts], St) -> +    [T|expand_macros(Ts, St)]; +expand_macros([], _St) -> [].  %% bind_args(Tokens, MacroLocation, MacroName, ArgumentVars, Bindings)  %%  Collect the arguments to a macro call. @@ -1367,6 +1381,93 @@ expand_arg([A|As], Ts, _L, Rest, Bs) ->  expand_arg([], Ts, L, Rest, Bs) ->      expand_macro(Ts, L, Rest, Bs). +%%% +%%% Here follows support for the ?FUNCTION_NAME and ?FUNCTION_ARITY +%%% macros. Since the parser has not been run yet, we don't know the +%%% name and arity of the current function. Therefore, we will need to +%%% scan the beginning of the current form to extract the name and +%%% arity of the function. +%%% + +update_fun_name(Token, #epp{fname=Toks0}=St) when is_list(Toks0) -> +    %% ?FUNCTION_NAME or ?FUNCTION_ARITY is used for the first time in +    %% a function.  First expand macros (except ?FUNCTION_NAME and +    %% ?FUNCTION_ARITY) in the form. + +    Toks1 = (catch expand_macros(Toks0, St#epp{fname=undefined})), + +    %% Now extract the name and arity from the stream of tokens, and store +    %% the result in the #epp{} record so we don't have to do it +    %% again. + +    case Toks1 of +	[{atom,_,Name},{'(',_}|Toks] -> +	    %% This is the beginning of a function definition. +	    %% Scan the token stream up to the matching right +	    %% parenthesis and count the number of arguments. +	    FA = update_fun_name_1(Toks, 1, {Name,0}, St), +	    St#epp{fname=FA}; +	[{'?',_}|_] -> +	    %% ?FUNCTION_NAME/?FUNCTION_ARITY used at the beginning +	    %% of a form. Does not make sense. +	    {var,_,Macro} = Token, +	    throw({error,loc(Token),{illegal_function_usage,Macro}}); +	_ when is_list(Toks1) -> +	    %% Not the beginning of a function (an attribute or a +	    %% syntax error). +	    {var,_,Macro} = Token, +	    throw({error,loc(Token),{illegal_function,Macro}}); +	_ -> +	    %% A macro expansion error. Return a dummy value and +	    %% let the caller notice and handle the error. +	    St#epp{fname={'_',0}} +    end; +update_fun_name(_Token, St) -> +    St. + +update_fun_name_1([Tok|Toks], L, FA, St) -> +    case classify_token(Tok) of +	comma -> +	    if +		L =:= 1 -> +		    {Name,Arity} = FA, +		    update_fun_name_1(Toks, L, {Name,Arity+1}, St); +		true -> +		    update_fun_name_1(Toks, L, FA, St) +	    end; +	left -> +	    update_fun_name_1(Toks, L+1, FA, St); +	right when L =:= 1 -> +	    FA; +	right -> +	    update_fun_name_1(Toks, L-1, FA, St); +	other -> +	    case FA of +		{Name,0} -> +		    update_fun_name_1(Toks, L, {Name,1}, St); +		{_,_} -> +		    update_fun_name_1(Toks, L, FA, St) +	    end +    end; +update_fun_name_1([], _, FA, _) -> +    %% Syntax error, but never mind. +    FA. + +classify_token({C,_}) -> classify_token_1(C); +classify_token(_) -> other. + +classify_token_1(',') -> comma; +classify_token_1('(') -> left; +classify_token_1('{') -> left; +classify_token_1('[') -> left; +classify_token_1('<<') -> left; +classify_token_1(')') -> right; +classify_token_1('}') -> right; +classify_token_1(']') -> right; +classify_token_1('>>') -> right; +classify_token_1(_) -> other. + +  %%% stringify(Ts, L) returns a list of one token: a string which when  %%% tokenized would yield the token list Ts. 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 9ef4acdf5f..4ca9a609a8 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -360,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}}) -> @@ -1143,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)], @@ -1153,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. @@ -2443,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}. @@ -2646,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), @@ -2813,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}; @@ -2994,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) @@ -3009,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 @@ -3531,6 +3538,8 @@ check_qlc_hrl(Line, M, F, As, St) ->  %% deprecated_function(Line, ModName, FuncName, [Arg], State) -> State.  %%  Add warning for calls to deprecated functions. +-dialyzer({no_match, deprecated_function/5}). +  deprecated_function(Line, M, F, As, St) ->      Arity = length(As),      MFA = {M, F, Arity}, @@ -3560,6 +3569,7 @@ deprecated_function(Line, M, F, As, St) ->      end.  -dialyzer({no_match, deprecated_type/5}). +  deprecated_type(L, M, N, As, St) ->      NAs = length(As),      case otp_internal:obsolete_type(M, N, NAs) of diff --git a/lib/stdlib/src/file_sorter.erl b/lib/stdlib/src/file_sorter.erl index aed857aa77..3aeaff8dc4 100644 --- a/lib/stdlib/src/file_sorter.erl +++ b/lib/stdlib/src/file_sorter.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-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. @@ -28,6 +28,8 @@           check/1, check/2,            keycheck/2, keycheck/3]). +-dialyzer(no_improper_lists). +  -include_lib("kernel/include/file.hrl").  -define(CHUNKSIZE, 16384). diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl index 62b6ca8a21..2b4472cdf7 100644 --- a/lib/stdlib/src/lists.erl +++ b/lib/stdlib/src/lists.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 1996-2013. 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. @@ -2267,6 +2267,8 @@ ukeysplit_2(I, Y, EY, [Z | L], R) ->  ukeysplit_2(_I, Y, _EY, [], R) ->      [Y | R]. +-dialyzer({no_improper_lists, ukeymergel/3}). +  ukeymergel(I, [T1, [H2 | T2], [H3 | T3] | L], Acc) ->      %% The fourth argument, [H2 | H3] (=HdM), may confuse type      %% checkers. Its purpose is to ensure that the tests H2 == HdM 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 bc70c296da..0dc2626ae8 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 1999-2015. All Rights Reserved. +%% Copyright Ericsson AB 1999-2016. All Rights Reserved.  %%  %% Licensed under the Apache License, Version 2.0 (the "License");  %% you may not use this file except in compliance with the License. @@ -23,6 +23,8 @@  %%---------------------------------------------------------------------- +-dialyzer({no_match, obsolete/3}). +  -type tag()     :: 'deprecated' | 'removed'. %% | 'experimental'.  -type mfas()    :: mfa() | {atom(), atom(), [byte()]}.  -type release() :: string(). @@ -697,18 +699,20 @@ is_snmp_agent_function(del_agent_caps,        1) -> true;  is_snmp_agent_function(get_agent_caps,        0) -> true;  is_snmp_agent_function(_,		      _) -> false. +-dialyzer({no_match, obsolete_type/3}). +  -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} -> -	    {Tag,Replacement,"in a future release"}; +        {deprecated=Tag,{_,_,_}=Replacement} -> +            {Tag,Replacement,"in a future release"};  	{_,String}=Ret when is_list(String) ->  	    Ret; -	{_,_,_}=Ret -> -	    Ret; +        {_,_,_}=Ret -> +            Ret;  	no ->  	    no      end. diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl index 24e64efee7..b396ba7057 100644 --- a/lib/stdlib/src/qlc.erl +++ b/lib/stdlib/src/qlc.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. @@ -51,6 +51,8 @@  -export([template_state/0, aux_name/3, name_suffix/2, vars/1,           var_ufold/2, var_fold/3, all_selections/1]). +-dialyzer(no_improper_lists). +  %% When cache=list lists bigger than ?MAX_LIST_SIZE bytes are put on  %% file. Also used when merge join finds big equivalence classes.  -define(MAX_LIST_SIZE, 512*1024). diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl index 9f69cd5003..e4b9768b12 100644 --- a/lib/stdlib/src/qlc_pt.erl +++ b/lib/stdlib/src/qlc_pt.erl @@ -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. diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl index dc060e82d9..d455abf7b0 100644 --- a/lib/stdlib/src/rand.erl +++ b/lib/stdlib/src/rand.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 2015. All Rights Reserved. +%% Copyright Ericsson AB 2015-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. @@ -256,6 +256,8 @@ exs64_uniform(Max, {Alg, R}) ->  %% =====================================================================  -type exsplus_state() :: nonempty_improper_list(uint58(), uint58()). +-dialyzer({no_improper_lists, exsplus_seed/1}). +  exsplus_seed({A1, A2, A3}) ->      {_, R1} = exsplus_next([(((A1 * 4294967197) + 1) band ?UINT58MASK)|  			    (((A2 * 4294967231) + 1) band ?UINT58MASK)]), @@ -263,6 +265,8 @@ exsplus_seed({A1, A2, A3}) ->  			    tl(R1)]),      R2. +-dialyzer({no_improper_lists, exsplus_next/1}). +  %% Advance xorshift116+ state for one step and generate 58bit unsigned integer  -spec exsplus_next(exsplus_state()) -> {uint58(), exsplus_state()}.  exsplus_next([S1|S0]) -> 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/supervisor.erl b/lib/stdlib/src/supervisor.erl index 23f3aaee1f..0400c845ab 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -33,6 +33,9 @@  	 terminate/2, code_change/3]).  -export([try_again_restart/2]). +%% For release_handler only +-export([get_callback_module/1]). +  %%--------------------------------------------------------------------------  -export_type([sup_flags/0, child_spec/0, startchild_ret/0, strategy/0]). @@ -115,6 +118,7 @@  		intensity              :: non_neg_integer() | 'undefined',  		period                 :: pos_integer() | 'undefined',  		restarts = [], +		dynamic_restarts = 0   :: non_neg_integer(),  	        module,  	        args}).  -type state() :: #state{}. @@ -252,6 +256,17 @@ try_again_restart(Supervisor, Child) ->  cast(Supervisor, Req) ->      gen_server:cast(Supervisor, Req). +%%%----------------------------------------------------------------- +%%% Called by release_handler during upgrade +-spec get_callback_module(Pid) -> Module when +      Pid :: pid(), +      Module :: atom(). +get_callback_module(Pid) -> +    {status, _Pid, {module, _Mod}, +     [_PDict, _SysState, _Parent, _Dbg, Misc]} = sys:get_status(Pid), +    [_Header, _Data, {data, [{"State", State}]}] = Misc, +    State#state.module. +  %%% ---------------------------------------------------  %%%   %%% Initialize the supervisor. @@ -506,39 +521,26 @@ handle_call(which_children, _From, State) ->  handle_call(count_children, _From, #state{children = [#child{restart_type = temporary,  							     child_type = CT}]} = State)    when ?is_simple(State) -> -    {Active, Count} = -	?SETS:fold(fun(Pid, {Alive, Tot}) -> -			   case is_pid(Pid) andalso is_process_alive(Pid) of -			       true ->{Alive+1, Tot +1}; -			       false -> -				   {Alive, Tot + 1} -			   end -		   end, {0, 0}, dynamics_db(temporary, State#state.dynamics)), +    Sz = ?SETS:size(dynamics_db(temporary, State#state.dynamics)),      Reply = case CT of -		supervisor -> [{specs, 1}, {active, Active}, -			       {supervisors, Count}, {workers, 0}]; -		worker -> [{specs, 1}, {active, Active}, -			   {supervisors, 0}, {workers, Count}] +		supervisor -> [{specs, 1}, {active, Sz}, +			       {supervisors, Sz}, {workers, 0}]; +		worker -> [{specs, 1}, {active, Sz}, +			   {supervisors, 0}, {workers, Sz}]  	    end,      {reply, Reply, State}; -handle_call(count_children, _From,  #state{children = [#child{restart_type = RType, +handle_call(count_children, _From,  #state{dynamic_restarts = Restarts, +					   children = [#child{restart_type = RType,  							      child_type = CT}]} = State)    when ?is_simple(State) -> -    {Active, Count} = -	?DICTS:fold(fun(Pid, _Val, {Alive, Tot}) -> -			   case is_pid(Pid) andalso is_process_alive(Pid) of -			       true -> -				   {Alive+1, Tot +1}; -			       false -> -				   {Alive, Tot + 1} -			   end -		   end, {0, 0}, dynamics_db(RType, State#state.dynamics)), +    Sz = ?DICTS:size(dynamics_db(RType, State#state.dynamics)), +    Active = Sz - Restarts,      Reply = case CT of  		supervisor -> [{specs, 1}, {active, Active}, -			       {supervisors, Count}, {workers, 0}]; +			       {supervisors, Sz}, {workers, 0}];  		worker -> [{specs, 1}, {active, Active}, -			   {supervisors, 0}, {workers, Count}] +			   {supervisors, 0}, {workers, Sz}]  	    end,      {reply, Reply, State}; @@ -808,8 +810,15 @@ restart(Child, State) ->  	    {shutdown, remove_child(Child, NState)}      end. -restart(simple_one_for_one, Child, State) -> +restart(simple_one_for_one, Child, State0) ->      #child{pid = OldPid, mfargs = {M, F, A}} = Child, +    State = case OldPid of +		?restarting(_) -> +		    NRes = State0#state.dynamic_restarts - 1, +		    State0#state{dynamic_restarts = NRes}; +		_ -> +		    State0 +	    end,      Dynamics = ?DICTS:erase(OldPid, dynamics_db(Child#child.restart_type,  					       State#state.dynamics)),      case do_start_child_i(M, F, A) of @@ -822,8 +831,10 @@ restart(simple_one_for_one, Child, State) ->  	    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{dynamics = DynamicsDb}, +	    NState = State#state{dynamic_restarts = NRestarts, +				 dynamics = DynamicsDb},  	    report_error(start_error, Error, Child, State#state.name),  	    {try_again, NState}      end; diff --git a/lib/stdlib/src/unicode.erl b/lib/stdlib/src/unicode.erl index 3e8e6f5101..617da11ba8 100644 --- a/lib/stdlib/src/unicode.erl +++ b/lib/stdlib/src/unicode.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %%  -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-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. @@ -561,6 +561,8 @@ do_o_binary(F,L) ->  	    erlang:iolist_to_binary(List)      end. +-dialyzer({no_improper_lists, do_o_binary2/2}). +  do_o_binary2(_F,[]) ->      <<>>;  do_o_binary2(F,[H|T]) -> diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl index bec0bd3f6d..f8ba6f18e9 100644 --- a/lib/stdlib/src/zip.erl +++ b/lib/stdlib/src/zip.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 2006-2013. All Rights Reserved. +%% Copyright Ericsson AB 2006-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. @@ -1566,6 +1566,8 @@ append_bins([_|_]=List, B) ->  append_bins([], B) ->      B. +-dialyzer({no_improper_lists, pwrite_iolist/3}). +  pwrite_iolist(B, Pos, Bin) ->      {Left, Right} = split_binary(B, Pos),      Sz = erlang:iolist_size(Bin), | 
