diff options
Diffstat (limited to 'lib/stdlib')
-rw-r--r-- | lib/stdlib/doc/src/ets.xml | 22 | ||||
-rw-r--r-- | lib/stdlib/src/dets_v8.erl | 2 | ||||
-rw-r--r-- | lib/stdlib/src/dets_v9.erl | 5 | ||||
-rw-r--r-- | lib/stdlib/src/epp.erl | 43 | ||||
-rw-r--r-- | lib/stdlib/src/erl_lint.erl | 14 | ||||
-rw-r--r-- | lib/stdlib/src/lists.erl | 64 | ||||
-rw-r--r-- | lib/stdlib/src/ordsets.erl | 16 | ||||
-rw-r--r-- | lib/stdlib/src/string.erl | 2 | ||||
-rw-r--r-- | lib/stdlib/test/dets_SUITE.erl | 39 | ||||
-rw-r--r-- | lib/stdlib/test/epp_SUITE.erl | 38 | ||||
-rw-r--r-- | lib/stdlib/test/string_SUITE.erl | 5 |
11 files changed, 178 insertions, 72 deletions
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml index dd4a289c61..702e1b928e 100644 --- a/lib/stdlib/doc/src/ets.xml +++ b/lib/stdlib/doc/src/ets.xml @@ -56,8 +56,8 @@ Even if there are no references to a table from any process, it will not automatically be destroyed unless the owner process terminates. It can be destroyed explicitly by using - <c>delete/1</c>.</p> - <p>Since R13B01, table ownership can be transferred at process termination + <c>delete/1</c>. The default owner is the process that created the + table. Table ownership can be transferred at process termination by using the <seealso marker="#heir">heir</seealso> option or explicitly by calling <seealso marker="#give_away/3">give_away/3</seealso>.</p> <p>Some implementation details:</p> @@ -82,11 +82,15 @@ <c>float()</c> that extends to the same value, hence the key <c>1</c> and the key <c>1.0</c> are regarded as equal in an <c>ordered_set</c> table.</p> - <p>In general, the functions below will exit with reason - <c>badarg</c> if any argument is of the wrong format, or if the - table identifier is invalid.</p> </description> - + <section> + <title>Failure</title> + <p>In general, the functions below will exit with reason + <c>badarg</c> if any argument is of the wrong format, if the + table identifier is invalid or if the operation is denied due to + table access rights (<seealso marker="#protected">protected</seealso> + or <seealso marker="#private">private</seealso>).</p> + </section> <section><marker id="concurrency"></marker> <title>Concurrency</title> <p>This module provides some limited support for concurrent access. @@ -947,7 +951,7 @@ ets:select(Table,MatchSpec),</code> <type> <v>Name = atom()</v> <v>Options = [Option]</v> - <v> Option = Type | Access | named_table | {keypos,Pos} | {heir,pid(),HeirData} | {heir,none} | {write_concurrency,bool()}</v> + <v> Option = Type | Access | named_table | {keypos,Pos} | {heir,pid(),HeirData} | {heir,none} | {write_concurrency,bool()} | {read_concurrency,bool()}</v> <v> Type = set | ordered_set | bag | duplicate_bag</v> <v> Access = public | protected | private</v> <v> Pos = int()</v> @@ -963,7 +967,7 @@ ets:select(Table,MatchSpec),</code> table is named or not. If one or more options are left out, the default values are used. This means that not specifying any options (<c>[]</c>) is the same as specifying - <c>[set,protected,{keypos,1},{heir,none},{write_concurrency,false}]</c>.</p> + <c>[set,protected,{keypos,1},{heir,none},{write_concurrency,false},{read_concurrency,false}]</c>.</p> <list type="bulleted"> <item> <p><c>set</c> @@ -1002,12 +1006,14 @@ ets:select(Table,MatchSpec),</code> Any process may read or write to the table.</p> </item> <item> + <marker id="protected"></marker> <p><c>protected</c> The owner process can read and write to the table. Other processes can only read the table. This is the default setting for the access rights.</p> </item> <item> + <marker id="private"></marker> <p><c>private</c> Only the owner process can read or write to the table.</p> </item> diff --git a/lib/stdlib/src/dets_v8.erl b/lib/stdlib/src/dets_v8.erl index 1f9f84cd27..af36958c1c 100644 --- a/lib/stdlib/src/dets_v8.erl +++ b/lib/stdlib/src/dets_v8.erl @@ -1074,6 +1074,8 @@ wl([], _Type, Del, Lookup, I, Objs) -> [{Del, Lookup, Objs} | I]. %% -> {NewHead, ok} | {NewHead, Error} +may_grow(Head, 0, once) -> + {Head, ok}; may_grow(Head, _N, _How) when Head#head.fixed =/= false -> {Head, ok}; may_grow(#head{access = read}=Head, _N, _How) -> diff --git a/lib/stdlib/src/dets_v9.erl b/lib/stdlib/src/dets_v9.erl index 53238e962f..132af01f79 100644 --- a/lib/stdlib/src/dets_v9.erl +++ b/lib/stdlib/src/dets_v9.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1908,6 +1908,9 @@ write_cache(Head) -> end. %% -> {NewHead, ok} | {NewHead, Error} +may_grow(Head, 0, once) -> + %% Do not re-hash if there is a chance that the file is not dirty. + {Head, ok}; may_grow(Head, _N, _How) when Head#head.fixed =/= false -> {Head, ok}; may_grow(#head{access = read}=Head, _N, _How) -> diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl index 81b2431f40..e5ccaddbb4 100644 --- a/lib/stdlib/src/epp.erl +++ b/lib/stdlib/src/epp.erl @@ -33,7 +33,9 @@ %% Epp state record. -record(epp, {file, %Current file location, %Current location + delta, %Offset from Location (-file) name="", %Current file name + name2="", %-"-, modified by -file istk=[], %Ifdef stack sstk=[], %State stack path=[], %Include-path @@ -234,8 +236,8 @@ init_server(Pid, Name, File, AtLocation, Path, Pdm, Pre) -> case user_predef(Pdm, Ms0) of {ok,Ms1} -> epp_reply(Pid, {ok,self()}), - St = #epp{file=File, location=AtLocation, name=Name, - path=Path, macs=Ms1, pre_opened = Pre}, + St = #epp{file=File, location=AtLocation, delta=0, name=Name, + name2=Name, path=Path, macs=Ms1, pre_opened = Pre}, From = wait_request(St), enter_file_reply(From, Name, AtLocation, AtLocation), wait_req_scan(St); @@ -358,8 +360,8 @@ enter_file2(NewF, Pname, From, St, AtLocation, ExtraPath) -> enter_file_reply(From, Pname, Loc, AtLocation), Ms = dict:store({atom,'FILE'}, {none,[{string,Loc,Pname}]}, St#epp.macs), Path = St#epp.path ++ ExtraPath, - #epp{location=Loc,file=NewF, - name=Pname,sstk=[St|St#epp.sstk],path=Path,macs=Ms}. + #epp{file=NewF,location=Loc,name=Pname,delta=0, + sstk=[St|St#epp.sstk],path=Path,macs=Ms}. enter_file_reply(From, Name, Location, AtLocation) -> Attr = loc_attr(AtLocation), @@ -391,14 +393,23 @@ leave_file(From, St) -> case St#epp.sstk of [OldSt|Sts] -> close_file(St), - enter_file_reply(From, OldSt#epp.name, - OldSt#epp.location, OldSt#epp.location), + #epp{location=OldLoc, delta=Delta, name=OldName, + name2=OldName2} = OldSt, + CurrLoc = add_line(OldLoc, Delta), Ms = dict:store({atom,'FILE'}, - {none, - [{string,OldSt#epp.location, - OldSt#epp.name}]}, + {none,[{string,CurrLoc,OldName2}]}, St#epp.macs), - wait_req_scan(OldSt#epp{sstk=Sts,macs=Ms}); + NextSt = OldSt#epp{sstk=Sts,macs=Ms}, + enter_file_reply(From, OldName, CurrLoc, CurrLoc), + case OldName2 =:= OldName of + true -> + From; + false -> + NFrom = wait_request(NextSt), + enter_file_reply(NFrom, OldName2, OldLoc, + neg_line(CurrLoc)) + end, + wait_req_scan(NextSt); [] -> epp_reply(From, {eof,St#epp.location}), wait_req_scan(St) @@ -768,7 +779,8 @@ scan_file([{'(',_Llp},{string,_Ls,Name},{',',_Lc},{integer,_Li,Ln},{')',_Lrp}, Ms = dict:store({atom,'FILE'}, {none,[{string,1,Name}]}, St#epp.macs), Locf = loc(Tf), NewLoc = new_location(Ln, St#epp.location, Locf), - wait_req_scan(St#epp{name=Name,location=NewLoc,macs=Ms}); + Delta = abs(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) -> epp_reply(From, {error,{loc(Tf),epp,{bad,file}}}), wait_req_scan(St). @@ -1132,6 +1144,9 @@ neg_line(L) -> abs_line(L) -> erl_scan:set_attribute(line, L, fun(Line) -> abs(Line) end). +add_line(L, Offset) -> + erl_scan:set_attribute(line, L, fun(Line) -> Line+Offset end). + start_loc(Line) when is_integer(Line) -> 1; start_loc({_Line, _Column}) -> @@ -1191,10 +1206,10 @@ interpret_file_attr([{attribute,Loc,file,{File,Line}}=Form | Forms], %% -include or -include_lib % true = L =:= Line, case Fs of - [_, Delta1, File | Fs1] -> % end of included file - [Form | interpret_file_attr(Forms, Delta1, [File | Fs1])]; + [_, File | Fs1] -> % end of included file + [Form | interpret_file_attr(Forms, 0, [File | Fs1])]; _ -> % start of included file - [Form | interpret_file_attr(Forms, 0, [File, Delta | Fs])] + [Form | interpret_file_attr(Forms, 0, [File | Fs])] end end; interpret_file_attr([Form0 | Forms], Delta, Fs) -> diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index 077621ac91..0c2d3db8ec 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -311,6 +311,8 @@ format_error({ill_defined_behaviour_callbacks,Behaviour}) -> %% --- types and specs --- format_error({singleton_typevar, Name}) -> io_lib:format("type variable ~w is only used once (is unbound)", [Name]); +format_error({bad_export_type, _ETs}) -> + io_lib:format("bad export_type declaration", []); format_error({duplicated_export_type, {T, A}}) -> io_lib:format("type ~w/~w already exported", [T, A]); format_error({undefined_type, {TypeName, Arity}}) -> @@ -1128,8 +1130,7 @@ export(Line, Es, #lint{exports = Es0, called = Called} = St0) -> export_type(Line, ETs, #lint{usage = Usage, exp_types = ETs0} = St0) -> UTs0 = Usage#usage.used_types, - {ETs1,UTs1,St1} = - foldl(fun (TA, {E,U,St2}) -> + try foldl(fun ({T,A}=TA, {E,U,St2}) when is_atom(T), is_integer(A) -> St = case gb_sets:is_element(TA, E) of true -> Warn = {duplicated_export_type,TA}, @@ -1139,8 +1140,13 @@ export_type(Line, ETs, #lint{usage = Usage, exp_types = ETs0} = St0) -> end, {gb_sets:add_element(TA, E), dict:store(TA, Line, U), St} end, - {ETs0,UTs0,St0}, ETs), - St1#lint{usage = Usage#usage{used_types = UTs1}, exp_types = ETs1}. + {ETs0,UTs0,St0}, ETs) of + {ETs1,UTs1,St1} -> + St1#lint{usage = Usage#usage{used_types = UTs1}, exp_types = ETs1} + catch + error:_ -> + add_error(Line, {bad_export_type, ETs}, St0) + end. -type import() :: {module(), [fa()]} | module(). -spec import(line(), import(), lint_state()) -> lint_state(). diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl index 431e5b114e..c669c1f7c1 100644 --- a/lib/stdlib/src/lists.erl +++ b/lib/stdlib/src/lists.erl @@ -358,7 +358,7 @@ merge(L) -> %% merge3(X, Y, Z) -> L %% merges three sorted lists X, Y and Z --spec merge3([_], [_], [_]) -> [_]. +-spec merge3([X], [Y], [Z]) -> [(X | Y | Z)]. merge3(L1, [], L3) -> merge(L1, L3); @@ -370,7 +370,7 @@ merge3(L1, [H2 | T2], [H3 | T3]) -> %% rmerge3(X, Y, Z) -> L %% merges three reversed sorted lists X, Y and Z --spec rmerge3([_], [_], [_]) -> [_]. +-spec rmerge3([X], [Y], [Z]) -> [(X | Y | Z)]. rmerge3(L1, [], L3) -> rmerge(L1, L3); @@ -382,7 +382,7 @@ rmerge3(L1, [H2 | T2], [H3 | T3]) -> %% merge(X, Y) -> L %% merges two sorted lists X and Y --spec merge([_], [_]) -> [_]. +-spec merge([X], [Y]) -> [(X | Y)]. merge(T1, []) -> T1; @@ -394,7 +394,7 @@ merge(T1, [H2 | T2]) -> %% reverse(rmerge(reverse(A),reverse(B))) is equal to merge(I,A,B). --spec rmerge([_], [_]) -> [_]. +-spec rmerge([X], [Y]) -> [(X | Y)]. rmerge(T1, []) -> T1; @@ -420,12 +420,12 @@ thing_to_list(X) when is_list(X) -> X. %Assumed to be a string %% flatten(List, Tail) %% Flatten a list, adding optional tail. --spec flatten([_]) -> [_]. +-spec flatten([term()]) -> [term()]. flatten(List) when is_list(List) -> do_flatten(List, []). --spec flatten([_], [_]) -> [_]. +-spec flatten([term()], [term()]) -> [term()]. flatten(List, Tail) when is_list(List), is_list(Tail) -> do_flatten(List, Tail). @@ -440,7 +440,7 @@ do_flatten([], Tail) -> %% flatlength(List) %% Calculate the length of a list of lists. --spec flatlength([_]) -> non_neg_integer(). +-spec flatlength([term()]) -> non_neg_integer(). flatlength(List) -> flatlength(List, 0). @@ -481,7 +481,7 @@ flatlength([], L) -> L. % keysearch3(Key, N, T); %keysearch3(Key, N, []) -> false. --spec keydelete(_, pos_integer(), [T]) -> [T]. +-spec keydelete(term(), pos_integer(), [T]) -> [T] when T :: tuple(). keydelete(K, N, L) when is_integer(N), N > 0 -> keydelete3(K, N, L). @@ -491,7 +491,7 @@ keydelete3(Key, N, [H|T]) -> [H|keydelete3(Key, N, T)]; keydelete3(_, _, []) -> []. --spec keyreplace(_, pos_integer(), [_], tuple()) -> [_]. +-spec keyreplace(term(), pos_integer(), [tuple()], tuple()) -> [tuple()]. keyreplace(K, N, L, New) when is_integer(N), N > 0, is_tuple(New) -> keyreplace3(K, N, L, New). @@ -502,7 +502,8 @@ keyreplace3(Key, Pos, [H|T], New) -> [H|keyreplace3(Key, Pos, T, New)]; keyreplace3(_, _, [], _) -> []. --spec keytake(_, pos_integer(), [_]) -> {'value', tuple(), [_]} | 'false'. +-spec keytake(term(), pos_integer(), [tuple()]) -> + {'value', tuple(), [tuple()]} | 'false'. keytake(Key, N, L) when is_integer(N), N > 0 -> keytake(Key, N, L, []). @@ -513,7 +514,8 @@ keytake(Key, N, [H|T], L) -> keytake(Key, N, T, [H|L]); keytake(_K, _N, [], _L) -> false. --spec keystore(_, pos_integer(), [_], tuple()) -> [_]. +-spec keystore(term(), pos_integer(), [tuple()], tuple()) -> [tuple(),...]. + keystore(K, N, L, New) when is_integer(N), N > 0, is_tuple(New) -> keystore2(K, N, L, New). @@ -524,7 +526,7 @@ keystore2(Key, N, [H|T], New) -> keystore2(_Key, _N, [], New) -> [New]. --spec keysort(pos_integer(), [T]) -> [T] when is_subtype(T, tuple()). +-spec keysort(pos_integer(), [T]) -> [T] when T :: tuple(). keysort(I, L) when is_integer(I), I > 0 -> case L of @@ -582,7 +584,7 @@ keysort_1(_I, X, _EX, [], R) -> lists:reverse(R, [X]). -spec keymerge(pos_integer(), [X], [Y]) -> - [R] when is_subtype(X, tuple()), is_subtype(Y, tuple()), is_subtype(R, tuple()). + [R] when X :: tuple(), Y :: tuple(), R :: tuple(). keymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> case L2 of @@ -597,7 +599,7 @@ keymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> %% reverse(rkeymerge(I,reverse(A),reverse(B))) is equal to keymerge(I,A,B). -spec rkeymerge(pos_integer(), [X], [Y]) -> - [R] when is_subtype(X, tuple()), is_subtype(Y, tuple()), is_subtype(R, tuple()). + [R] when X :: tuple(), Y :: tuple(), R :: tuple(). rkeymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> case L2 of @@ -609,7 +611,7 @@ rkeymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> lists:reverse(M, []) end. --spec ukeysort(pos_integer(), [T]) -> [T] when is_subtype(T, tuple()). +-spec ukeysort(pos_integer(), [T]) -> [T] when T :: tuple(). ukeysort(I, L) when is_integer(I), I > 0 -> case L of @@ -675,7 +677,7 @@ ukeysort_1(_I, X, _EX, []) -> [X]. -spec ukeymerge(pos_integer(), [X], [Y]) -> - [(X | Y)] when is_subtype(X, tuple()), is_subtype(Y, tuple()). + [(X | Y)] when X :: tuple(), Y :: tuple(). ukeymerge(Index, L1, T2) when is_integer(Index), Index > 0 -> case L1 of @@ -690,7 +692,7 @@ ukeymerge(Index, L1, T2) when is_integer(Index), Index > 0 -> %% reverse(rukeymerge(I,reverse(A),reverse(B))) is equal to ukeymerge(I,A,B). -spec rukeymerge(pos_integer(), [X], [Y]) -> - [(X | Y)] when is_subtype(X, tuple()), is_subtype(Y, tuple()). + [(X | Y)] when X :: tuple(), Y :: tuple(). rukeymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> case L2 of @@ -702,7 +704,7 @@ rukeymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> lists:reverse(M, []) end. --spec keymap(fun((_) -> _), pos_integer(), [tuple()]) -> [tuple()]. +-spec keymap(fun((term()) -> term()), pos_integer(), [tuple()]) -> [tuple()]. keymap(Fun, Index, [Tup|Tail]) -> [setelement(Index, Tup, Fun(element(Index, Tup)))|keymap(Fun, Index, Tail)]; @@ -725,7 +727,7 @@ sort(Fun, [X, Y | T]) -> fsplit_2(Y, X, Fun, T, [], []) end. --spec merge(fun((X, Y) -> boolean()), [X], [Y]) -> [_]. +-spec merge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)]. merge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) -> lists:reverse(fmerge2_1(T1, H2, Fun, T2, []), []); @@ -734,7 +736,7 @@ merge(Fun, T1, []) when is_function(Fun, 2) -> %% reverse(rmerge(F,reverse(A),reverse(B))) is equal to merge(F,A,B). --spec rmerge(fun((X, Y) -> boolean()), [X], [Y]) -> [_]. +-spec rmerge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)]. rmerge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) -> lists:reverse(rfmerge2_1(T1, H2, Fun, T2, []), []); @@ -768,7 +770,7 @@ usort_1(Fun, X, [Y | L]) -> ufsplit_2(Y, L, Fun, [X]) end. --spec umerge(fun((X, Y) -> boolean()), [X], [Y]) -> [_]. +-spec umerge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)]. umerge(Fun, [], T2) when is_function(Fun, 2) -> T2; @@ -777,7 +779,7 @@ umerge(Fun, [H1 | T1], T2) when is_function(Fun, 2) -> %% reverse(rumerge(F,reverse(A),reverse(B))) is equal to umerge(F,A,B). --spec rumerge(fun((X, Y) -> boolean()), [X], [Y]) -> [_]. +-spec rumerge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)]. rumerge(Fun, T1, []) when is_function(Fun, 2) -> T1; @@ -851,7 +853,7 @@ umerge(L) -> %% merges three sorted lists X, Y and Z without duplicates, %% removes duplicates --spec umerge3([_], [_], [_]) -> [_]. +-spec umerge3([X], [Y], [Z]) -> [(X | Y | Z)]. umerge3(L1, [], L3) -> umerge(L1, L3); @@ -864,7 +866,7 @@ umerge3(L1, [H2 | T2], [H3 | T3]) -> %% merges three reversed sorted lists X, Y and Z without duplicates, %% removes duplicates --spec rumerge3([_], [_], [_]) -> [_]. +-spec rumerge3([X], [Y], [Z]) -> [(X | Y | Z)]. rumerge3(L1, [], L3) -> rumerge(L1, L3); @@ -876,7 +878,7 @@ rumerge3(L1, [H2 | T2], [H3 | T3]) -> %% umerge(X, Y) -> L %% merges two sorted lists X and Y without duplicates, removes duplicates --spec umerge([_], [_]) -> [_]. +-spec umerge([X], [Y]) -> [(X | Y)]. umerge([], T2) -> T2; @@ -889,7 +891,7 @@ umerge([H1 | T1], T2) -> %% reverse(rumerge(reverse(A),reverse(B))) is equal to umerge(I,A,B). --spec rumerge([_], [_]) -> [_]. +-spec rumerge([X], [Y]) -> [(X | Y)]. rumerge(T1, []) -> T1; @@ -952,13 +954,13 @@ flatmap(F, [Hd|Tail]) -> F(Hd) ++ flatmap(F, Tail); flatmap(F, []) when is_function(F, 1) -> []. --spec foldl(fun((T, _) -> _), _, [T]) -> _. +-spec foldl(fun((T, term()) -> term()), term(), [T]) -> term(). foldl(F, Accu, [Hd|Tail]) -> foldl(F, F(Hd, Accu), Tail); foldl(F, Accu, []) when is_function(F, 2) -> Accu. --spec foldr(fun((T, _) -> _), _, [T]) -> _. +-spec foldr(fun((T, term()) -> term()), term(), [T]) -> term(). foldr(F, Accu, [Hd|Tail]) -> F(Hd, foldr(F, Accu, Tail)); @@ -998,14 +1000,14 @@ zf(F, [Hd|Tail]) -> end; zf(F, []) when is_function(F, 1) -> []. --spec foreach(F :: fun((T) -> _), List :: [T]) -> 'ok'. +-spec foreach(F :: fun((T) -> term()), List :: [T]) -> 'ok'. foreach(F, [Hd|Tail]) -> F(Hd), foreach(F, Tail); foreach(F, []) when is_function(F, 1) -> ok. --spec mapfoldl(fun((T, _) -> {_, _}), _, [T]) -> {[_], _}. +-spec mapfoldl(fun((A, term()) -> {B, term()}), term(), [A]) -> {[B], term()}. mapfoldl(F, Accu0, [Hd|Tail]) -> {R,Accu1} = F(Hd, Accu0), @@ -1013,7 +1015,7 @@ mapfoldl(F, Accu0, [Hd|Tail]) -> {[R|Rs],Accu2}; mapfoldl(F, Accu, []) when is_function(F, 2) -> {[],Accu}. --spec mapfoldr(fun((T, _) -> {_, _}), _, [T]) -> {[_], _}. +-spec mapfoldr(fun((A, term()) -> {B, term()}), term(), [A]) -> {[B], term()}. mapfoldr(F, Accu0, [Hd|Tail]) -> {Rs,Accu1} = mapfoldr(F, Accu0, Tail), diff --git a/lib/stdlib/src/ordsets.erl b/lib/stdlib/src/ordsets.erl index e992b66714..4c72e351d0 100644 --- a/lib/stdlib/src/ordsets.erl +++ b/lib/stdlib/src/ordsets.erl @@ -26,12 +26,14 @@ -export([subtract/2,is_subset/2]). -export([fold/3,filter/2]). +-export_type([ordset/1]). + -type ordset(T) :: [T]. %% new() -> Set. %% Return a new empty ordered set. --spec new() -> ordset(term()). +-spec new() -> []. new() -> []. @@ -84,7 +86,7 @@ is_element(_, []) -> false. %% add_element(Element, OrdSet) -> OrdSet. %% Return OrdSet with Element inserted in it. --spec add_element(term(), ordset(_)) -> ordset(_). +-spec add_element(E, ordset(T)) -> [T | E,...]. add_element(E, [H|Es]) when E > H -> [H|add_element(E, Es)]; add_element(E, [H|_]=Set) when E < H -> [E|Set]; @@ -94,7 +96,7 @@ add_element(E, []) -> [E]. %% del_element(Element, OrdSet) -> OrdSet. %% Return OrdSet but with Element removed. --spec del_element(term(), ordset(_)) -> ordset(_). +-spec del_element(term(), ordset(T)) -> ordset(T). del_element(E, [H|Es]) when E > H -> [H|del_element(E, Es)]; del_element(E, [H|_]=Set) when E < H -> Set; @@ -104,7 +106,7 @@ del_element(_, []) -> []. %% union(OrdSet1, OrdSet2) -> OrdSet %% Return the union of OrdSet1 and OrdSet2. --spec union(ordset(_), ordset(_)) -> ordset(_). +-spec union(ordset(T1), ordset(T2)) -> ordset(T1 | T2). union([E1|Es1], [E2|_]=Set2) when E1 < E2 -> [E1|union(Es1, Set2)]; @@ -118,7 +120,7 @@ union(Es1, []) -> Es1. %% union([OrdSet]) -> OrdSet %% Return the union of the list of ordered sets. --spec union([ordset(_)]) -> ordset(_). +-spec union([ordset(T)]) -> ordset(T). union([S1,S2|Ss]) -> union1(union(S1, S2), Ss); @@ -206,7 +208,7 @@ is_subset(_, []) -> false. %% fold(Fun, Accumulator, OrdSet) -> Accumulator. %% Fold function Fun over all elements in OrdSet and return Accumulator. --spec fold(fun((_, _) -> _), _, ordset(_)) -> _. +-spec fold(fun((T, term()) -> term()), term(), ordset(T)) -> term(). fold(F, Acc, Set) -> lists:foldl(F, Acc, Set). @@ -214,7 +216,7 @@ fold(F, Acc, Set) -> %% filter(Fun, OrdSet) -> OrdSet. %% Filter OrdSet with Fun. --spec filter(fun((_) -> boolean()), ordset(_)) -> ordset(_). +-spec filter(fun((T) -> boolean()), ordset(T)) -> ordset(T). filter(F, Set) -> lists:filter(F, Set). diff --git a/lib/stdlib/src/string.erl b/lib/stdlib/src/string.erl index 6636a03f06..c987c224db 100644 --- a/lib/stdlib/src/string.erl +++ b/lib/stdlib/src/string.erl @@ -201,7 +201,7 @@ chars(C, 0, Tail) when is_integer(C) -> -spec copies(string(), non_neg_integer()) -> string(). -copies(CharList, Num) when is_list(CharList), Num >= 0 -> +copies(CharList, Num) when is_list(CharList), is_integer(Num), Num >= 0 -> copies(CharList, Num, []). copies(_CharList, 0, R) -> diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl index a1f70dc27d..8b18ef5664 100644 --- a/lib/stdlib/test/dets_SUITE.erl +++ b/lib/stdlib/test/dets_SUITE.erl @@ -50,7 +50,8 @@ otp_4208/1, otp_4989/1, many_clients/1, otp_4906/1, otp_5402/1, 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_8070/1, otp_8856/1, otp_8898/1, otp_8899/1, otp_8903/1, + otp_8923/1]). -export([dets_dirty_loop/0]). @@ -108,7 +109,8 @@ all(suite) -> cache_duplicate_bags_v9, otp_4208, otp_4989, 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_7146, otp_8070, otp_8856, otp_8898, otp_8899, otp_8903, + otp_8923]} end. not_run(suite) -> []; @@ -3805,6 +3807,39 @@ otp_8903(Config) when is_list(Config) -> file:delete(File), ok. +otp_8923(doc) -> + ["OTP-8923. rehash due to lookup after initialization."]; +otp_8923(suite) -> + []; +otp_8923(Config) when is_list(Config) -> + Tab = otp_8923, + File = filename(Tab, Config), + %% Create a file with more than 256 keys: + file:delete(File), + Bin = list_to_binary([ 0 || _ <- lists:seq(1, 400) ]), + BigBin = list_to_binary([ 0 ||_ <- lists:seq(1, 4000)]), + Ets = ets:new(temp, [{keypos,1}]), + ?line [ true = ets:insert(Ets, {C,Bin}) || C <- lists:seq(1, 700) ], + ?line true = ets:insert(Ets, {helper_data,BigBin}), + ?line true = ets:insert(Ets, {prim_btree,BigBin}), + ?line true = ets:insert(Ets, {sec_btree,BigBin}), + %% Note: too few slots; re-hash will take place + ?line {ok, Tab} = dets:open_file(Tab, [{file,File}]), + ?line Tab = ets:to_dets(Ets, Tab), + ?line ok = dets:close(Tab), + ?line true = ets:delete(Ets), + + ?line {ok,Ref} = dets:open_file(File), + ?line [{1,_}] = dets:lookup(Ref, 1), + ?line ok = dets:close(Ref), + + ?line {ok,Ref2} = dets:open_file(File), + ?line [{helper_data,_}] = dets:lookup(Ref2, helper_data), + ?line ok = dets:close(Ref2), + + file:delete(File), + ok. + %% %% Parts common to several test cases %% diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl index e31dfdd764..e9fb932632 100644 --- a/lib/stdlib/test/epp_SUITE.erl +++ b/lib/stdlib/test/epp_SUITE.erl @@ -24,7 +24,7 @@ variable/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_8562/1, otp_8665/1]). + otp_8562/1, otp_8665/1, otp_8911/1]). -export([epp_parse_erl_form/2]). @@ -64,7 +64,7 @@ all(doc) -> all(suite) -> [rec_1, upcase_mac, predef_mac, 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, otp_8665]. + overload_mac, otp_8388, otp_8470, otp_8503, otp_8562, otp_8665, otp_8911]. rec_1(doc) -> ["Recursive macros hang or crash epp (OTP-1398)."]; @@ -1197,6 +1197,40 @@ otp_8562(Config) when is_list(Config) -> ?line [] = compile(Config, Cs), ok. +otp_8911(doc) -> + ["OTP-8911. -file and file inclusion bug"]; +otp_8911(suite) -> + []; +otp_8911(Config) when is_list(Config) -> + ?line {ok, CWD} = file:get_cwd(), + ?line ok = file:set_cwd(?config(priv_dir, Config)), + + File = "i.erl", + Cont = <<"-module(i). + -compile(export_all). + -file(\"fil1\", 100). + -include(\"i1.erl\"). + t() -> + a. + ">>, + ?line ok = file:write_file(File, Cont), + Incl = <<"-file(\"fil2\", 35). + t1() -> + b. + ">>, + File1 = "i1.erl", + ?line ok = file:write_file(File1, Incl), + + ?line {ok, i} = cover:compile(File), + ?line a = i:t(), + ?line {ok,[{{i,6},1}]} = cover:analyse(i, calls, line), + ?line cover:stop(), + + file:delete(File), + file:delete(File1), + ?line file:set_cwd(CWD), + ok. + otp_8665(doc) -> ["OTP-8665. Bugfix premature end."]; otp_8665(suite) -> diff --git a/lib/stdlib/test/string_SUITE.erl b/lib/stdlib/test/string_SUITE.erl index 3171b87c44..452e048dd7 100644 --- a/lib/stdlib/test/string_SUITE.erl +++ b/lib/stdlib/test/string_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -240,7 +240,8 @@ copies(Config) when is_list(Config) -> ?line "." = string:copies(".", 1), ?line 30 = length(string:copies("123", 10)), %% invalid arg type - ?line {'EXIT',_} = (catch string:chars("hej", -1)), + ?line {'EXIT',_} = (catch string:copies("hej", -1)), + ?line {'EXIT',_} = (catch string:copies("hej", 2.0)), ok. words(suite) -> |