aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/src')
-rw-r--r--lib/stdlib/src/beam_lib.erl4
-rw-r--r--lib/stdlib/src/epp.erl46
-rw-r--r--lib/stdlib/src/erl_compile.erl1
-rw-r--r--lib/stdlib/src/erl_expand_records.erl5
-rw-r--r--lib/stdlib/src/erl_lint.erl8
-rw-r--r--lib/stdlib/src/erl_parse.yrl39
-rw-r--r--lib/stdlib/src/erl_pp.erl74
-rw-r--r--lib/stdlib/src/escript.erl1
-rw-r--r--lib/stdlib/src/ets.erl8
-rw-r--r--lib/stdlib/src/gen_statem.erl261
-rw-r--r--lib/stdlib/src/lib.erl2
-rw-r--r--lib/stdlib/src/ms_transform.erl7
-rw-r--r--lib/stdlib/src/otp_internal.erl4
-rw-r--r--lib/stdlib/src/proc_lib.erl14
-rw-r--r--lib/stdlib/src/proplists.erl5
-rw-r--r--lib/stdlib/src/qlc.erl7
-rw-r--r--lib/stdlib/src/qlc_pt.erl18
-rw-r--r--lib/stdlib/src/queue.erl6
-rw-r--r--lib/stdlib/src/shell.erl4
-rw-r--r--lib/stdlib/src/sofs.erl3
-rw-r--r--lib/stdlib/src/stdlib.app.src2
-rw-r--r--lib/stdlib/src/supervisor.erl33
-rw-r--r--lib/stdlib/src/zip.erl82
23 files changed, 375 insertions, 259 deletions
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index 7a17226e46..d7ee5c1f5d 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -46,7 +46,7 @@
terminate/2,code_change/3]).
-export([make_crypto_key/2, get_crypto_key/1]). %Utilities used by compiler
--export_type([attrib_entry/0, compinfo_entry/0, labeled_entry/0]).
+-export_type([attrib_entry/0, compinfo_entry/0, labeled_entry/0, label/0]).
-import(lists, [append/1, delete/2, foreach/2, keysort/2,
member/2, reverse/1, sort/1, splitwith/2]).
@@ -55,7 +55,7 @@
-type beam() :: module() | file:filename() | binary().
--type forms() :: [erl_parse:abstract_form()].
+-type forms() :: [erl_parse:abstract_form() | erl_parse:form_info()].
-type abst_code() :: {AbstVersion :: atom(), forms()} | 'no_abstract_code'.
-type dataB() :: binary().
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 73934e0e3c..40eba4ad67 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -954,11 +954,15 @@ scan_undef(_Toks, Undef, From, St) ->
%% scan_include(Tokens, IncludeToken, From, St)
-scan_include([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}], Inc,
- From, St) ->
+scan_include(Tokens0, Inc, From, St) ->
+ Tokens = coalesce_strings(Tokens0),
+ scan_include1(Tokens, Inc, From, St).
+
+scan_include1([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}], Inc,
+ From, St) ->
NewName = expand_var(NewName0),
enter_file(NewName, Inc, From, St);
-scan_include(_Toks, Inc, From, St) ->
+scan_include1(_Toks, Inc, From, St) ->
epp_reply(From, {error,{loc(Inc),epp,{bad,include}}}),
wait_req_scan(St).
@@ -977,13 +981,17 @@ expand_lib_dir(Name) ->
error
end.
-scan_include_lib([{'(',_Llp},{string,_Lf,_NewName0},{')',_Lrp},{dot,_Ld}],
- Inc, From, St)
+scan_include_lib(Tokens0, Inc, From, St) ->
+ Tokens = coalesce_strings(Tokens0),
+ scan_include_lib1(Tokens, Inc, From, St).
+
+scan_include_lib1([{'(',_Llp},{string,_Lf,_NewName0},{')',_Lrp},{dot,_Ld}],
+ Inc, From, St)
when length(St#epp.sstk) >= 8 ->
epp_reply(From, {error,{loc(Inc),epp,{depth,"include_lib"}}}),
wait_req_scan(St);
-scan_include_lib([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}],
- Inc, From, St) ->
+scan_include_lib1([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}],
+ Inc, From, St) ->
NewName = expand_var(NewName0),
Loc = start_loc(St#epp.location),
case file:path_open(St#epp.path, NewName, [read]) of
@@ -1008,7 +1016,7 @@ scan_include_lib([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}],
wait_req_scan(St)
end
end;
-scan_include_lib(_Toks, Inc, From, St) ->
+scan_include_lib1(_Toks, Inc, From, St) ->
epp_reply(From, {error,{loc(Inc),epp,{bad,include_lib}}}),
wait_req_scan(St).
@@ -1110,8 +1118,12 @@ scan_endif(_Toks, Endif, From, St) ->
%% Set the current file and line to the given file and line.
%% Note that the line of the attribute itself is kept.
-scan_file([{'(',_Llp},{string,_Ls,Name},{',',_Lc},{integer,_Li,Ln},{')',_Lrp},
- {dot,_Ld}], Tf, From, St) ->
+scan_file(Tokens0, Tf, From, St) ->
+ Tokens = coalesce_strings(Tokens0),
+ scan_file1(Tokens, Tf, From, St).
+
+scan_file1([{'(',_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),
Ms0 = St#epp.macs,
@@ -1120,7 +1132,7 @@ scan_file([{'(',_Llp},{string,_Ls,Name},{',',_Lc},{integer,_Li,Ln},{')',_Lrp},
NewLoc = new_location(Ln, St#epp.location, Locf),
Delta = get_line(element(2, Tf))-Ln + St#epp.delta,
wait_req_scan(St#epp{name2=Name,location=NewLoc,delta=Delta,macs=Ms});
-scan_file(_Toks, Tf, From, St) ->
+scan_file1(_Toks, Tf, From, St) ->
epp_reply(From, {error,{loc(Tf),epp,{bad,file}}}),
wait_req_scan(St).
@@ -1537,6 +1549,18 @@ stringify(Ts, L) ->
[$\s | S] = lists:flatten(stringify1(Ts)),
[{string, L, S}].
+coalesce_strings([{string,A,S} | Tokens]) ->
+ coalesce_strings(Tokens, A, [S]);
+coalesce_strings([T | Tokens]) ->
+ [T | coalesce_strings(Tokens)];
+coalesce_strings([]) ->
+ [].
+
+coalesce_strings([{string,_,S}|Tokens], A, S0) ->
+ coalesce_strings(Tokens, A, [S | S0]);
+coalesce_strings(Tokens, A, S) ->
+ [{string,A,lists:append(lists:reverse(S))} | coalesce_strings(Tokens)].
+
%% epp_request(Epp)
%% epp_request(Epp, Request)
%% epp_reply(From, Reply)
diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl
index ef54076ee3..a6ae398d03 100644
--- a/lib/stdlib/src/erl_compile.erl
+++ b/lib/stdlib/src/erl_compile.erl
@@ -60,6 +60,7 @@ compile_cmdline() ->
_ -> my_halt(2)
end.
+-spec my_halt(_) -> no_return().
my_halt(Reason) ->
erlang:halt(Reason).
diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl
index 9c0a7fb7d5..ebcbc54ab1 100644
--- a/lib/stdlib/src/erl_expand_records.erl
+++ b/lib/stdlib/src/erl_expand_records.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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.
@@ -37,8 +37,9 @@
checked_ra=[] % successfully accessed records
}).
--spec(module(AbsForms, CompileOptions) -> AbsForms when
+-spec(module(AbsForms, CompileOptions) -> AbsForms2 when
AbsForms :: [erl_parse:abstract_form()],
+ AbsForms2 :: [erl_parse:abstract_form()],
CompileOptions :: [compile:option()]).
%% Is is assumed that Fs is a valid list of forms. It should pass
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 2508f96b91..e9332ce069 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -99,7 +99,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
module='', %Module
behaviour=[], %Behaviour
exports=gb_sets:empty() :: gb_sets:set(fa()),%Exports
- imports=[] :: [fa()], %Imports, an orddict()
+ imports=[] :: orddict:orddict(fa(), module()),%Imports
compile=[], %Compile flags
records=dict:new() %Record definitions
:: dict:dict(atom(), {line(),Fields :: term()}),
@@ -467,7 +467,7 @@ used_vars(Exprs, BindingsList) ->
%% really all ordsets!
-spec(module(AbsForms) -> {ok, Warnings} | {error, Errors, Warnings} when
- AbsForms :: [erl_parse:abstract_form()],
+ AbsForms :: [erl_parse:abstract_form() | erl_parse:form_info()],
Warnings :: [{file:filename(),[ErrorInfo]}],
Errors :: [{FileName2 :: file:filename(),[ErrorInfo]}],
ErrorInfo :: error_info()).
@@ -479,7 +479,7 @@ module(Forms) ->
-spec(module(AbsForms, FileName) ->
{ok, Warnings} | {error, Errors, Warnings} when
- AbsForms :: [erl_parse:abstract_form()],
+ AbsForms :: [erl_parse:abstract_form() | erl_parse:form_info()],
FileName :: atom() | string(),
Warnings :: [{file:filename(),[ErrorInfo]}],
Errors :: [{FileName2 :: file:filename(),[ErrorInfo]}],
@@ -492,7 +492,7 @@ module(Forms, FileName) ->
-spec(module(AbsForms, FileName, CompileOptions) ->
{ok, Warnings} | {error, Errors, Warnings} when
- AbsForms :: [erl_parse:abstract_form()],
+ AbsForms :: [erl_parse:abstract_form() | erl_parse:form_info()],
FileName :: atom() | string(),
CompileOptions :: [compile:option()],
Warnings :: [{file:filename(),[ErrorInfo]}],
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index a896de4f1c..85b2816451 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -170,9 +170,6 @@ fun_type -> '(' top_types ')' '->' top_type
: {type, ?anno('$1'), 'fun',
[{type, ?anno('$1'), product, '$2'},'$5']}.
-map_pair_types -> '...' : [{type, ?anno('$1'), map_field_assoc,
- [{type, ?anno('$1'), any, []},
- {type, ?anno('$1'), any, []}]}].
map_pair_types -> map_pair_type : ['$1'].
map_pair_types -> map_pair_type ',' map_pair_types : ['$1'|'$3'].
@@ -534,7 +531,7 @@ Erlang code.
-compile([{hipe,[{regalloc,linear_scan}]}]).
-export_type([abstract_clause/0, abstract_expr/0, abstract_form/0,
- abstract_type/0, error_info/0]).
+ abstract_type/0, form_info/0, error_info/0]).
%% Start of Abstract Format
@@ -546,7 +543,6 @@ Erlang code.
| af_export()
| af_import()
| af_export_type()
- | af_optional_callbacks()
| af_compile()
| af_file()
| af_record_decl()
@@ -573,9 +569,6 @@ Erlang code.
-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()}}.
@@ -867,16 +860,22 @@ Erlang code.
| 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_literal() :: af_atom()
+ | af_character()
+ | af_float()
+ | af_integer()
+ | 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_character() :: {'char', anno(), char()}.
-type af_float() :: {'float', anno(), float()}.
+-type af_integer() :: {'integer', anno(), non_neg_integer()}.
+
-type af_string() :: {'string', anno(), string()}.
-type af_match(T) :: {'match', anno(), af_pattern(), T}.
@@ -944,6 +943,10 @@ Erlang code.
-type type_name() :: atom().
+-type form_info() :: {'eof', erl_anno:line()}
+ | {'error', erl_scan:error_info() | error_info()}
+ | {'warning', erl_scan:error_info() | error_info()}.
+
%% End of Abstract Format
%% XXX. To be refined.
@@ -1503,8 +1506,9 @@ type_preop_prec('#') -> {700,800}.
| abstract_type().
-spec map_anno(Fun, Abstr) -> NewAbstr when
- Fun :: fun((Anno) -> Anno),
+ Fun :: fun((Anno) -> NewAnno),
Anno :: erl_anno:anno(),
+ NewAnno :: erl_anno:anno(),
Abstr :: erl_parse_tree(),
NewAbstr :: erl_parse_tree().
@@ -1513,14 +1517,14 @@ map_anno(F0, Abstr) ->
{NewAbstr, []} = modify_anno1(Abstr, [], F),
NewAbstr.
--spec fold_anno(Fun, Acc0, Abstr) -> NewAbstr when
+-spec fold_anno(Fun, Acc0, Abstr) -> Acc1 when
Fun :: fun((Anno, AccIn) -> AccOut),
Anno :: erl_anno:anno(),
Acc0 :: term(),
+ Acc1 :: term(),
AccIn :: term(),
AccOut :: term(),
- Abstr :: erl_parse_tree(),
- NewAbstr :: erl_parse_tree().
+ Abstr :: erl_parse_tree().
fold_anno(F0, Acc0, Abstr) ->
F = fun(A, Acc) -> {A, F0(A, Acc)} end,
@@ -1528,8 +1532,9 @@ fold_anno(F0, Acc0, Abstr) ->
NewAcc.
-spec mapfold_anno(Fun, Acc0, Abstr) -> {NewAbstr, Acc1} when
- Fun :: fun((Anno, AccIn) -> {Anno, AccOut}),
+ Fun :: fun((Anno, AccIn) -> {NewAnno, AccOut}),
Anno :: erl_anno:anno(),
+ NewAnno :: erl_anno:anno(),
Acc0 :: term(),
Acc1 :: term(),
AccIn :: term(),
@@ -1545,7 +1550,9 @@ mapfold_anno(F, Acc0, Abstr) ->
Abstr :: erl_parse_tree().
new_anno(Term) ->
- map_anno(fun erl_anno:new/1, Term).
+ F = fun(L, Acc) -> {erl_anno:new(L), Acc} end,
+ {NewAbstr, []} = modify_anno1(Term, [], F),
+ NewAbstr.
-spec anno_to_term(Abstr) -> term() when
Abstr :: erl_parse_tree().
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index ca764675fc..d30cd508c1 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -70,19 +70,19 @@
%%%
-spec(form(Form) -> io_lib:chars() when
- Form :: erl_parse:abstract_form()).
+ Form :: erl_parse:abstract_form() | erl_parse:form_info()).
form(Thing) ->
form(Thing, none).
-spec(form(Form, Options) -> io_lib:chars() when
- Form :: erl_parse:abstract_form(),
+ Form :: erl_parse:abstract_form() | erl_parse:form_info(),
Options :: options()).
form(Thing, Options) ->
?TEST(Thing),
State = state(Options),
- frmt(lform(Thing, options(Options), State), State).
+ frmt(lform(Thing, options(Options)), State).
-spec(attribute(Attribute) -> io_lib:chars() when
Attribute :: erl_parse:abstract_form()).
@@ -97,7 +97,7 @@ attribute(Thing) ->
attribute(Thing, Options) ->
?TEST(Thing),
State = state(Options),
- frmt(lattribute(Thing, options(Options), State), State).
+ frmt(lattribute(Thing, options(Options)), State).
-spec(function(Function) -> io_lib:chars() when
Function :: erl_parse:abstract_form()).
@@ -217,55 +217,55 @@ encoding(Options) ->
unicode -> unicode
end.
-lform({attribute,Line,Name,Arg}, Opts, State) ->
- lattribute({attribute,Line,Name,Arg}, Opts, State);
-lform({function,Line,Name,Arity,Clauses}, Opts, _State) ->
+lform({attribute,Line,Name,Arg}, Opts) ->
+ lattribute({attribute,Line,Name,Arg}, Opts);
+lform({function,Line,Name,Arity,Clauses}, Opts) ->
lfunction({function,Line,Name,Arity,Clauses}, Opts);
%% These are specials to make it easier for the compiler.
-lform({error,E}, _Opts, _State) ->
+lform({error,E}, _Opts) ->
leaf(format("~p\n", [{error,E}]));
-lform({warning,W}, _Opts, _State) ->
+lform({warning,W}, _Opts) ->
leaf(format("~p\n", [{warning,W}]));
-lform({eof,_Line}, _Opts, _State) ->
+lform({eof,_Line}, _Opts) ->
$\n.
-lattribute({attribute,_Line,type,Type}, Opts, _State) ->
+lattribute({attribute,_Line,type,Type}, Opts) ->
[typeattr(type, Type, Opts),leaf(".\n")];
-lattribute({attribute,_Line,opaque,Type}, Opts, _State) ->
+lattribute({attribute,_Line,opaque,Type}, Opts) ->
[typeattr(opaque, Type, Opts),leaf(".\n")];
-lattribute({attribute,_Line,spec,Arg}, _Opts, _State) ->
+lattribute({attribute,_Line,spec,Arg}, _Opts) ->
[specattr(spec, Arg),leaf(".\n")];
-lattribute({attribute,_Line,callback,Arg}, _Opts, _State) ->
+lattribute({attribute,_Line,callback,Arg}, _Opts) ->
[specattr(callback, Arg),leaf(".\n")];
-lattribute({attribute,_Line,Name,Arg}, Opts, State) ->
- [lattribute(Name, Arg, Opts, State),leaf(".\n")].
+lattribute({attribute,_Line,Name,Arg}, Opts) ->
+ [lattribute(Name, Arg, Opts),leaf(".\n")].
-lattribute(module, {M,Vs}, _Opts, _State) ->
+lattribute(module, {M,Vs}, _Opts) ->
A = a0(),
attr("module",[{var,A,pname(M)},
foldr(fun(V, C) -> {cons,A,{var,A,V},C}
end, {nil,A}, Vs)]);
-lattribute(module, M, _Opts, _State) ->
+lattribute(module, M, _Opts) ->
attr("module", [{var,a0(),pname(M)}]);
-lattribute(export, Falist, _Opts, _State) ->
+lattribute(export, Falist, _Opts) ->
call({var,a0(),"-export"}, [falist(Falist)], 0, options(none));
-lattribute(import, Name, _Opts, _State) when is_list(Name) ->
+lattribute(import, Name, _Opts) when is_list(Name) ->
attr("import", [{var,a0(),pname(Name)}]);
-lattribute(import, {From,Falist}, _Opts, _State) ->
+lattribute(import, {From,Falist}, _Opts) ->
attr("import",[{var,a0(),pname(From)},falist(Falist)]);
-lattribute(export_type, Talist, _Opts, _State) ->
+lattribute(export_type, Talist, _Opts) ->
call({var,a0(),"-export_type"}, [falist(Talist)], 0, options(none));
-lattribute(optional_callbacks, Falist, Opts, _State) ->
+lattribute(optional_callbacks, Falist, Opts) ->
ArgL = try falist(Falist)
catch _:_ -> abstract(Falist, Opts)
end,
call({var,a0(),"-optional_callbacks"}, [ArgL], 0, options(none));
-lattribute(file, {Name,Line}, _Opts, State) ->
- attr("file", [{var,a0(),(State#pp.string_fun)(Name)},{integer,a0(),Line}]);
-lattribute(record, {Name,Is}, Opts, _State) ->
+lattribute(file, {Name,Line}, _Opts) ->
+ attr("file", [{string,a0(),Name},{integer,a0(),Line}]);
+lattribute(record, {Name,Is}, Opts) ->
Nl = leaf(format("-record(~w,", [Name])),
[{first,Nl,record_fields(Is, Opts)},$)];
-lattribute(Name, Arg, Options, _State) ->
+lattribute(Name, Arg, Options) ->
attr(write(Name), [abstract(Arg, Options)]).
abstract(Arg, #options{encoding = Encoding}) ->
@@ -344,27 +344,9 @@ binary_type(I1, I2) ->
map_type(Fs) ->
{first,[$#],map_pair_types(Fs)}.
-map_pair_types(Fs0) ->
- Fs = replace_any_map(Fs0),
+map_pair_types(Fs) ->
tuple_type(Fs, fun map_pair_type/2).
-replace_any_map([{type,Line,map_field_assoc,[KType,VType]}]=Fs) ->
- IsAny = fun({type,_,any,[]}) -> true;
- %% ({var,_,'_'}) -> true;
- (_) -> false
- end,
- case IsAny(KType) andalso IsAny(VType) of
- true ->
- [{type,Line,map_field_assoc,any}];
- false ->
- Fs
- end;
-replace_any_map([F|Fs]) ->
- [F|replace_any_map(Fs)];
-replace_any_map([]) -> [].
-
-map_pair_type({type,_Line,map_field_assoc,any}, _Prec) ->
- leaf("...");
map_pair_type({type,_Line,map_field_assoc,[KType,VType]}, Prec) ->
{list,[{cstep,[ltype(KType, Prec),leaf(" =>")],ltype(VType, Prec)}]};
map_pair_type({type,_Line,map_field_exact,[KType,VType]}, Prec) ->
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index b8ce311c35..f53b0e2246 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -906,6 +906,7 @@ anno(L) ->
fatal(Str) ->
throw(Str).
+-spec my_halt(_) -> no_return().
my_halt(Reason) ->
erlang:halt(Reason).
diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl
index 3f74e01692..20de06fd0b 100644
--- a/lib/stdlib/src/ets.erl
+++ b/lib/stdlib/src/ets.erl
@@ -232,20 +232,20 @@ match(_) ->
match_object(_, _) ->
erlang:nif_error(undef).
--spec match_object(Tab, Pattern, Limit) -> {[Match], Continuation} |
+-spec match_object(Tab, Pattern, Limit) -> {[Object], Continuation} |
'$end_of_table' when
Tab :: tab(),
Pattern :: match_pattern(),
Limit :: pos_integer(),
- Match :: [term()],
+ Object :: tuple(),
Continuation :: continuation().
match_object(_, _, _) ->
erlang:nif_error(undef).
--spec match_object(Continuation) -> {[Match], Continuation} |
+-spec match_object(Continuation) -> {[Object], Continuation} |
'$end_of_table' when
- Match :: [term()],
+ Object :: tuple(),
Continuation :: continuation().
match_object(_) ->
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index 23bddafeed..3b3477b282 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -24,7 +24,7 @@
[start/3,start/4,start_link/3,start_link/4,
stop/1,stop/3,
cast/2,call/2,call/3,
- enter_loop/5,enter_loop/6,enter_loop/7,
+ enter_loop/4,enter_loop/5,enter_loop/6,
reply/1,reply/2]).
%% gen callbacks
@@ -63,8 +63,8 @@
{To :: pid(), Tag :: term()}. % Reply-to specifier for call
-type state() ::
- state_name() | % For state callback function StateName/5
- term(). % For state callback function handle_event/5
+ state_name() | % For StateName/3 callback functios
+ term(). % For handle_event/4 callback function
-type state_name() :: atom().
@@ -174,28 +174,33 @@
%% an {ok, ...} tuple. Thereafter the state callbacks are called
%% for all events to this server.
-callback init(Args :: term()) ->
- {callback_mode(), state(), data()} |
- {callback_mode(), state(), data(), [action()] | action()} |
+ {ok, state(), data()} |
+ {ok, state(), data(), [action()] | action()} |
'ignore' |
{'stop', Reason :: term()}.
-%% Example state callback for callback_mode() =:= state_functions
-%% state name 'state_name'.
+%% This callback shall return the callback mode of the callback module.
%%
-%% In this mode all states has to be type state_name() i.e atom().
+%% It is called once after init/0 and code_change/4 but before
+%% the first state callback StateName/3 or handle_event/4.
+-callback callback_mode() -> callback_mode().
+
+%% Example state callback for StateName = 'state_name'
+%% when callback_mode() =:= state_functions.
+%%
+%% In this mode all states has to be of type state_name() i.e atom().
%%
-%% Note that state callbacks and only state callbacks have arity 5
-%% and that is intended.
+%% Note that the only callbacks that have arity 3 are these
+%% StateName/3 callbacks and terminate/3, so the state name
+%% 'terminate' is unusable in this mode.
-callback state_name(
event_type(),
EventContent :: term(),
Data :: data()) ->
state_function_result().
%%
-%% State callback for callback_mode() =:= handle_event_function.
-%%
-%% Note that state callbacks and only state callbacks have arity 5
-%% and that is intended.
+%% State callback for all states
+%% when callback_mode() =:= handle_event_function.
-callback handle_event(
event_type(),
EventContent :: term(),
@@ -219,9 +224,8 @@
OldState :: state(),
OldData :: data(),
Extra :: term()) ->
- {NewCallbackMode :: callback_mode(),
- NewState :: state(),
- NewData :: data()}.
+ {ok, NewState :: state(), NewData :: data()} |
+ (Reason :: term()).
%% Format the callback module state in some sensible that is
%% often condensed way. For StatusOption =:= 'normal' the perferred
@@ -239,10 +243,13 @@
[init/1, % One may use enter_loop/5,6,7 instead
format_status/2, % Has got a default implementation
%%
- state_name/3, % Example for callback_mode =:= state_functions:
- %% there has to be a StateName/5 callback function for every StateName.
+ state_name/3, % Example for callback_mode() =:= state_functions:
+ %% there has to be a StateName/3 callback function
+ %% for every StateName in your state machine but the state name
+ %% 'state_name' does of course not have to be used.
%%
- handle_event/4]). % For callback_mode =:= handle_event_function
+ handle_event/4 % For callback_mode() =:= handle_event_function
+ ]).
%% Type validation functions
callback_mode(CallbackMode) ->
@@ -450,43 +457,35 @@ reply({To,Tag}, Reply) when is_pid(To) ->
%% the same arguments as you would have returned from init/1
-spec enter_loop(
Module :: module(), Opts :: [debug_opt()],
- CallbackMode :: callback_mode(),
State :: state(), Data :: data()) ->
no_return().
-enter_loop(Module, Opts, CallbackMode, State, Data) ->
- enter_loop(Module, Opts, CallbackMode, State, Data, self()).
+enter_loop(Module, Opts, State, Data) ->
+ enter_loop(Module, Opts, State, Data, self()).
%%
-spec enter_loop(
Module :: module(), Opts :: [debug_opt()],
- CallbackMode :: callback_mode(),
State :: state(), Data :: data(),
Server_or_Actions ::
server_name() | pid() | [action()]) ->
no_return().
-enter_loop(Module, Opts, CallbackMode, State, Data, Server_or_Actions) ->
+enter_loop(Module, Opts, State, Data, Server_or_Actions) ->
if
is_list(Server_or_Actions) ->
- enter_loop(
- Module, Opts, CallbackMode, State, Data,
- self(), Server_or_Actions);
+ enter_loop(Module, Opts, State, Data, self(), Server_or_Actions);
true ->
- enter_loop(
- Module, Opts, CallbackMode, State, Data,
- Server_or_Actions, [])
+ enter_loop(Module, Opts, State, Data, Server_or_Actions, [])
end.
%%
-spec enter_loop(
Module :: module(), Opts :: [debug_opt()],
- CallbackMode :: callback_mode(),
State :: state(), Data :: data(),
Server :: server_name() | pid(),
Actions :: [action()] | action()) ->
no_return().
-enter_loop(Module, Opts, CallbackMode, State, Data, Server, Actions) ->
+enter_loop(Module, Opts, State, Data, Server, Actions) ->
is_atom(Module) orelse error({atom,Module}),
- callback_mode(CallbackMode) orelse error({callback_mode,CallbackMode}),
Parent = gen:get_parent(),
- enter(Module, Opts, CallbackMode, State, Data, Server, Actions, Parent).
+ enter(Module, Opts, State, Data, Server, Actions, Parent).
%%---------------------------------------------------------------------------
%% API helpers
@@ -514,7 +513,7 @@ send(Proc, Msg) ->
end.
%% Here the init_it/6 and enter_loop/5,6,7 functions converge
-enter(Module, Opts, CallbackMode, State, Data, Server, Actions, Parent) ->
+enter(Module, Opts, State, Data, Server, Actions, Parent) ->
%% The values should already have been type checked
Name = gen:get_proc_name(Server),
Debug = gen:debug_options(Name, Opts),
@@ -530,7 +529,7 @@ enter(Module, Opts, CallbackMode, State, Data, Server, Actions, Parent) ->
[Actions,{postpone,false}]
end,
S = #{
- callback_mode => CallbackMode,
+ callback_mode => undefined,
module => Module,
name => Name,
%% All fields below will be replaced according to the arguments to
@@ -558,9 +557,15 @@ init_it(Starter, Parent, ServerRef, Module, Args, Opts) ->
Result ->
init_result(Starter, Parent, ServerRef, Module, Result, Opts);
Class:Reason ->
+ Stacktrace = erlang:get_stacktrace(),
+ Name = gen:get_proc_name(ServerRef),
gen:unregister_name(ServerRef),
proc_lib:init_ack(Starter, {error,Reason}),
- erlang:raise(Class, Reason, erlang:get_stacktrace())
+ error_info(
+ Class, Reason, Stacktrace,
+ #{name => Name, callback_mode => undefined},
+ [], [], undefined),
+ erlang:raise(Class, Reason, Stacktrace)
end.
%%---------------------------------------------------------------------------
@@ -568,30 +573,12 @@ init_it(Starter, Parent, ServerRef, Module, Args, Opts) ->
init_result(Starter, Parent, ServerRef, Module, Result, Opts) ->
case Result of
- {CallbackMode,State,Data} ->
- case callback_mode(CallbackMode) of
- true ->
- proc_lib:init_ack(Starter, {ok,self()}),
- enter(
- Module, Opts, CallbackMode, State, Data,
- ServerRef, [], Parent);
- false ->
- Error = {callback_mode,CallbackMode},
- proc_lib:init_ack(Starter, {error,Error}),
- exit(Error)
- end;
- {CallbackMode,State,Data,Actions} ->
- case callback_mode(CallbackMode) of
- true ->
- proc_lib:init_ack(Starter, {ok,self()}),
- enter(
- Module, Opts, CallbackMode, State, Data,
- ServerRef, Actions, Parent);
- false ->
- Error = {callback_mode,CallbackMode},
- proc_lib:init_ack(Starter, {error,Error}),
- exit(Error)
- end;
+ {ok,State,Data} ->
+ proc_lib:init_ack(Starter, {ok,self()}),
+ enter(Module, Opts, State, Data, ServerRef, [], Parent);
+ {ok,State,Data,Actions} ->
+ proc_lib:init_ack(Starter, {ok,self()}),
+ enter(Module, Opts, State, Data, ServerRef, Actions, Parent);
{stop,Reason} ->
gen:unregister_name(ServerRef),
proc_lib:init_ack(Starter, {error,Reason}),
@@ -601,8 +588,14 @@ init_result(Starter, Parent, ServerRef, Module, Result, Opts) ->
proc_lib:init_ack(Starter, ignore),
exit(normal);
_ ->
- Error = {bad_return_value,Result},
+ Name = gen:get_proc_name(ServerRef),
+ gen:unregister_name(ServerRef),
+ Error = {bad_return_from_init,Result},
proc_lib:init_ack(Starter, {error,Error}),
+ error_info(
+ error, Error, ?STACKTRACE(),
+ #{name => Name, callback_mode => undefined},
+ [], [], undefined),
exit(Error)
end.
@@ -630,11 +623,9 @@ system_code_change(
Result -> Result
end
of
- {NewCallbackMode,NewState,NewData} ->
- callback_mode(NewCallbackMode) orelse
- error({callback_mode,NewCallbackMode}),
+ {ok,NewState,NewData} ->
{ok,
- S#{callback_mode := NewCallbackMode,
+ S#{callback_mode := undefined,
state := NewState,
data := NewData}};
{ok,_} = Error ->
@@ -675,14 +666,14 @@ format_status(
%% them, not as the real erlang messages. Use trace for that.
%%---------------------------------------------------------------------------
-print_event(Dev, {in,Event}, {Name,_}) ->
+print_event(Dev, {in,Event}, {Name,State}) ->
io:format(
- Dev, "*DBG* ~p received ~s~n",
- [Name,event_string(Event)]);
-print_event(Dev, {out,Reply,{To,_Tag}}, {Name,_}) ->
+ Dev, "*DBG* ~p receive ~s in state ~p~n",
+ [Name,event_string(Event),State]);
+print_event(Dev, {out,Reply,{To,_Tag}}, {Name,State}) ->
io:format(
- Dev, "*DBG* ~p sent ~p to ~p~n",
- [Name,Reply,To]);
+ Dev, "*DBG* ~p send ~p to ~p from state ~p~n",
+ [Name,Reply,To,State]);
print_event(Dev, {Tag,Event,NextState}, {Name,State}) ->
StateString =
case NextState of
@@ -874,22 +865,36 @@ loop_event(
%%
try
case CallbackMode of
+ undefined ->
+ Module:callback_mode();
state_functions ->
- Module:State(Type, Content, Data);
+ erlang:apply(Module, State, [Type,Content,Data]);
handle_event_function ->
Module:handle_event(Type, Content, State, Data)
- end of
+ end
+ of
+ Result when CallbackMode =:= undefined ->
+ loop_event_callback_mode(
+ Parent, Debug, S, Events, State, Data, P, Event, Result);
Result ->
loop_event_result(
Parent, Debug, S, Events, State, Data, P, Event, Result)
catch
+ Result when CallbackMode =:= undefined ->
+ loop_event_callback_mode(
+ Parent, Debug, S, Events, State, Data, P, Event, Result);
Result ->
loop_event_result(
Parent, Debug, S, Events, State, Data, P, Event, Result);
- error:badarg when CallbackMode =:= state_functions ->
+ error:badarg ->
case erlang:get_stacktrace() of
- [{erlang,apply,[Module,State,_],_}|Stacktrace] ->
- Args = [Type,Content,Data],
+ [{erlang,apply,
+ [Module,State,[Type,Content,Data]=Args],
+ _}
+ |Stacktrace]
+ when CallbackMode =:= state_functions ->
+ %% We get here e.g if apply fails
+ %% due to State not being an atom
terminate(
error,
{undef_state_function,{Module,State,Args}},
@@ -901,24 +906,29 @@ loop_event(
Debug, S, [Event|Events], State, Data, P)
end;
error:undef ->
- %% Process an undef to check for the simple mistake
+ %% Process undef to check for the simple mistake
%% of calling a nonexistent state function
+ %% to make the undef more precise
case erlang:get_stacktrace() of
- [{Module,State,
- [Type,Content,Data]=Args,
- _}
+ [{Module,callback_mode,[]=Args,_}
+ |Stacktrace]
+ when CallbackMode =:= undefined ->
+ terminate(
+ error,
+ {undef_callback,{Module,callback_mode,Args}},
+ Stacktrace,
+ Debug, S, [Event|Events], State, Data, P);
+ [{Module,State,[Type,Content,Data]=Args,_}
|Stacktrace]
- when CallbackMode =:= state_functions ->
+ when CallbackMode =:= state_functions ->
terminate(
error,
{undef_state_function,{Module,State,Args}},
Stacktrace,
Debug, S, [Event|Events], State, Data, P);
- [{Module,handle_event,
- [Type,Content,State,Data]=Args,
- _}
+ [{Module,handle_event,[Type,Content,State,Data]=Args,_}
|Stacktrace]
- when CallbackMode =:= handle_event_function ->
+ when CallbackMode =:= handle_event_function ->
terminate(
error,
{undef_state_function,{Module,handle_event,Args}},
@@ -936,6 +946,25 @@ loop_event(
Debug, S, [Event|Events], State, Data, P)
end.
+%% Interpret callback_mode() result
+loop_event_callback_mode(
+ Parent, Debug, S, Events, State, Data, P, Event, CallbackMode) ->
+ case callback_mode(CallbackMode) of
+ true ->
+ Hibernate = false, % We have already GC:ed recently
+ loop_event(
+ Parent, Debug,
+ S#{callback_mode := CallbackMode},
+ Events,
+ State, Data, P, Event, Hibernate);
+ false ->
+ terminate(
+ error,
+ {bad_return_from_callback_mode,CallbackMode},
+ ?STACKTRACE(),
+ Debug, S, [Event|Events], State, Data, P)
+ end.
+
%% Interpret all callback return variants
loop_event_result(
Parent, Debug, S, Events, State, Data, P, Event, Result) ->
@@ -988,7 +1017,9 @@ loop_event_result(
State, Data, P, Event, State, Actions);
_ ->
terminate(
- error, {bad_return_value,Result}, ?STACKTRACE(),
+ error,
+ {bad_return_from_state_function,Result},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, Data, P)
end.
@@ -1025,20 +1056,26 @@ loop_event_actions(
Postpone, Hibernate, Timeout, NextEvents);
false ->
terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
+ error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, NewData, P)
end;
{next_event,Type,Content} ->
case event_type(Type) of
true ->
+ NewDebug =
+ sys_debug(Debug, S, State, {in,{Type,Content}}),
loop_event_actions(
- Parent, Debug, S, Events,
+ Parent, NewDebug, S, Events,
State, NewData, P, Event, NextState, Actions,
Postpone, Hibernate, Timeout,
[{Type,Content}|NextEvents]);
false ->
terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
+ error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, NewData, P)
end;
%% Actions that set options
@@ -1049,7 +1086,9 @@ loop_event_actions(
NewPostpone, Hibernate, Timeout, NextEvents);
{postpone,_} ->
terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
+ error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, NewData, P);
postpone ->
loop_event_actions(
@@ -1063,7 +1102,9 @@ loop_event_actions(
Postpone, NewHibernate, Timeout, NextEvents);
{hibernate,_} ->
terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
+ error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, NewData, P);
hibernate ->
loop_event_actions(
@@ -1082,7 +1123,9 @@ loop_event_actions(
Postpone, Hibernate, NewTimeout, NextEvents);
{timeout,_,_} ->
terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
+ error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, NewData, P);
infinity -> % Clear timer - it will never trigger
loop_event_actions(
@@ -1097,7 +1140,9 @@ loop_event_actions(
Postpone, Hibernate, NewTimeout, NextEvents);
_ ->
terminate(
- error, {bad_action,Action}, ?STACKTRACE(),
+ error,
+ {bad_action_from_state_function,Action},
+ ?STACKTRACE(),
Debug, S, [Event|Events], State, NewData, P)
end;
%%
@@ -1169,7 +1214,9 @@ do_reply_then_terminate(
NewDebug, S, Q, State, Data, P, Rs);
_ ->
terminate(
- error, {bad_action,R}, ?STACKTRACE(),
+ error,
+ {bad_reply_action_from_state_function,R},
+ ?STACKTRACE(),
Debug, S, Q, State, Data, P)
end.
@@ -1188,8 +1235,9 @@ terminate(
C:R ->
ST = erlang:get_stacktrace(),
error_info(
- C, R, ST, Debug, S, Q, P,
+ C, R, ST, S, Q, P,
format_status(terminate, get(), S, State, Data)),
+ sys:print_log(Debug),
erlang:raise(C, R, ST)
end,
case Reason of
@@ -1198,8 +1246,9 @@ terminate(
{shutdown,_} -> ok;
_ ->
error_info(
- Class, Reason, Stacktrace, Debug, S, Q, P,
- format_status(terminate, get(), S, State, Data))
+ Class, Reason, Stacktrace, S, Q, P,
+ format_status(terminate, get(), S, State, Data)),
+ sys:print_log(Debug)
end,
case Stacktrace of
[] ->
@@ -1209,7 +1258,7 @@ terminate(
end.
error_info(
- Class, Reason, Stacktrace, Debug,
+ Class, Reason, Stacktrace,
#{name := Name, callback_mode := CallbackMode},
Q, P, FmtData) ->
{FixedReason,FixedStacktrace} =
@@ -1276,9 +1325,7 @@ error_info(
case FixedStacktrace of
[] -> [];
_ -> [FixedStacktrace]
- end),
- sys:print_log(Debug),
- ok.
+ end).
%% Call Module:format_status/2 or return a default value
@@ -1291,7 +1338,7 @@ format_status(Opt, PDict, #{module := Module}, State, Data) ->
_:_ ->
format_status_default(
Opt, State,
- "Module:format_status/2 crashed")
+ atom_to_list(Module) ++ ":format_status/2 crashed")
end;
false ->
format_status_default(Opt, State, Data)
@@ -1299,10 +1346,10 @@ format_status(Opt, PDict, #{module := Module}, State, Data) ->
%% The default Module:format_status/2
format_status_default(Opt, State, Data) ->
- SSD = {State,Data},
+ StateData = {State,Data},
case Opt of
terminate ->
- SSD;
+ StateData;
_ ->
- [{data,[{"State",SSD}]}]
+ [{data,[{"State",StateData}]}]
end.
diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/lib.erl
index 6fba63a895..56654097d9 100644
--- a/lib/stdlib/src/lib.erl
+++ b/lib/stdlib/src/lib.erl
@@ -73,7 +73,7 @@ nonl([H|T]) -> [H|nonl(T)].
send(To, Msg) -> To ! Msg.
--spec sendw(To, Msg) -> Msg when
+-spec sendw(To, Msg) -> term() when
To :: pid() | atom() | {atom(), node()},
Msg :: term().
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index 24b5fde1db..c0eea652e7 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2002-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.
@@ -224,8 +224,9 @@ transform_from_shell(Dialect, Clauses, BoundEnvironment) ->
%% Called when translating during compiling
%%
--spec parse_transform(Forms, Options) -> Forms when
- Forms :: [erl_parse:abstract_form()],
+-spec parse_transform(Forms, Options) -> Forms2 when
+ Forms :: [erl_parse:abstract_form() | erl_parse:form_info()],
+ Forms2 :: [erl_parse:abstract_form() | erl_parse:form_info()],
Options :: term().
parse_transform(Forms, _Options) ->
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 7a59523f06..3bd338071b 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -35,7 +35,7 @@
obsolete(Module, Name, Arity) ->
case obsolete_1(Module, Name, Arity) of
{deprecated=Tag,{_,_,_}=Replacement} ->
- {Tag,Replacement,"in a future release"};
+ {Tag,Replacement,"a future release"};
{_,String}=Ret when is_list(String) ->
Ret;
{_,_,_}=Ret ->
@@ -541,6 +541,8 @@ obsolete_1(random, _, _) ->
"use the 'rand' module instead"};
obsolete_1(code, rehash, 0) ->
{deprecated, "deprecated because the code path cache feature has been removed"};
+obsolete_1(queue, lait, 1) ->
+ {deprecated, {queue,liat,1}};
%% Removed in OTP 19.
diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl
index 4a19603ec2..3dc1848550 100644
--- a/lib/stdlib/src/proc_lib.erl
+++ b/lib/stdlib/src/proc_lib.erl
@@ -479,18 +479,12 @@ trans_init(gen,init_it,[gen_server,_,_,supervisor_bridge,[Module|_],_]) ->
{supervisor_bridge,Module,1};
trans_init(gen,init_it,[gen_server,_,_,_,supervisor_bridge,[Module|_],_]) ->
{supervisor_bridge,Module,1};
-trans_init(gen,init_it,[GenMod,_,_,Module,_,_])
- when GenMod =:= gen_server;
- GenMod =:= gen_statem;
- GenMod =:= gen_fsm ->
- {Module,init,1};
-trans_init(gen,init_it,[GenMod,_,_,_,Module|_])
- when GenMod =:= gen_server;
- GenMod =:= gen_statem;
- GenMod =:= gen_fsm ->
- {Module,init,1};
trans_init(gen,init_it,[gen_event|_]) ->
{gen_event,init_it,6};
+trans_init(gen,init_it,[_GenMod,_,_,Module,_,_]) when is_atom(Module) ->
+ {Module,init,1};
+trans_init(gen,init_it,[_GenMod,_,_,_,Module|_]) when is_atom(Module) ->
+ {Module,init,1};
trans_init(M, F, A) when is_atom(M), is_atom(F) ->
{M,F,length(A)}.
diff --git a/lib/stdlib/src/proplists.erl b/lib/stdlib/src/proplists.erl
index 8e99ec0ed9..5356467b19 100644
--- a/lib/stdlib/src/proplists.erl
+++ b/lib/stdlib/src/proplists.erl
@@ -438,8 +438,9 @@ substitute_aliases_1([], P) ->
%% @see normalize/2
-spec substitute_negations(Negations, ListIn) -> ListOut when
- Negations :: [{Key, Key}],
- Key :: term(),
+ Negations :: [{Key1, Key2}],
+ Key1 :: term(),
+ Key2 :: term(),
ListIn :: [term()],
ListOut :: [term()].
diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl
index b396ba7057..f3665824f2 100644
--- a/lib/stdlib/src/qlc.erl
+++ b/lib/stdlib/src/qlc.erl
@@ -734,10 +734,11 @@ table(TraverseFun, Options) when is_function(TraverseFun) ->
table(T1, T2) ->
erlang:error(badarg, [T1, T2]).
--spec(transform_from_evaluator(LC, Bs) -> Expr when
+-spec(transform_from_evaluator(LC, Bs) -> Return when
LC :: abstract_expr(),
- Expr :: abstract_expr(),
- Bs :: erl_eval:binding_struct()).
+ Bs :: erl_eval:binding_struct(),
+ Return :: {ok, abstract_expr()}
+ | {not_ok, {error, module(), Reason :: term()}}).
transform_from_evaluator(LC, Bs0) ->
qlc_pt:transform_from_evaluator(LC, Bs0).
diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl
index e4b9768b12..0db63b81f4 100644
--- a/lib/stdlib/src/qlc_pt.erl
+++ b/lib/stdlib/src/qlc_pt.erl
@@ -67,8 +67,8 @@
%%%
-spec(parse_transform(Forms, Options) -> Forms2 when
- Forms :: [erl_parse:abstract_form()],
- Forms2 :: [erl_parse:abstract_form()],
+ Forms :: [erl_parse:abstract_form() | erl_parse:form_info()],
+ Forms2 :: [erl_parse:abstract_form() | erl_parse:form_info()],
Options :: [Option],
Option :: type_checker | compile:option()).
@@ -117,19 +117,21 @@ parse_transform(Forms0, Options) ->
true = ets:delete(NodeInfo)
end.
--spec(transform_from_evaluator(LC, Bs) -> Expr when
+-spec(transform_from_evaluator(LC, Bs) -> Return when
LC :: erl_parse:abstract_expr(),
- Expr :: erl_parse:abstract_expr(),
- Bs :: erl_eval:binding_struct()).
+ Bs :: erl_eval:binding_struct(),
+ Return :: {ok, erl_parse:abstract_expr()}
+ | {not_ok, {error, module(), Reason :: term()}}).
transform_from_evaluator(LC, Bindings) ->
?DEBUG("qlc Parse Transform (Evaluator Version)~n", []),
transform_expression(LC, Bindings, false).
--spec(transform_expression(LC, Bs) -> Expr when
+-spec(transform_expression(LC, Bs) -> Return when
LC :: erl_parse:abstract_expr(),
- Expr :: erl_parse:abstract_expr(),
- Bs :: erl_eval:binding_struct()).
+ Bs :: erl_eval:binding_struct(),
+ Return :: {ok, erl_parse:abstract_expr()}
+ | {not_ok, [{error, Reason :: term()}]}).
transform_expression(LC, Bindings) ->
transform_expression(LC, Bindings, true).
diff --git a/lib/stdlib/src/queue.erl b/lib/stdlib/src/queue.erl
index d4d1904886..11c0aa8d2b 100644
--- a/lib/stdlib/src/queue.erl
+++ b/lib/stdlib/src/queue.erl
@@ -31,10 +31,14 @@
%% Okasaki API from klacke
-export([cons/2,head/1,tail/1,
- snoc/2,last/1,daeh/1,init/1,liat/1,lait/1]).
+ snoc/2,last/1,daeh/1,init/1,liat/1]).
-export_type([queue/0, queue/1]).
+%% Mis-spelled, deprecated.
+-export([lait/1]).
+-deprecated([lait/1]).
+
%%--------------------------------------------------------------------------
%% Efficient implementation of double ended fifo queues
%%
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index 82a3a2be4f..28f37ef8bf 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -768,6 +768,8 @@ used_records({call,_,{atom,_,record_info},[A,{atom,_,Name}]}) ->
{name, Name, A};
used_records({call,Line,{tuple,_,[M,F]},As}) ->
used_records({call,Line,{remote,Line,M,F},As});
+used_records({type,_,record,[{atom,_,Name}|Fs]}) ->
+ {name, Name, Fs};
used_records(T) when is_tuple(T) ->
{expr, tuple_to_list(T)};
used_records(E) ->
diff --git a/lib/stdlib/src/sofs.erl b/lib/stdlib/src/sofs.erl
index b18df2ad09..c244e06ca4 100644
--- a/lib/stdlib/src/sofs.erl
+++ b/lib/stdlib/src/sofs.erl
@@ -621,6 +621,9 @@ canonical_relation(Sets) when ?IS_SET(Sets) ->
%%% Functions on binary relations only.
%%%
+-spec(rel2fam(BinRel) -> Family when
+ Family :: family(),
+ BinRel :: binary_relation()).
rel2fam(R) ->
relation_to_family(R).
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index 32bcdc4f2a..09176d2ca0 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -106,7 +106,7 @@
dets]},
{applications, [kernel]},
{env, []},
- {runtime_dependencies, ["sasl-2.6","kernel-4.1","erts-7.3","crypto-3.3",
+ {runtime_dependencies, ["sasl-3.0","kernel-5.0","erts-8.0","crypto-3.3",
"compiler-5.0"]}
]}.
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index 38b764541a..c81e72689c 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -30,7 +30,7 @@
%% Internal exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3]).
+ terminate/2, code_change/3, format_status/2]).
-export([try_again_restart/2]).
%% For release_handler only
@@ -246,7 +246,7 @@ check_childspecs(ChildSpecs) when is_list(ChildSpecs) ->
check_childspecs(X) -> {error, {badarg, X}}.
%%%-----------------------------------------------------------------
-%%% Called by timer:apply_after from restart/2
+%%% Called by restart/2
-spec try_again_restart(SupRef, Child) -> ok when
SupRef :: sup_ref(),
Child :: child_id() | pid().
@@ -264,8 +264,13 @@ cast(Supervisor, Req) ->
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.
+ case lists:keyfind(supervisor, 1, Misc) of
+ {supervisor, [{"Callback", Mod}]} ->
+ Mod;
+ _ ->
+ [_Header, _Data, {data, [{"State", State}]} | _] = Misc,
+ State#state.module
+ end.
%%% ---------------------------------------------------
%%%
@@ -571,8 +576,8 @@ count_child(#child{pid = Pid, child_type = supervisor},
end.
-%%% If a restart attempt failed, this message is sent via
-%%% timer:apply_after(0,...) in order to give gen_server the chance to
+%%% If a restart attempt failed, this message is cast
+%%% from restart/2 in order to give gen_server the chance to
%%% check it's inbox before trying again.
-spec handle_cast({try_again_restart, child_id() | pid()}, state()) ->
{'noreply', state()} | {stop, shutdown, state()}.
@@ -790,16 +795,10 @@ restart(Child, State) ->
Id = if ?is_simple(State) -> Child#child.pid;
true -> Child#child.name
end,
- {ok, _TRef} = timer:apply_after(0,
- ?MODULE,
- try_again_restart,
- [self(),Id]),
+ ok = try_again_restart(self(), Id),
{ok,NState2};
{try_again, NState2, #child{name=ChName}} ->
- {ok, _TRef} = timer:apply_after(0,
- ?MODULE,
- try_again_restart,
- [self(),ChName]),
+ ok = try_again_restart(self(), ChName),
{ok,NState2};
Other ->
Other
@@ -1456,3 +1455,9 @@ report_progress(Child, SupName) ->
Progress = [{supervisor, SupName},
{started, extract_child(Child)}],
error_logger:info_report(progress, Progress).
+
+format_status(terminate, [_PDict, State]) ->
+ State;
+format_status(_, [_PDict, State]) ->
+ [{data, [{"State", State}]},
+ {supervisor, [{"Callback", State#state.module}]}].
diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl
index f8ba6f18e9..340cc21390 100644
--- a/lib/stdlib/src/zip.erl
+++ b/lib/stdlib/src/zip.erl
@@ -279,7 +279,8 @@ do_openzip_get(F, #openzip{files = Files, in = In0, input = Input,
case file_name_search(F, Files) of
{#zip_file{offset = Offset},_}=ZFile ->
In1 = Input({seek, bof, Offset}, In0),
- case get_z_file(In1, Z, Input, Output, [], fun silent/1, CWD, ZFile) of
+ case get_z_file(In1, Z, Input, Output, [], fun silent/1,
+ CWD, ZFile, fun all/1) of
{file, R, _In2} -> {ok, R};
_ -> throw(file_not_found)
end;
@@ -1403,9 +1404,10 @@ get_z_files([{#zip_file{offset = Offset},_} = ZFile | Rest], Z, In0,
true ->
In1 = Input({seek, bof, Offset}, In0),
{In2, Acc1} =
- case get_z_file(In1, Z, Input, Output, OpO, FB, CWD, ZFile) of
+ case get_z_file(In1, Z, Input, Output, OpO, FB,
+ CWD, ZFile, Filter) of
{file, GZD, Inx} -> {Inx, [GZD | Acc0]};
- {dir, Inx} -> {Inx, Acc0}
+ {_, Inx} -> {Inx, Acc0}
end,
get_z_files(Rest, Z, In2, Opts, Acc1);
_ ->
@@ -1413,7 +1415,8 @@ get_z_files([{#zip_file{offset = Offset},_} = ZFile | Rest], Z, In0,
end.
%% get a file from the archive, reading chunks
-get_z_file(In0, Z, Input, Output, OpO, FB, CWD, {ZipFile,Extra}) ->
+get_z_file(In0, Z, Input, Output, OpO, FB,
+ CWD, {ZipFile,Extra}, Filter) ->
case Input({read, ?LOCAL_FILE_HEADER_SZ}, In0) of
{eof, In1} ->
{eof, In1};
@@ -1433,29 +1436,64 @@ get_z_file(In0, Z, Input, Output, OpO, FB, CWD, {ZipFile,Extra}) ->
end,
{BFileN, In3} = Input({read, FileNameLen + ExtraLen}, In1),
{FileName, _} = get_file_name_extra(FileNameLen, ExtraLen, BFileN),
- FileName1 = add_cwd(CWD, FileName),
- case lists:last(FileName) of
- $/ ->
- %% perhaps this should always be done?
- Output({ensure_dir,FileName1},[]),
- {dir, In3};
- _ ->
- %% FileInfo = local_file_header_to_file_info(LH)
- %%{Out, In4, CRC, UncompSize} =
- {Out, In4, CRC, _UncompSize} =
- get_z_data(CompMethod, In3, FileName1,
- CompSize, Input, Output, OpO, Z),
- In5 = skip_z_data_descriptor(GPFlag, Input, In4),
- %% TODO This should be fixed some day:
- %% In5 = Input({set_file_info, FileName, FileInfo#file_info{size=UncompSize}}, In4),
- FB(FileName),
- CRC =:= CRC32 orelse throw({bad_crc, FileName}),
- {file, Out, In5}
+ ReadAndWrite =
+ case check_valid_location(CWD, FileName) of
+ {true,FileName1} ->
+ true;
+ {false,FileName1} ->
+ Filter({ZipFile#zip_file{name = FileName1},Extra})
+ end,
+ case ReadAndWrite of
+ true ->
+ case lists:last(FileName) of
+ $/ ->
+ %% perhaps this should always be done?
+ Output({ensure_dir,FileName1},[]),
+ {dir, In3};
+ _ ->
+ %% FileInfo = local_file_header_to_file_info(LH)
+ %%{Out, In4, CRC, UncompSize} =
+ {Out, In4, CRC, _UncompSize} =
+ get_z_data(CompMethod, In3, FileName1,
+ CompSize, Input, Output, OpO, Z),
+ In5 = skip_z_data_descriptor(GPFlag, Input, In4),
+ %% TODO This should be fixed some day:
+ %% In5 = Input({set_file_info, FileName,
+ %% FileInfo#file_info{size=UncompSize}}, In4),
+ FB(FileName),
+ CRC =:= CRC32 orelse throw({bad_crc, FileName}),
+ {file, Out, In5}
+ end;
+ false ->
+ {ignore, In3}
end;
_ ->
throw(bad_local_file_header)
end.
+%% make sure FileName doesn't have relative path that points over CWD
+check_valid_location(CWD, FileName) ->
+ %% check for directory traversal exploit
+ case check_dir_level(filename:split(FileName), 0) of
+ {FileOrDir,Level} when Level < 0 ->
+ CWD1 = if CWD == "" -> "./";
+ true -> CWD
+ end,
+ error_logger:format("Illegal path: ~ts, extracting in ~ts~n",
+ [add_cwd(CWD,FileName),CWD1]),
+ {false,add_cwd(CWD, FileOrDir)};
+ _ ->
+ {true,add_cwd(CWD, FileName)}
+ end.
+
+check_dir_level([FileOrDir], Level) ->
+ {FileOrDir,Level};
+check_dir_level(["." | Parts], Level) ->
+ check_dir_level(Parts, Level);
+check_dir_level([".." | Parts], Level) ->
+ check_dir_level(Parts, Level-1);
+check_dir_level([_Dir | Parts], Level) ->
+ check_dir_level(Parts, Level+1).
get_file_name_extra(FileNameLen, ExtraLen, B) ->
case B of