aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib')
-rw-r--r--lib/stdlib/doc/src/erl_tar.xml27
-rw-r--r--lib/stdlib/doc/src/gen_fsm.xml4
-rw-r--r--lib/stdlib/doc/src/gen_server.xml2
-rw-r--r--lib/stdlib/doc/src/maps.xml37
-rw-r--r--lib/stdlib/doc/src/notes.xml561
-rw-r--r--lib/stdlib/doc/src/pg.xml5
-rw-r--r--lib/stdlib/doc/src/string.xml6
-rw-r--r--lib/stdlib/doc/src/sys.xml5
-rw-r--r--lib/stdlib/doc/src/zip.xml13
-rw-r--r--lib/stdlib/examples/erl_id_trans.erl2
-rw-r--r--lib/stdlib/src/dets.erl5
-rw-r--r--lib/stdlib/src/epp.erl16
-rw-r--r--lib/stdlib/src/erl_eval.erl10
-rw-r--r--lib/stdlib/src/erl_expand_records.erl32
-rw-r--r--lib/stdlib/src/erl_lint.erl41
-rw-r--r--lib/stdlib/src/erl_parse.yrl21
-rw-r--r--lib/stdlib/src/erl_pp.erl21
-rw-r--r--lib/stdlib/src/erl_scan.erl4
-rw-r--r--lib/stdlib/src/erl_tar.erl38
-rw-r--r--lib/stdlib/src/escript.erl5
-rw-r--r--lib/stdlib/src/filelib.erl12
-rw-r--r--lib/stdlib/src/gen_fsm.erl49
-rw-r--r--lib/stdlib/src/gen_server.erl51
-rw-r--r--lib/stdlib/src/io_lib_format.erl2
-rw-r--r--lib/stdlib/src/io_lib_pretty.erl2
-rw-r--r--lib/stdlib/src/maps.erl37
-rw-r--r--lib/stdlib/src/otp_internal.erl65
-rw-r--r--lib/stdlib/src/pg.erl3
-rw-r--r--lib/stdlib/src/proc_lib.erl6
-rw-r--r--lib/stdlib/src/shell.erl8
-rw-r--r--lib/stdlib/src/slave.erl23
-rw-r--r--lib/stdlib/src/stdlib.app.src2
-rw-r--r--lib/stdlib/src/stdlib.appup.src6
-rw-r--r--lib/stdlib/src/sys.erl10
-rw-r--r--lib/stdlib/src/zip.erl37
-rw-r--r--lib/stdlib/test/Makefile3
-rw-r--r--lib/stdlib/test/binary_module_SUITE.erl4
-rw-r--r--lib/stdlib/test/dets_SUITE.erl47
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl7
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl59
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl10
-rw-r--r--lib/stdlib/test/erl_scan_SUITE.erl246
-rw-r--r--lib/stdlib/test/filelib_SUITE.erl144
-rw-r--r--lib/stdlib/test/gen_fsm_SUITE.erl39
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl41
-rw-r--r--lib/stdlib/test/io_SUITE.erl10
-rw-r--r--lib/stdlib/test/maps_SUITE.erl80
-rw-r--r--lib/stdlib/test/shell_SUITE.erl5
-rw-r--r--lib/stdlib/test/stdlib_SUITE.erl12
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl57
-rw-r--r--lib/stdlib/test/tar_SUITE.erl66
-rw-r--r--lib/stdlib/test/unicode_SUITE.erl12
-rw-r--r--lib/stdlib/vsn.mk2
53 files changed, 1583 insertions, 429 deletions
diff --git a/lib/stdlib/doc/src/erl_tar.xml b/lib/stdlib/doc/src/erl_tar.xml
index f81e36f810..7f25f5b7bc 100644
--- a/lib/stdlib/doc/src/erl_tar.xml
+++ b/lib/stdlib/doc/src/erl_tar.xml
@@ -35,10 +35,11 @@
<modulesummary>Unix 'tar' utility for reading and writing tar archives</modulesummary>
<description>
<p>The <c>erl_tar</c> module archives and extract files to and from
- a tar file. The tar file format is the POSIX extended tar file format
- specified in IEEE Std 1003.1 and ISO/IEC&nbsp;9945-1. That is the same
- format as used by <c>tar</c> program on Solaris, but is not the same
- as used by the GNU tar program.</p>
+ a tar file. <c>erl_tar</c> supports the <c>ustar</c> format
+ (IEEE Std 1003.1 and ISO/IEC&nbsp;9945-1). All modern <c>tar</c>
+ programs (including GNU tar) can read this format. To ensure that
+ that GNU tar produces a tar file that <c>erl_tar</c> can read,
+ give the <c>--format=ustar</c> option to GNU tar.</p>
<p>By convention, the name of a tar file should end in "<c>.tar</c>".
To abide to the convention, you'll need to add "<c>.tar</c>" yourself
to the name.</p>
@@ -65,6 +66,20 @@
</description>
<section>
+ <title>UNICODE SUPPORT</title>
+ <p>If <seealso
+ marker="kernel:file#native_name_encoding/0">file:native_name_encoding/0</seealso>
+ returns <c>utf8</c>, path names will be encoded in UTF-8 when
+ creating tar files and path names will be assumed to be encoded in
+ UTF-8 when extracting tar files.</p>
+
+ <p>If <seealso
+ marker="kernel:file#native_name_encoding/0">file:native_name_encoding/0</seealso>
+ returns <c>latin1</c>, no translation of path names will be
+ done.</p>
+ </section>
+
+ <section>
<title>LIMITATIONS</title>
<p>For maximum compatibility, it is safe to archive files with names
up to 100 characters in length. Such tar files can generally be
@@ -112,8 +127,8 @@
<fsummary>Add a file to an open tar file</fsummary>
<type>
<v>TarDescriptor = term()</v>
- <v>FilenameOrBin = Filename()|binary()</v>
- <v>Filename = filename()()</v>
+ <v>FilenameOrBin = filename()|binary()</v>
+ <v>Filename = filename()</v>
<v>NameInArchive = filename()</v>
<v>Options = [Option]</v>
<v>Option = dereference|verbose</v>
diff --git a/lib/stdlib/doc/src/gen_fsm.xml b/lib/stdlib/doc/src/gen_fsm.xml
index 1713367bd8..848d57f3e6 100644
--- a/lib/stdlib/doc/src/gen_fsm.xml
+++ b/lib/stdlib/doc/src/gen_fsm.xml
@@ -115,7 +115,7 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
If <c>FsmName={global,GlobalName}</c>, the gen_fsm is
registered globally as <c>GlobalName</c> using
<c>global:register_name/2</c>.
- If <c>EventMgrName={via,Module,ViaName}</c>, the event manager will
+ If <c>FsmName={via,Module,ViaName}</c>, the gen_fsm will
register with the registry represented by <c>Module</c>.
The <c>Module</c> callback should export the functions
<c>register_name/2</c>, <c>unregister_name/1</c>,
@@ -210,7 +210,7 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
registered at another node, or</item>
<item><c>{global,GlobalName}</c>, if the gen_fsm is globally
registered.</item>
- <item><c>{via,Module,ViaName}</c>, if the event manager is registered
+ <item><c>{via,Module,ViaName}</c>, if the gen_fsm is registered
through an alternative process registry.</item>
</list>
<p><c>Event</c> is an arbitrary term which is passed as one of
diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml
index 4c83fde237..62c0394479 100644
--- a/lib/stdlib/doc/src/gen_server.xml
+++ b/lib/stdlib/doc/src/gen_server.xml
@@ -113,7 +113,7 @@ gen_server:abcast -----> Module:handle_cast/2
registered globally as <c>GlobalName</c> using
<c>global:register_name/2</c>. If no name is provided,
the gen_server is not registered.
- If <c>EventMgrName={via,Module,ViaName}</c>, the event manager will
+ If <c>ServerName={via,Module,ViaName}</c>, the gen_server will
register with the registry represented by <c>Module</c>.
The <c>Module</c> callback should export the functions
<c>register_name/2</c>, <c>unregister_name/1</c>,
diff --git a/lib/stdlib/doc/src/maps.xml b/lib/stdlib/doc/src/maps.xml
index 76137e3dee..64229fa8d3 100644
--- a/lib/stdlib/doc/src/maps.xml
+++ b/lib/stdlib/doc/src/maps.xml
@@ -108,6 +108,26 @@
</func>
<func>
+ <name name="get" arity="3"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>
+ Returns the value <c><anno>Value</anno></c> associated with <c><anno>Key</anno></c> if
+ <c><anno>Map</anno></c> contains <c><anno>Key</anno></c>.
+ If no value is associated with <c><anno>Key</anno></c> then returns <c><anno>Default</anno></c>.
+ </p>
+ <p>Example:</p>
+ <code type="none">
+> Map = #{ key1 => val1, key2 => val2 }.
+#{key1 => val1,key2 => val2}
+> maps:get(key1, Map, "Default value").
+val1
+> maps:get(key3, Map, "Default value").
+"Default value"</code>
+ </desc>
+ </func>
+
+ <func>
<name name="is_key" arity="2"/>
<fsummary></fsummary>
<desc>
@@ -299,6 +319,23 @@ false</code>
</func>
<func>
+ <name name="with" arity="2"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>
+ Returns a new map <c><anno>Map2</anno></c> with the keys <c>K1</c> through <c>Kn</c> and their associated values from map <c><anno>Map1</anno></c>.
+ Any key in <c><anno>Ks</anno></c> that does not exist in <c><anno>Map1</anno></c> are ignored.
+ </p>
+ <p>Example:</p>
+ <code type="none">
+> Map = #{42 => value_three,1337 => "value two","a" => 1},
+ Ks = ["a",42,"other key"],
+ maps:without(Ks,Map).
+#{42 => value_three,"a" => 1}</code>
+ </desc>
+ </func>
+
+ <func>
<name name="without" arity="2"/>
<fsummary></fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index e94a4d6a55..ebc750a399 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -30,6 +30,563 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The type spec of the FormFunc argument to
+ sys:handle_debug/4 was erroneously pointing to dbg_fun().
+ This is now corrected and the new type is format_fun().</p>
+ <p>
+ Own Id: OTP-11800</p>
+ </item>
+ <item>
+ <p>
+ Behaviors such as gen_fsm and gen_server should always
+ invoke format_status/2 before printing the state to the
+ logs.</p>
+ <p>
+ Own Id: OTP-11967</p>
+ </item>
+ <item>
+ <p> The documentation of <c>dets:insert_new/2</c> has
+ been corrected. (Thanks to Alexei Sholik for reporting
+ the bug.) </p>
+ <p>
+ Own Id: OTP-12024</p>
+ </item>
+ <item>
+ <p>
+ Printing a term with io_lib:format and control sequence
+ w, precision P and field width F, where F&lt; P would
+ fail in one of the two following ways:</p>
+ <p>
+ 1) If P &lt; printed length of the term, an infinite loop
+ would be entered, consuming all available memory.</p>
+ <p>
+ 2) If P &gt;= printed length of the term, an exception
+ would be raised.</p>
+ <p>
+ These two problems are now corrected.</p>
+ <p>
+ Own Id: OTP-12041</p>
+ </item>
+ <item>
+ <p>
+ The documentation of <c>maps:values/1</c> has been
+ corrected.</p>
+ <p>
+ Own Id: OTP-12055</p>
+ </item>
+ <item>
+ <p>
+ Expand shell functions in map expressions.</p>
+ <p>
+ Own Id: OTP-12063</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add maps:with/2</p>
+ <p>
+ Own Id: OTP-12137</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 2.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ OTP-11850 fixed filelib:wildcard/1 to work with broken
+ symlinks. This correction, however, introduced problems
+ since symlinks were no longer followed for functions like
+ filelib:ensure_dir/1, filelib:is_dir/1,
+ filelib:file_size/1, etc. This is now corrected.</p>
+ <p>
+ Own Id: OTP-12054 Aux Id: seq12660 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p><c>filelib:wildcard("broken_symlink")</c> would return
+ an empty list if "broken_symlink" was a symlink that did
+ not point to an existing file.</p>
+ <p>
+ Own Id: OTP-11850 Aux Id: seq12571 </p>
+ </item>
+ <item>
+ <p><c>erl_tar</c> can now handle files names that contain
+ Unicode characters. See "UNICODE SUPPORT" in the
+ documentation for <c>erl_tar</c>.</p>
+ <p>When creating a tar file, <c>erl_tar</c> would
+ sometime write a too short end of tape marker. GNU tar
+ would correctly extract files from such tar file, but
+ would complain about "A lone zero block at...".</p>
+ <p>
+ Own Id: OTP-11854</p>
+ </item>
+ <item>
+ <p> When redefining and exporting the type <c>map()</c>
+ the Erlang Code Linter (<c>erl_lint</c>) erroneously
+ emitted an error. This bug has been fixed. </p>
+ <p>
+ Own Id: OTP-11872</p>
+ </item>
+ <item>
+ <p>
+ Fix evaluation of map updates in the debugger and
+ erl_eval</p>
+ <p>
+ Reported-by: José Valim</p>
+ <p>
+ Own Id: OTP-11922</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>The following native functions now bump an appropriate
+ amount of reductions and yield when out of
+ reductions:</p> <list>
+ <item><c>erlang:binary_to_list/1</c></item>
+ <item><c>erlang:binary_to_list/3</c></item>
+ <item><c>erlang:bitstring_to_list/1</c></item>
+ <item><c>erlang:list_to_binary/1</c></item>
+ <item><c>erlang:iolist_to_binary/1</c></item>
+ <item><c>erlang:list_to_bitstring/1</c></item>
+ <item><c>binary:list_to_bin/1</c></item> </list>
+ <p>Characteristics impact:</p> <taglist>
+ <tag>Performance</tag> <item>The functions converting
+ from lists got a performance loss for very small lists,
+ and a performance gain for very large lists.</item>
+ <tag>Priority</tag> <item>Previously a process executing
+ one of these functions effectively got an unfair priority
+ boost. This priority boost depended on the input size.
+ The larger the input was, the larger the priority boost
+ got. This unfair priority boost is now lost. </item>
+ </taglist>
+ <p>
+ Own Id: OTP-11888</p>
+ </item>
+ <item>
+ <p>
+ Add <c>maps:get/3</c> to maps module. The function will
+ return the supplied default value if the key does not
+ exist in the map.</p>
+ <p>
+ Own Id: OTP-11951</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 2.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The option dupnames did not work as intended in re. When
+ looking for names with {capture, [Name, ...]}, re:run
+ returned a random instance of the match for that name,
+ instead of the leftmost matching instance, which was what
+ the documentation stated. This is now corrected to adhere
+ to the documentation. The option {capture,all_names}
+ along with a re:inspect/2 function is also added to
+ further help in using named subpatterns.</p>
+ <p>
+ Own Id: OTP-11205</p>
+ </item>
+ <item>
+ <p>
+ If option 'binary' was set for standard_input, then c:i()
+ would hang if the output was more than one page long -
+ i.e. then input after "(c)ontinue (q)uit --&gt;" could
+ not be read. This has been corrected. (Thanks to José
+ Valim)</p>
+ <p>
+ Own Id: OTP-11589</p>
+ </item>
+ <item>
+ <p>
+ stdlib/lists: Add function droplast/1 This functions
+ drops the last element of a non-empty list. lists:last/1
+ and lists:droplast/1 are the dual of hd/1 and tl/1 but
+ for the end of a list. (Thanks to Hans Svensson)</p>
+ <p>
+ Own Id: OTP-11677</p>
+ </item>
+ <item>
+ <p>
+ Allow all auto imports to be suppressed at once.
+ Introducing the no_auto_import attribute:
+ -compile(no_auto_import). Useful for code generation
+ tools that always use the qualified function names and
+ want to avoid the auto imported functions clashing with
+ local ones. (Thanks to José Valim.)</p>
+ <p>
+ Own Id: OTP-11682</p>
+ </item>
+ <item>
+ <p>
+ supervisor_bridge does no longer report normal
+ termination of children. The reason is that in some
+ cases, for instance when the restart strategy is
+ simple_one_for_one, the log could be completely
+ overloaded with reports about normally terminating
+ processes. (Thanks to Artem Ocheredko)</p>
+ <p>
+ Own Id: OTP-11685</p>
+ </item>
+ <item>
+ <p> The type annotations for alternative registries using
+ the {via, Module, Name} syntax for sup_name() and
+ sup_ref() in the supervisor module are now consistent
+ with the documentation. Dialyzer should no longer
+ complain about valid supervisor:start_link() and
+ supervisor:start_child() calls. (Thanks to Caleb
+ Helbling.) </p>
+ <p>
+ Own Id: OTP-11707</p>
+ </item>
+ <item>
+ <p> Two Dets bugs have been fixed. When trying to open a
+ short file that is not a Dets file, the file was deleted
+ even with just read access. Calling
+ <c>dets:is_dets_file/1</c> with a file that is not a Dets
+ file, a file descriptor was left open. (Thanks to Håkan
+ Mattsson for reporting the bugs.) </p>
+ <p>
+ Own Id: OTP-11709</p>
+ </item>
+ <item>
+ <p>
+ Fix race bug in <c>ets:all</c>. Concurrent creation of
+ tables could cause other tables to not be included in the
+ result. (Thanks to Florian Schintke for bug report)</p>
+ <p>
+ Own Id: OTP-11726</p>
+ </item>
+ <item>
+ <p>
+ erl_eval now properly evaluates '=='/2 when it is used in
+ guards. (Thanks to José Valim)</p>
+ <p>
+ Own Id: OTP-11747</p>
+ </item>
+ <item>
+ <p>
+ Calls to proplists:get_value/3 are replaced by the faster
+ lists:keyfind/3 in io_lib_pretty. Elements in the list
+ are always 2-tuples. (Thanks to Andrew Thompson)</p>
+ <p>
+ Own Id: OTP-11752</p>
+ </item>
+ <item>
+ <p> A qlc bug where filters were erroneously optimized
+ away has been fixed. Thanks to Sam Bobroff for reporting
+ the bug. </p>
+ <p>
+ Own Id: OTP-11758</p>
+ </item>
+ <item>
+ <p>
+ A number of compiler errors where unusual or nonsensical
+ code would crash the compiler have been reported by Ulf
+ Norell and corrected by Anthony Ramine.</p>
+ <p>
+ Own Id: OTP-11770</p>
+ </item>
+ <item>
+ <p> Since Erlang/OTP R16B the Erlang Core Linter
+ (<c>erl_lint</c>) has not emitted errors when built-in
+ types were re-defined. This bug has been fixed. (Thanks
+ to Roberto Aloi.) </p>
+ <p>
+ Own Id: OTP-11772</p>
+ </item>
+ <item>
+ <p>
+ The functions <c>sys:get_state/1,2</c> and
+ <c>sys:replace_state/2,3</c> are fixed so they can now be
+ run while the process is sys suspended. To accomplish
+ this, the new callbacks <c>Mod:system_get_state/1</c> and
+ <c>Mod:system_replace_state/2</c> are added, which are
+ also implemented by the generic behaviours
+ <c>gen_server</c>, <c>gen_event</c> and <c>gen_fsm</c>.</p>
+ <p>
+ The potential incompatibility refers to</p>
+ <p>
+ <list> <item>The previous behaviour of intercepting the
+ system message and passing a tuple of size 2 as the last
+ argument to <c>sys:handle_system_msg/6</c> is no longer
+ supported.</item> <item>The error handling when
+ <c>StateFun</c> in <c>sys:replace_state/2,3</c> fails is
+ changed from being totally silent to possibly (if the
+ callback module does not catch) throw an exception in the
+ client process.</item> </list></p>
+ <p>
+ (Thanks to James Fish and Steve Vinoski)</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11817</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Options to set match_limit and match_limit_recursion are
+ added to re:run. The option report_errors is also added
+ to get more information when re:run fails due to limits
+ or compilation errors.</p>
+ <p>
+ Own Id: OTP-10285</p>
+ </item>
+ <item>
+ <p> The pre-defined types <c>array/0</c>, <c>dict/0</c>,
+ <c>digraph/0</c>, <c>gb_set/0</c>, <c>gb_tree/0</c>,
+ <c>queue/0</c>, <c>set/0</c>, and <c>tid/0</c> have been
+ deprecated. They will be removed in Erlang/OTP 18.0. </p>
+ <p> Instead the types <c>array:array/0</c>,
+ <c>dict:dict/0</c>, <c>digraph:graph/0</c>,
+ <c>gb_set:set/0</c>, <c>gb_tree:tree/0</c>,
+ <c>queue:queue/0</c>, <c>sets:set/0</c>, and
+ <c>ets:tid/0</c> can be used. (Note: it has always been
+ necessary to use <c>ets:tid/0</c>.) </p> <p> It is
+ allowed in Erlang/OTP 17.0 to locally re-define the types
+ <c>array/0</c>, <c>dict/0</c>, and so on. </p> <p> New
+ types <c>array:array/1</c>, <c>dict:dict/2</c>,
+ <c>gb_sets:set/1</c>, <c>gb_trees:tree/2</c>,
+ <c>queue:queue/1</c>, and <c>sets:set/1</c> have been
+ added. </p> <p> A compiler option,
+ <c>nowarn_deprecated_type</c>, has been introduced. By
+ including the attribute </p> <c>
+ -compile(nowarn_deprecated_type).</c> <p> in an Erlang
+ source file, warnings about deprecated types can be
+ avoided in Erlang/OTP 17.0. </p> <p> The option can also
+ be given as a compiler flag: </p> <c> erlc
+ +nowarn_deprecated_type file.erl</c>
+ <p>
+ Own Id: OTP-10342</p>
+ </item>
+ <item>
+ <p>
+ Calls to erlang:open_port/2 with 'spawn' are updated to
+ handle space in the command path.</p>
+ <p>
+ Own Id: OTP-10842</p>
+ </item>
+ <item>
+ <p> Dialyzer's <c>unmatched_return</c> warnings have been
+ corrected. </p>
+ <p>
+ Own Id: OTP-10908</p>
+ </item>
+ <item>
+ <p>
+ Forbid unsized fields in patterns of binary generators
+ and simplified v3_core's translation of bit string
+ generators. (Thanks to Anthony Ramine.)</p>
+ <p>
+ Own Id: OTP-11186</p>
+ </item>
+ <item>
+ <p>
+ The version of the PCRE library Used by Erlang's re
+ module is raised to 8.33 from 7.6. This means, among
+ other things, better Unicode and Unicode Character
+ Properties support. New options connected to PCRE 8.33
+ are also added to the re module (ucd, notempty_atstart,
+ no_start_optimize). PCRE has extended the regular
+ expression syntax between 7.6 and 8.33, why this imposes
+ a potential incompatibility. Only very complicated
+ regular expressions may be affected, but if you know you
+ are using obscure features, please test run your regular
+ expressions and verify that their behavior has not
+ changed.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11204</p>
+ </item>
+ <item>
+ <p>
+ Added dict:is_empty/1 and orddict:is_empty/1. (Thanks to
+ Magnus Henoch.)</p>
+ <p>
+ Own Id: OTP-11353</p>
+ </item>
+ <item>
+ <p>
+ A call to either the <c>garbage_collect/1</c> BIF or the
+ <c>check_process_code/2</c> BIF may trigger garbage
+ collection of another processes than the process calling
+ the BIF. The previous implementations performed these
+ kinds of garbage collections without considering the
+ internal state of the process being garbage collected. In
+ order to be able to more easily and more efficiently
+ implement yielding native code, these types of garbage
+ collections have been rewritten. A garbage collection
+ like this is now triggered by an asynchronous request
+ signal, the actual garbage collection is performed by the
+ process being garbage collected itself, and finalized by
+ a reply signal to the process issuing the request. Using
+ this approach processes can disable garbage collection
+ and yield without having to set up the heap in a state
+ that can be garbage collected.</p>
+ <p>
+ The <seealso
+ marker="erts:erlang#garbage_collect/2"><c>garbage_collect/2</c></seealso>,
+ and <seealso
+ marker="erts:erlang#check_process_code/3"><c>check_process_code/3</c></seealso>
+ BIFs have been introduced. Both taking an option list as
+ last argument. Using these, one can issue asynchronous
+ requests.</p>
+ <p>
+ <c>code:purge/1</c> and <c>code:soft_purge/1</c> have
+ been rewritten to utilize asynchronous
+ <c>check_process_code</c> requests in order to
+ parallelize work.</p>
+ <p>
+ Characteristics impact: A call to the
+ <c>garbage_collect/1</c> BIF or the
+ <c>check_process_code/2</c> BIF will normally take longer
+ time to complete while the system as a whole wont be as
+ much negatively effected by the operation as before. A
+ call to <c>code:purge/1</c> and <c>code:soft_purge/1</c>
+ may complete faster or slower depending on the state of
+ the system while the system as a whole wont be as much
+ negatively effected by the operation as before.</p>
+ <p>
+ Own Id: OTP-11388 Aux Id: OTP-11535, OTP-11648 </p>
+ </item>
+ <item>
+ <p> Improve the documentation of the supervisor's
+ <c>via</c> reference. (Thanks to MaximMinin.) </p>
+ <p>
+ Own Id: OTP-11399</p>
+ </item>
+ <item>
+ <p><c>orddict:from_list/1</c> now uses the optimized sort
+ routines in the <c>lists</c> module instead of
+ (essentially) an insertion sort. Depending on the input
+ data, the speed of the new <c>from_list/1</c> is anything
+ from slightly faster up to several orders of magnitude
+ faster than the old <c>from_list/1</c>.</p> (Thanks to
+ Steve Vinoski.)
+ <p>
+ Own Id: OTP-11552</p>
+ </item>
+ <item>
+ <p>
+ EEP43: New data type - Maps</p>
+ <p>
+ With Maps you may for instance: <taglist> <item><c>M0 =
+ #{ a =&gt; 1, b =&gt; 2}, % create
+ associations</c></item> <item><c>M1 = M0#{ a := 10 }, %
+ update values</c></item> <item><c>M2 = M1#{ "hi" =&gt;
+ "hello"}, % add new associations</c></item> <item><c>#{
+ "hi" := V1, a := V2, b := V3} = M2. % match keys with
+ values</c></item> </taglist></p>
+ <p>
+ For information on how to use Maps please see Map Expressions in the
+ <seealso marker="doc/reference_manual:expressions#map_expressions">
+ Reference Manual</seealso>.</p>
+ <p>
+ The current implementation is without the following
+ features: <taglist> <item>No variable keys</item>
+ <item>No single value access</item> <item>No map
+ comprehensions</item> </taglist></p>
+ <p>
+ Note that Maps is <em>experimental</em> during OTP 17.0.</p>
+ <p>
+ Own Id: OTP-11616</p>
+ </item>
+ <item>
+ <p>
+ When tab completing the erlang shell now expands
+ zero-arity functions all the way to closing parenthesis,
+ unless there is another function with the same name and a
+ different arity. (Thanks to Pierre Fenoll.)</p>
+ <p>
+ Own Id: OTP-11684</p>
+ </item>
+ <item>
+ <p> The Erlang Code Preprocessor (<c>epp</c>) could loop
+ when encountering a circular macro definition in an
+ included file. This bug has been fixed. </p> <p> Thanks
+ to Maruthavanan Subbarayan for reporting the bug, and to
+ Richard Carlsson for providing a bug fix. </p>
+ <p>
+ Own Id: OTP-11728</p>
+ </item>
+ <item>
+ <p> The Erlang Code Linter (<c>erl_lint</c>) has since
+ Erlang/OTP R13B emitted warnings whenever any of the
+ types <c>arity()</c>, <c>bitstring()</c>,
+ <c>iodata()</c>, or <c>boolean()</c> were re-defined. Now
+ errors are emitted instead. </p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11771</p>
+ </item>
+ <item>
+ <p> The <c>encoding</c> option of
+ <c>erl_parse:abstract/2</c> has been extended to include
+ <c>none</c> and a callback function (a predicate). </p>
+ <p>
+ Own Id: OTP-11807</p>
+ </item>
+ <item>
+ <p>
+ Export zip option types to allow referal from other
+ modules.</p>
+ <p>
+ Thanks to Pierre Fenoll and Håkan Mattson</p>
+ <p>
+ Own Id: OTP-11828</p>
+ </item>
+ <item>
+ <p>
+ The module <c>pg</c> has been deprecated and will be
+ removed in Erlang/OTP 18.</p>
+ <p>
+ Own Id: OTP-11840</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 1.19.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -1809,7 +2366,7 @@
platforms than before. If <c>configure</c> warns about no
atomic implementation available, try using the
<c>libatomic_ops</c> library. Use the <seealso
- marker="doc/installation_guide:INSTALL#How-to-Build-and-Install-ErlangOTP_A-Closer-Look-at-the-individual-Steps_Configuring">--with-libatomic_ops=PATH</seealso>
+ marker="doc/installation_guide:INSTALL#Advanced-configuration-and-build-of-ErlangOTP">--with-libatomic_ops=PATH</seealso>
<c>configure</c> command line argument when specifying
where the <c>libatomic_ops</c> installation is located.
The <c>libatomic_ops</c> library can be downloaded from:
@@ -1827,7 +2384,7 @@
the pentium 4 processor. If you want the runtime system
to be compatible with older processors (back to 486) you
need to pass the <seealso
- marker="doc/installation_guide:INSTALL#How-to-Build-and-Install-ErlangOTP_A-Closer-Look-at-the-individual-Steps_Configuring">--enable-ethread-pre-pentium4-compatibility</seealso>
+ marker="doc/installation_guide:INSTALL#Advanced-configuration-and-build-of-ErlangOTP">--enable-ethread-pre-pentium4-compatibility</seealso>
<c>configure</c> command line argument when configuring
the system.</p>
<p>
diff --git a/lib/stdlib/doc/src/pg.xml b/lib/stdlib/doc/src/pg.xml
index 7cc1b805b4..a3b69884b6 100644
--- a/lib/stdlib/doc/src/pg.xml
+++ b/lib/stdlib/doc/src/pg.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>1996</year>
- <year>2013</year>
+ <year>2014</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,9 @@
<module>pg</module>
<modulesummary>Distributed, Named Process Groups</modulesummary>
<description>
+ <warning>
+ <p>This module is deprecated and will be removed in Erlang/OTP 18.</p>
+ </warning>
<p>This (experimental) module implements process groups. A process
group is a group of processes that can be accessed by a common
name. For example, a group named <c>foobar</c> can include a set
diff --git a/lib/stdlib/doc/src/string.xml b/lib/stdlib/doc/src/string.xml
index c96cc95a44..b05d5cbc08 100644
--- a/lib/stdlib/doc/src/string.xml
+++ b/lib/stdlib/doc/src/string.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -124,6 +124,10 @@
<code type="none">
> tokens("abc defxxghix jkl", "x ").
["abc", "def", "ghi", "jkl"] </code>
+ <p>Note that, as shown in the example above, two or more
+ adjacent separator characters in <c><anno>String</anno></c>
+ will be treated as one. That is, there will not be any empty
+ strings in the resulting list of tokens.</p>
</desc>
</func>
<func>
diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml
index a46fa1289f..19605f325b 100644
--- a/lib/stdlib/doc/src/sys.xml
+++ b/lib/stdlib/doc/src/sys.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -115,6 +115,9 @@
<datatype>
<name name="dbg_fun"/>
</datatype>
+ <datatype>
+ <name name="format_fun"/>
+ </datatype>
</datatypes>
<funcs>
<func>
diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml
index 66c21da193..48b376743d 100644
--- a/lib/stdlib/doc/src/zip.xml
+++ b/lib/stdlib/doc/src/zip.xml
@@ -123,6 +123,18 @@
</taglist>
</desc>
</datatype>
+ <datatype>
+ <name name="filename"/>
+ <p>The name of a zip file.</p>
+ </datatype>
+ <datatype><name name="extension"/></datatype>
+ <datatype><name name="extension_spec"/></datatype>
+ <datatype>
+ <name name="create_option"/>
+ <desc>
+ <p>These options are described in <seealso marker="#zip_options">create/3</seealso>.</p>
+ </desc>
+ </datatype>
</datatypes>
<funcs>
<func>
@@ -160,6 +172,7 @@
set to <c>["gif", "jpg"]</c> and <c>uncompress</c> is set to
<c>["jpg"]</c>, only files with <c>"gif"</c> as extension will
be compressed. No other files will be compressed.</p>
+ <marker id="zip_options"></marker>
<p>The following options are available:</p>
<taglist>
<tag><c>cooked</c></tag>
diff --git a/lib/stdlib/examples/erl_id_trans.erl b/lib/stdlib/examples/erl_id_trans.erl
index 5fcb74310e..e71e26e51a 100644
--- a/lib/stdlib/examples/erl_id_trans.erl
+++ b/lib/stdlib/examples/erl_id_trans.erl
@@ -148,7 +148,7 @@ pattern({map,Line,Ps0}) ->
Ps1 = pattern_list(Ps0),
{map,Line,Ps1};
pattern({map_field_exact,Line,K,V}) ->
- Ke = pattern(K),
+ Ke = expr(K),
Ve = pattern(V),
{map_field_exact,Line,Ke,Ve};
%%pattern({struct,Line,Tag,Ps0}) ->
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index c32da1624f..76e03bbfaa 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -440,9 +440,10 @@ insert(Tab, Objs) when is_list(Objs) ->
insert(Tab, Obj) ->
badarg(treq(Tab, {insert, [Obj]}), [Tab, Obj]).
--spec insert_new(Name, Objects) -> boolean() when
+-spec insert_new(Name, Objects) -> boolean() | {'error', Reason} when
Name :: tab_name(),
- Objects :: object() | [object()].
+ Objects :: object() | [object()],
+ Reason :: term().
insert_new(Tab, Objs) when is_list(Objs) ->
badarg(treq(Tab, {insert_new, Objs}), [Tab, Objs]);
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 9b506b0a44..5f8637c118 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -1121,8 +1121,20 @@ skip_toks(From, St, [I|Sis]) ->
skip_toks(From, St#epp{location=Cl}, Sis);
{ok,_Toks,Cl} ->
skip_toks(From, St#epp{location=Cl}, [I|Sis]);
- {error,_E,Cl} ->
- skip_toks(From, St#epp{location=Cl}, [I|Sis]);
+ {error,E,Cl} ->
+ case E of
+ {_,file_io_server,invalid_unicode} ->
+ %% The compiler needs to know that there was
+ %% invalid unicode characters in the file
+ %% (and there is no point in continuing anyway
+ %% since io server process has terminated).
+ epp_reply(From, {error,E}),
+ leave_file(wait_request(St), St);
+ _ ->
+ %% Some other invalid token, such as a bad floating
+ %% point number. Just ignore it.
+ skip_toks(From, St#epp{location=Cl}, [I|Sis])
+ end;
{eof,Cl} ->
leave_file(From, St#epp{location=Cl,istk=[I|Sis]});
{error,_E} ->
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index acde3ad5d6..639ddfc214 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -77,7 +77,7 @@
%% Only exprs/2 checks the command by calling erl_lint. The reason is
%% that if there is a function handler present, then it is possible
%% that there are valid constructs in Expression to be taken care of
-%% by a function handler but considerad errors by erl_lint.
+%% by a function handler but considered errors by erl_lint.
-spec(exprs(Expressions, Bindings) -> {value, Value, NewBindings} when
Expressions :: expressions(),
@@ -244,17 +244,17 @@ expr({record,_,_,Name,_}, _Bs, _Lf, _Ef, _RBs) ->
erlang:raise(error, {undef_record,Name}, stacktrace());
%% map
-expr({map,_, Binding,Es}, Bs0, Lf, Ef, RBs) ->
- {value, Map0, Bs1} = expr(Binding, Bs0, Lf, Ef, RBs),
+expr({map,_,Binding,Es}, Bs0, Lf, Ef, RBs) ->
+ {value, Map0, Bs1} = expr(Binding, Bs0, Lf, Ef, none),
case Map0 of
#{} ->
- {Vs,Bs} = eval_map_fields(Es, Bs1, Lf, Ef),
+ {Vs,Bs2} = eval_map_fields(Es, Bs0, Lf, Ef),
Map1 = lists:foldl(fun ({map_assoc,K,V}, Mi) ->
maps:put(K, V, Mi);
({map_exact,K,V}, Mi) ->
maps:update(K, V, Mi)
end, Map0, Vs),
- ret_expr(Map1, Bs, RBs);
+ ret_expr(Map1, merge_bindings(Bs2, Bs1), RBs);
_ ->
erlang:raise(error, {badarg,Map0}, stacktrace())
end;
diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl
index f53c6e1278..c74f68647f 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-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2014. 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
@@ -38,6 +38,8 @@
checked_ra=[] % successfully accessed records
}).
+-define(REC_OFFSET, 100000000). % A hundred millions. Also in v3_core.
+
-spec(module(AbsForms, CompileOptions) -> AbsForms when
AbsForms :: [erl_parse:abstract_form()],
CompileOptions :: [compile:option()]).
@@ -135,19 +137,20 @@ pattern({tuple,Line,Ps}, St0) ->
pattern({map,Line,Ps}, St0) ->
{TPs,St1} = pattern_list(Ps, St0),
{{map,Line,TPs},St1};
-pattern({map_field_exact,Line,Key0,V0}, St0) ->
- {Key,St1} = pattern(Key0, St0),
+pattern({map_field_exact,Line,K0,V0}, St0) ->
+ {K,St1} = expr(K0, St0),
{V,St2} = pattern(V0, St1),
- {{map_field_exact,Line,Key,V},St2};
+ {{map_field_exact,Line,K,V},St2};
%%pattern({struct,Line,Tag,Ps}, St0) ->
%% {TPs,TPsvs,St1} = pattern_list(Ps, St0),
%% {{struct,Line,Tag,TPs},TPsvs,St1};
pattern({record_index,Line,Name,Field}, St) ->
{index_expr(Line, Field, Name, record_fields(Name, St)),St};
-pattern({record,Line,Name,Pfs}, St0) ->
+pattern({record,Line0,Name,Pfs}, St0) ->
Fs = record_fields(Name, St0),
{TMs,St1} = pattern_list(pattern_fields(Fs, Pfs), St0),
- {{tuple,Line,[{atom,Line,Name} | TMs]},St1};
+ Line = record_offset(Line0, St1),
+ {{tuple,Line,[{atom,Line0,Name} | TMs]},St1};
pattern({bin,Line,Es0}, St0) ->
{Es1,St1} = pattern_bin(Es0, St0),
{{bin,Line,Es1},St1};
@@ -329,8 +332,9 @@ expr({map_field_exact,Line,K0,V0}, St0) ->
expr({record_index,Line,Name,F}, St) ->
I = index_expr(Line, F, Name, record_fields(Name, St)),
expr(I, St);
-expr({record,Line,Name,Is}, St) ->
- expr({tuple,Line,[{atom,Line,Name} |
+expr({record,Line0,Name,Is}, St) ->
+ Line = record_offset(Line0, St),
+ expr({tuple,Line,[{atom,Line0,Name} |
record_inits(record_fields(Name, St), Is)]},
St);
expr({record_field,Line,R,Name,F}, St) ->
@@ -582,8 +586,9 @@ strict_get_record_field(Line, R, {atom,_,F}=Index, Name, St0) ->
I = index_expr(F, Fs, 2),
P = record_pattern(2, I, Var, length(Fs)+1, Line, [{atom,Line,Name}]),
NLine = neg_line(Line),
+ RLine = record_offset(NLine, St),
E = {'case',NLine,R,
- [{clause,NLine,[{tuple,NLine,P}],[],[Var]},
+ [{clause,NLine,[{tuple,RLine,P}],[],[Var]},
{clause,NLine,[{var,NLine,'_'}],[],
[{call,NLine,{remote,NLine,
{atom,NLine,erlang},
@@ -836,7 +841,7 @@ optimize_is_record(H0, G0, #exprec{compile=Opts}) ->
[] ->
{H0,G0};
Rs0 ->
- case lists:member(no_is_record_optimization, Opts) of
+ case lists:member(dialyzer, Opts) of % no_is_record_optimization
true ->
{H0,G0};
false ->
@@ -961,3 +966,10 @@ opt_remove_2(A, _) -> A.
neg_line(L) ->
erl_parse:set_line(L, fun(Line) -> -abs(Line) end).
+
+record_offset(L, St) ->
+ case lists:member(dialyzer, St#exprec.compile) of
+ true when L >= 0 -> L+?REC_OFFSET;
+ true when L < 0 -> L-?REC_OFFSET;
+ false -> L
+ end.
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index c4c94fbee4..39cc03cf7a 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -1046,9 +1046,10 @@ check_undefined_types(#lint{usage=Usage,types=Def}=St0) ->
Used = Usage#usage.used_types,
UTAs = dict:fetch_keys(Used),
Undef = [{TA,dict:fetch(TA, Used)} ||
- TA <- UTAs,
+ {T,_}=TA <- UTAs,
not dict:is_key(TA, Def),
- not is_default_type(TA)],
+ not is_default_type(TA),
+ not is_newly_introduced_var_arity_type(T)],
foldl(fun ({TA,L}, St) ->
add_error(L, {undefined_type,TA}, St)
end, St0, Undef).
@@ -1407,7 +1408,7 @@ pattern({map,_Line,Ps}, Vt, Old, Bvt, St) ->
({map_field_assoc,L,_,_}, {Psvt,Bvt0,St0}) ->
{Psvt,Bvt0,add_error(L, illegal_pattern, St0)};
({map_field_exact,L,KP,VP}, {Psvt,Bvt0,St0}) ->
- case is_valid_map_key(KP, St0) of
+ case is_valid_map_key(KP, pattern, St0) of
true ->
{Pvt,Bvt1,St1} = pattern(VP, Vt, Old, Bvt, St0),
{vtmerge_pat(Pvt, Psvt),vtmerge_pat(Bvt0, Bvt1), St1};
@@ -2322,14 +2323,16 @@ is_valid_call(Call) ->
%% check for value expression without variables
is_valid_map_key(K,St) ->
+ is_valid_map_key(K,expr,St).
+is_valid_map_key(K,Ctx,St) ->
case expr(K,[],St) of
{[],_} ->
- is_valid_map_key_value(K);
+ is_valid_map_key_value(K,Ctx);
{[Var|_],_} ->
{false,variable,element(1,Var)}
end.
-is_valid_map_key_value(K) ->
+is_valid_map_key_value(K,Ctx) ->
case K of
{char,_,_} -> true;
{integer,_,_} -> true;
@@ -2338,34 +2341,36 @@ is_valid_map_key_value(K) ->
{nil,_} -> true;
{atom,_,_} -> true;
{cons,_,H,T} ->
- is_valid_map_key_value(H) andalso
- is_valid_map_key_value(T);
+ is_valid_map_key_value(H,Ctx) andalso
+ is_valid_map_key_value(T,Ctx);
{tuple,_,Es} ->
foldl(fun(E,B) ->
- B andalso is_valid_map_key_value(E)
+ B andalso is_valid_map_key_value(E,Ctx)
end,true,Es);
{map,_,Arg,Ps} ->
% only check for value expressions to be valid
% invalid map expressions are later checked in
% core and kernel
- is_valid_map_key_value(Arg) andalso foldl(fun
+ is_valid_map_key_value(Arg,Ctx) andalso foldl(fun
({Tag,_,Ke,Ve},B) when Tag =:= map_field_assoc;
- Tag =:= map_field_exact ->
- B andalso is_valid_map_key_value(Ke)
- andalso is_valid_map_key_value(Ve)
+ Tag =:= map_field_exact, Ctx =:= expr ->
+ B andalso is_valid_map_key_value(Ke,Ctx)
+ andalso is_valid_map_key_value(Ve,Ctx);
+ (_,_) -> false
end,true,Ps);
{map,_,Ps} ->
foldl(fun
({Tag,_,Ke,Ve},B) when Tag =:= map_field_assoc;
- Tag =:= map_field_exact ->
- B andalso is_valid_map_key_value(Ke)
- andalso is_valid_map_key_value(Ve)
+ Tag =:= map_field_exact, Ctx =:= expr ->
+ B andalso is_valid_map_key_value(Ke,Ctx)
+ andalso is_valid_map_key_value(Ve,Ctx);
+ (_,_) -> false
end, true, Ps);
{record,_,_,Fs} ->
foldl(fun
({record_field,_,Ke,Ve},B) ->
- B andalso is_valid_map_key_value(Ke)
- andalso is_valid_map_key_value(Ve)
+ B andalso is_valid_map_key_value(Ke,Ctx)
+ andalso is_valid_map_key_value(Ve,Ctx)
end,true,Fs);
{bin,_,Es} ->
% only check for value expressions to be valid
@@ -2373,7 +2378,7 @@ is_valid_map_key_value(K) ->
% core and kernel
foldl(fun
({bin_element,_,E,_,_},B) ->
- B andalso is_valid_map_key_value(E)
+ B andalso is_valid_map_key_value(E,Ctx)
end,true,Es);
_ -> false
end.
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 1dc5fc52a7..e1ae3b7aea 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -848,10 +848,12 @@ build_fun(Line, Cs) ->
end.
check_clauses(Cs, Name, Arity) ->
- mapl(fun ({clause,L,N,As,G,B}) when N =:= Name, length(As) =:= Arity ->
- {clause,L,As,G,B};
- ({clause,L,_N,_As,_G,_B}) ->
- ret_err(L, "head mismatch") end, Cs).
+ [case C of
+ {clause,L,N,As,G,B} when N =:= Name, length(As) =:= Arity ->
+ {clause,L,As,G,B};
+ {clause,L,_N,_As,_G,_B} ->
+ ret_err(L, "head mismatch")
+ end || C <- Cs].
build_try(L,Es,Scs,{Ccs,As}) ->
{'try',L,Es,Scs,Ccs,As}.
@@ -861,17 +863,6 @@ ret_err(L, S) ->
{location,Location} = get_attribute(L, location),
return_error(Location, S).
-%% mapl(F,List)
-%% an alternative map which always maps from left to right
-%% and makes it possible to interrupt the mapping with throw on
-%% the first occurence from left as expected.
-%% can be removed when the jam machine (and all other machines)
-%% uses the standardized (Erlang 5.0) evaluation order (from left to right)
-mapl(F, [H|T]) ->
- V = F(H),
- [V | mapl(F,T)];
-mapl(_, []) ->
- [].
%% Convert between the abstract form of a term and a term.
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 9dbe89da91..3dbb5ab64c 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -256,6 +256,10 @@ ltype({type,_Line,nonempty_list,[T]}) ->
{seq,$[,$],[$,],[ltype(T),leaf("...")]};
ltype({type,Line,nil,[]}) ->
lexpr({nil,Line}, 0, options(none));
+ltype({type,Line,map,any}) ->
+ simple_type({atom,Line,map}, []);
+ltype({type,_Line,map,Pairs}) ->
+ map_type(Pairs);
ltype({type,Line,tuple,any}) ->
simple_type({atom,Line,tuple}, []);
ltype({type,_Line,tuple,Ts}) ->
@@ -289,6 +293,23 @@ binary_type(I1, I2) ->
E2 = [[leaf("_:_*"),lexpr(I2, P, options(none))] || U],
{seq,'<<','>>',[$,],E1++E2}.
+map_type(Fs) ->
+ {first,[$#],map_pair_types(Fs)}.
+
+map_pair_types(Fs) ->
+ tuple_type(Fs, fun map_pair_type/1).
+
+map_pair_type({type,_Line,map_field_assoc,Ktype,Vtype}) ->
+ map_assoc_typed(lexpr(Ktype, options(none)), Vtype).
+
+map_assoc_typed(B, {type,_,union,Ts}) ->
+ {first,[B,$\s],{seq,[],[],[],map_assoc_union_type(Ts)}};
+map_assoc_typed(B, Type) ->
+ {list,[{cstep,[B," =>"],ltype(Type)}]}.
+
+map_assoc_union_type([T|Ts]) ->
+ [[leaf("=> "),ltype(T)] | ltypes(Ts, fun union_elem/1)].
+
record_type(Name, Fields) ->
{first,[record_name(Name)],field_types(Fields)}.
diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl
index ae59d5f44f..6fd6bb888b 100644
--- a/lib/stdlib/src/erl_scan.erl
+++ b/lib/stdlib/src/erl_scan.erl
@@ -1075,7 +1075,7 @@ scan_number([$#|Cs]=Cs0, St, Line, Col, Toks, Ncs0) ->
Ncs = lists:reverse(Ncs0),
case catch list_to_integer(Ncs) of
B when B >= 2, B =< 1+$Z-$A+10 ->
- Bcs = ?STR(St, Ncs++[$#]),
+ Bcs = Ncs++[$#],
scan_based_int(Cs, St, Line, Col, Toks, {B,[],Bcs});
B ->
Len = length(Ncs),
@@ -1108,7 +1108,7 @@ scan_based_int(Cs, St, Line, Col, Toks, {B,Ncs0,Bcs}) ->
Ncs = lists:reverse(Ncs0),
case catch erlang:list_to_integer(Ncs, B) of
N when is_integer(N) ->
- tok3(Cs, St, Line, Col, Toks, integer, ?STR(St, Bcs++Ncs), N);
+ tok3(Cs, St, Line, Col, Toks, integer, Bcs++Ncs, N);
_ ->
Len = length(Bcs)+length(Ncs),
Ncol = incr_column(Col, Len),
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index 40b48d7999..acf7a5cd40 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -381,7 +381,12 @@ to_octal(Int, Count, Result) ->
to_octal(Int div 8, Count-1, [Int rem 8 + $0|Result]).
to_string(Str0, Count) ->
- Str = list_to_binary(Str0),
+ Str = case file:native_name_encoding() of
+ utf8 ->
+ unicode:characters_to_binary(Str0);
+ latin1 ->
+ list_to_binary(Str0)
+ end,
case byte_size(Str) of
Size when Size < Count ->
[Str|zeroes(Count-Size)];
@@ -392,9 +397,17 @@ to_string(Str0, Count) ->
pad_file(File) ->
{ok,Position} = file:position(File, {cur,0}),
- %% There must be at least one empty record at the end of the file.
- Zeros = zeroes(?block_size - (Position rem ?block_size)),
- file:write(File, Zeros).
+ %% There must be at least two zero records at the end.
+ Fill = case ?block_size - (Position rem ?block_size) of
+ Fill0 when Fill0 < 2*?record_size ->
+ %% We need to another block here to ensure that there
+ %% are at least two zero records at the end.
+ Fill0 + ?block_size;
+ Fill0 ->
+ %% Large enough.
+ Fill0
+ end,
+ file:write(File, zeroes(Fill)).
split_filename(Name) when length(Name) =< ?th_name_len ->
{"", Name};
@@ -608,7 +621,22 @@ typeflag(Bin) ->
%% Get the name of the file from the prefix and name fields of the
%% tar header.
-get_name(Bin) ->
+get_name(Bin0) ->
+ List0 = get_name_raw(Bin0),
+ case file:native_name_encoding() of
+ utf8 ->
+ Bin = list_to_binary(List0),
+ case unicode:characters_to_list(Bin) of
+ {error,_,_} ->
+ List0;
+ List when is_list(List) ->
+ List
+ end;
+ latin1 ->
+ List0
+ end.
+
+get_name_raw(Bin) ->
Name = from_string(Bin, ?th_name, ?th_name_len),
case binary_to_list(Bin, ?th_prefix+1, ?th_prefix+1) of
[0] ->
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index a8a82272d6..6bd0eb8a22 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -59,7 +59,6 @@
file:filename()
| {file:filename(), binary()}
| {file:filename(), binary(), file:file_info()}.
--type zip_create_option() :: term().
-type section() ::
shebang
| {shebang, shebang() | default | undefined}
@@ -68,8 +67,8 @@
| {emu_args, emu_args() | undefined}
| {source, file:filename() | binary()}
| {beam, file:filename() | binary()}
- | {archive, file:filename() | binary()}
- | {archive, [zip_file()], [zip_create_option()]}.
+ | {archive, zip:filename() | binary()}
+ | {archive, [zip_file()], [zip:create_option()]}.
%%-----------------------------------------------------------------------
diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl
index a266daa084..9efbe8da20 100644
--- a/lib/stdlib/src/filelib.erl
+++ b/lib/stdlib/src/filelib.erl
@@ -265,7 +265,7 @@ do_wildcard(Pattern, Cwd, Mod) ->
lists:sort(Files).
do_wildcard_1({exists,File}, Mod) ->
- case eval_read_file_info(File, Mod) of
+ case eval_read_link_info(File, Mod) of
{ok,_} -> [File];
_ -> []
end;
@@ -497,6 +497,16 @@ eval_read_file_info(File, erl_prim_loader) ->
eval_read_file_info(File, Mod) ->
Mod:read_file_info(File).
+eval_read_link_info(File, file) ->
+ file:read_link_info(File);
+eval_read_link_info(File, erl_prim_loader) ->
+ case erl_prim_loader:read_link_info(File) of
+ error -> {error, erl_prim_loader};
+ Res-> Res
+ end;
+eval_read_link_info(File, Mod) ->
+ Mod:read_link_info(File).
+
eval_list_dir(Dir, file) ->
file:list_dir(Dir);
eval_list_dir(Dir, erl_prim_loader) ->
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index e914f7d0b2..5afe3e8b09 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. 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
@@ -594,7 +594,8 @@ reply(Name, {To, Tag}, Reply, Debug, StateName) ->
terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) ->
case catch Mod:terminate(Reason, StateName, StateData) of
{'EXIT', R} ->
- error_info(R, Name, Msg, StateName, StateData, Debug),
+ FmtStateData = format_status(terminate, Mod, get(), StateData),
+ error_info(R, Name, Msg, StateName, FmtStateData, Debug),
exit(R);
_ ->
case Reason of
@@ -605,17 +606,7 @@ terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) ->
{shutdown,_}=Shutdown ->
exit(Shutdown);
_ ->
- FmtStateData =
- case erlang:function_exported(Mod, format_status, 2) of
- true ->
- Args = [get(), StateData],
- case catch Mod:format_status(terminate, Args) of
- {'EXIT', _} -> StateData;
- Else -> Else
- end;
- _ ->
- StateData
- end,
+ FmtStateData = format_status(terminate, Mod, get(), StateData),
error_info(Reason,Name,Msg,StateName,FmtStateData,Debug),
exit(Reason)
end
@@ -680,21 +671,29 @@ format_status(Opt, StatusData) ->
Header = gen:format_status_header("Status for state machine",
Name),
Log = sys:get_debug(log, Debug, []),
- DefaultStatus = [{data, [{"StateData", StateData}]}],
- Specfic =
- case erlang:function_exported(Mod, format_status, 2) of
- true ->
- case catch Mod:format_status(Opt,[PDict,StateData]) of
- {'EXIT', _} -> DefaultStatus;
- StatusList when is_list(StatusList) -> StatusList;
- Else -> [Else]
- end;
- _ ->
- DefaultStatus
- end,
+ Specfic = format_status(Opt, Mod, PDict, StateData),
+ Specfic = case format_status(Opt, Mod, PDict, StateData) of
+ S when is_list(S) -> S;
+ S -> [S]
+ end,
[{header, Header},
{data, [{"Status", SysState},
{"Parent", Parent},
{"Logged events", Log},
{"StateName", StateName}]} |
Specfic].
+
+format_status(Opt, Mod, PDict, State) ->
+ DefStatus = case Opt of
+ terminate -> State;
+ _ -> [{data, [{"StateData", State}]}]
+ end,
+ case erlang:function_exported(Mod, format_status, 2) of
+ true ->
+ case catch Mod:format_status(Opt, [PDict, State]) of
+ {'EXIT', _} -> DefStatus;
+ Else -> Else
+ end;
+ _ ->
+ DefStatus
+ end.
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 202a931fae..dadfe56b3d 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. 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
@@ -720,7 +720,8 @@ print_event(Dev, Event, Name) ->
terminate(Reason, Name, Msg, Mod, State, Debug) ->
case catch Mod:terminate(Reason, State) of
{'EXIT', R} ->
- error_info(R, Name, Msg, State, Debug),
+ FmtState = format_status(terminate, Mod, get(), State),
+ error_info(R, Name, Msg, FmtState, Debug),
exit(R);
_ ->
case Reason of
@@ -731,17 +732,7 @@ terminate(Reason, Name, Msg, Mod, State, Debug) ->
{shutdown,_}=Shutdown ->
exit(Shutdown);
_ ->
- FmtState =
- case erlang:function_exported(Mod, format_status, 2) of
- true ->
- Args = [get(), State],
- case catch Mod:format_status(terminate, Args) of
- {'EXIT', _} -> State;
- Else -> Else
- end;
- _ ->
- State
- end,
+ FmtState = format_status(terminate, Mod, get(), State),
error_info(Reason, Name, Msg, FmtState, Debug),
exit(Reason)
end
@@ -875,23 +866,29 @@ name_to_pid(Name) ->
%%-----------------------------------------------------------------
format_status(Opt, StatusData) ->
[PDict, SysState, Parent, Debug, [Name, State, Mod, _Time]] = StatusData,
- Header = gen:format_status_header("Status for generic server",
- Name),
+ Header = gen:format_status_header("Status for generic server", Name),
Log = sys:get_debug(log, Debug, []),
- DefaultStatus = [{data, [{"State", State}]}],
- Specfic =
- case erlang:function_exported(Mod, format_status, 2) of
- true ->
- case catch Mod:format_status(Opt, [PDict, State]) of
- {'EXIT', _} -> DefaultStatus;
- StatusList when is_list(StatusList) -> StatusList;
- Else -> [Else]
- end;
- _ ->
- DefaultStatus
- end,
+ Specfic = case format_status(Opt, Mod, PDict, State) of
+ S when is_list(S) -> S;
+ S -> [S]
+ end,
[{header, Header},
{data, [{"Status", SysState},
{"Parent", Parent},
{"Logged events", Log}]} |
Specfic].
+
+format_status(Opt, Mod, PDict, State) ->
+ DefStatus = case Opt of
+ terminate -> State;
+ _ -> [{data, [{"State", State}]}]
+ end,
+ case erlang:function_exported(Mod, format_status, 2) of
+ true ->
+ case catch Mod:format_status(Opt, [PDict, State]) of
+ {'EXIT', _} -> DefStatus;
+ Else -> Else
+ end;
+ _ ->
+ DefStatus
+ end.
diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index 56e15a17ec..89ae6fb187 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -255,7 +255,7 @@ term(T, none, _Adj, none, _Pad) -> T;
term(T, none, Adj, P, Pad) -> term(T, P, Adj, P, Pad);
term(T, F, Adj, P0, Pad) ->
L = lists:flatlength(T),
- P = case P0 of none -> erlang:min(L, F); _ -> P0 end,
+ P = erlang:min(L, case P0 of none -> F; _ -> min(P0, F) end),
if
L > P ->
adjust(chars($*, P), chars(Pad, F-P), Adj);
diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl
index 4057abd8d5..aece06afa6 100644
--- a/lib/stdlib/src/io_lib_pretty.erl
+++ b/lib/stdlib/src/io_lib_pretty.erl
@@ -25,8 +25,6 @@
-export([print/1,print/2,print/3,print/4,print/5,print/6]).
--compile(no_native).
-
%%%
%%% Exported functions
%%%
diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl
index 1f94d9e69d..ba4d6a5c87 100644
--- a/lib/stdlib/src/maps.erl
+++ b/lib/stdlib/src/maps.erl
@@ -23,7 +23,9 @@
fold/3,
map/2,
size/1,
- without/2
+ without/2,
+ with/2,
+ get/3
]).
@@ -43,8 +45,6 @@
values/1
]).
--compile(no_native).
-
-spec get(Key,Map) -> Value when
Key :: term(),
Map :: map(),
@@ -134,16 +134,31 @@ to_list(_) -> erlang:nif_error(undef).
update(_,_,_) -> erlang:nif_error(undef).
--spec values(Map) -> Keys when
+-spec values(Map) -> Values when
Map :: map(),
- Keys :: [Key],
- Key :: term().
+ Values :: [Value],
+ Value :: term().
values(_) -> erlang:nif_error(undef).
%%% End of BIFs
+-spec get(Key, Map, Default) -> Value | Default when
+ Key :: term(),
+ Map :: map(),
+ Value :: term(),
+ Default :: term().
+
+get(Key, Map, Default) ->
+ case maps:find(Key, Map) of
+ {ok, Value} ->
+ Value;
+ error ->
+ Default
+ end.
+
+
-spec fold(Fun,Init,Map) -> Acc when
Fun :: fun((K, V, AccIn) -> AccOut),
Init :: term(),
@@ -187,3 +202,13 @@ size(Map) when is_map(Map) ->
without(Ks, M) when is_list(Ks), is_map(M) ->
maps:from_list([{K,V}||{K,V} <- maps:to_list(M), not lists:member(K, Ks)]).
+
+
+-spec with(Ks, Map1) -> Map2 when
+ Ks :: [K],
+ Map1 :: map(),
+ Map2 :: map(),
+ K :: term().
+
+with(Ks, M) when is_list(Ks), is_map(M) ->
+ maps:from_list([{K,V}||{K,V} <- maps:to_list(M), lists:member(K, Ks)]).
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 380bc3eccc..6c25beabe9 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2014. 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
@@ -83,18 +83,18 @@ obsolete_1(crypto, sha_init, 0) ->
{deprecated, {crypto, hash_init, 1}};
obsolete_1(crypto, md4_update, 2) ->
- {deprecated, {crypto, hash_update, 3}};
+ {deprecated, {crypto, hash_update, 2}};
obsolete_1(crypto, md5_update, 2) ->
- {deprecated, {crypto, hash_update, 3}};
+ {deprecated, {crypto, hash_update, 2}};
obsolete_1(crypto, sha_update, 2) ->
- {deprecated, {crypto, hash_update, 3}};
+ {deprecated, {crypto, hash_update, 2}};
obsolete_1(crypto, md4_final, 1) ->
- {deprecated, {crypto, hash_final, 2}};
+ {deprecated, {crypto, hash_final, 1}};
obsolete_1(crypto, md5_final, 1) ->
- {deprecated, {crypto, hash_final, 2}};
+ {deprecated, {crypto, hash_final, 1}};
obsolete_1(crypto, sha_final, 1) ->
- {deprecated, {crypto, hash_final, 2}};
+ {deprecated, {crypto, hash_final, 1}};
obsolete_1(crypto, md5_mac, 2) ->
{deprecated, {crypto, hmac, 3}};
@@ -104,9 +104,9 @@ obsolete_1(crypto, sha_mac, 3) ->
{deprecated, {crypto, hmac, 4}};
obsolete_1(crypto, sha_mac_96, 2) ->
- {deprecated, {crypto, hmac_n, 3}};
+ {deprecated, {crypto, hmac, 4}};
obsolete_1(crypto, md5_mac_96, 2) ->
- {deprecated, {crypto, hmac_n, 3}};
+ {deprecated, {crypto, hmac, 4}};
obsolete_1(crypto, rsa_sign, 2) ->
{deprecated, {crypto, sign, 4}};
@@ -123,9 +123,9 @@ obsolete_1(crypto, dss_sign, 3) ->
{deprecated, {crypto, sign, 4}};
obsolete_1(crypto, dss_verify, 3) ->
- {deprecated, {crypto, verify, 4}};
+ {deprecated, {crypto, verify, 5}};
obsolete_1(crypto, dss_verify, 4) ->
- {deprecated, {crypto, verify, 4}};
+ {deprecated, {crypto, verify, 5}};
obsolete_1(crypto, mod_exp, 3) ->
{deprecated, {crypto, mod_pow, 3}};
@@ -133,7 +133,7 @@ obsolete_1(crypto, mod_exp, 3) ->
obsolete_1(crypto, dh_compute_key, 3) ->
{deprecated, {crypto, compute_key, 4}};
obsolete_1(crypto, dh_generate_key, 1) ->
- {deprecated, {crypto, generate_key, 3}};
+ {deprecated, {crypto, generate_key, 2}};
obsolete_1(crypto, dh_generate_key, 2) ->
{deprecated, {crypto, generate_key, 3}};
@@ -250,12 +250,12 @@ obsolete_1(snmp, N, A) ->
false ->
no;
true ->
- {deprecated, "Deprecated (will be removed in R17B); use snmpa:"++atom_to_list(N)++"/"++
+ {deprecated, "Deprecated (will be removed in OTP 18); use snmpa:"++atom_to_list(N)++"/"++
integer_to_list(A)++" instead"}
end;
obsolete_1(snmpa, old_info_format, 1) ->
- {deprecated, "Deprecated; (will be removed in R17B); use \"new\" format instead"};
+ {deprecated, "Deprecated; (will be removed in OTP 18); use \"new\" format instead"};
obsolete_1(snmpm, agent_info, 3) ->
{removed, {snmpm, agent_info, 2}, "R16B"};
obsolete_1(snmpm, update_agent_info, 5) ->
@@ -366,23 +366,6 @@ obsolete_1(auth, node_cookie, 1) ->
obsolete_1(auth, node_cookie, 2) ->
{deprecated, "Deprecated; use erlang:set_cookie/2 and net_adm:ping/1 instead"};
-obsolete_1(erlang, is_constant, 1) ->
- {removed, "Removed in R13B"};
-
-%% Added in R12B-0.
-obsolete_1(ssl, port, 1) ->
- {removed, {ssl, sockname, 1}, "R13B"};
-obsolete_1(ssl, accept, A) when A =:= 1; A =:= 2 ->
- {removed, "deprecated; use ssl:transport_accept/1,2 and ssl:ssl_accept/1,2"};
-obsolete_1(erlang, fault, 1) ->
- {removed, {erlang,error,1}, "R13B"};
-obsolete_1(erlang, fault, 2) ->
- {removed, {erlang,error,2}, "R13B"};
-
-%% Added in R12B-2.
-obsolete_1(file, rawopen, 2) ->
- {removed, "deprecated (will be removed in R13B); use file:open/2 with the raw option"};
-
obsolete_1(http, request, 1) -> {removed,{httpc,request,1},"R15B"};
obsolete_1(http, request, 2) -> {removed,{httpc,request,2},"R15B"};
obsolete_1(http, request, 4) -> {removed,{httpc,request,4},"R15B"};
@@ -438,13 +421,13 @@ obsolete_1(ssh_cm, stop_listener, 1) ->
obsolete_1(ssh_cm, session_open, A) when A =:= 2; A =:= 4 ->
{removed,{ssh_connection,session_channel,A},"R14B"};
obsolete_1(ssh_cm, direct_tcpip, A) when A =:= 6; A =:= 8 ->
- {removed,{ssh_connection,direct_tcpip,A}};
+ {removed,{ssh_connection,direct_tcpip,A},"R14B"};
obsolete_1(ssh_cm, tcpip_forward, 3) ->
{removed,{ssh_connection,tcpip_forward,3},"R14B"};
obsolete_1(ssh_cm, cancel_tcpip_forward, 3) ->
{removed,{ssh_connection,cancel_tcpip_forward,3},"R14B"};
obsolete_1(ssh_cm, open_pty, A) when A =:= 3; A =:= 7; A =:= 9 ->
- {removed,{ssh_connection,open_pty,A},"R14"};
+ {removed,{ssh_connection,open_pty,A},"R14B"};
obsolete_1(ssh_cm, setenv, 5) ->
{removed,{ssh_connection,setenv,5},"R14B"};
obsolete_1(ssh_cm, shell, 2) ->
@@ -458,11 +441,11 @@ obsolete_1(ssh_cm, winch, A) when A =:= 4; A =:= 6 ->
obsolete_1(ssh_cm, signal, 3) ->
{removed,{ssh_connection,signal,3},"R14B"};
obsolete_1(ssh_cm, attach, A) when A =:= 2; A =:= 3 ->
- {removed,{ssh,attach,A}};
+ {removed,"no longer useful; removed in R14B"};
obsolete_1(ssh_cm, detach, 2) ->
- {removed,"no longer useful; will be removed in R14B"};
+ {removed,"no longer useful; removed in R14B"};
obsolete_1(ssh_cm, set_user_ack, 4) ->
- {removed,"no longer useful; will be removed in R14B"};
+ {removed,"no longer useful; removed in R14B"};
obsolete_1(ssh_cm, adjust_window, 3) ->
{removed,{ssh_connection,adjust_window,3},"R14B"};
obsolete_1(ssh_cm, close, 2) ->
@@ -478,9 +461,9 @@ obsolete_1(ssh_cm, send_ack, A) when 3 =< A, A =< 5 ->
obsolete_1(ssh_ssh, connect, A) when 1 =< A, A =< 3 ->
{removed,{ssh,shell,A},"R14B"};
obsolete_1(ssh_sshd, listen, A) when 0 =< A, A =< 3 ->
- {removed,{ssh,daemon,[1,2,3]},"R14"};
+ {removed,{ssh,daemon,[1,2,3]},"R14B"};
obsolete_1(ssh_sshd, stop, 1) ->
- {removed,{ssh,stop_listener,1}};
+ {removed,{ssh,stop_listener,1},"R14B"};
%% Added in R13A.
obsolete_1(regexp, _, _) ->
@@ -524,7 +507,7 @@ obsolete_1(docb_xml_check, _, _) ->
%% Added in R15B
obsolete_1(asn1rt, F, _) when F == load_driver; F == unload_driver ->
- {deprecated,"deprecated (will be removed in R16A); has no effect as drivers are no longer used."};
+ {deprecated,"deprecated (will be removed in OTP 18); has no effect as drivers are no longer used"};
obsolete_1(ssl, pid, 1) ->
{removed,"was removed in R16; is no longer needed"};
obsolete_1(inviso, _, _) ->
@@ -532,7 +515,7 @@ obsolete_1(inviso, _, _) ->
%% Added in R15B01.
obsolete_1(gs, _, _) ->
- {deprecated,"the gs application has been deprecated and will be removed in R17; use the wx application instead"};
+ {deprecated,"the gs application has been deprecated and will be removed in OTP 18; use the wx application instead"};
obsolete_1(ssh, sign_data, 2) ->
{deprecated,"deprecated (will be removed in R16A); use public_key:pem_decode/1, public_key:pem_entry_decode/1 "
"and public_key:sign/3 instead"};
@@ -594,6 +577,8 @@ obsolete_1(asn1rt, utf8_binary_to_list, 1) ->
{deprecated,{unicode,characters_to_list,1}};
obsolete_1(asn1rt, utf8_list_to_binary, 1) ->
{deprecated,{unicode,characters_to_binary,1}};
+obsolete_1(pg, _, _) ->
+ {deprecated,"deprecated; will be removed in OTP 18"};
obsolete_1(_, _, _) ->
no.
diff --git a/lib/stdlib/src/pg.erl b/lib/stdlib/src/pg.erl
index ee177e4e0b..a41fd329c2 100644
--- a/lib/stdlib/src/pg.erl
+++ b/lib/stdlib/src/pg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. 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
@@ -17,6 +17,7 @@
%% %CopyrightEnd%
%%
-module(pg).
+-deprecated(module).
%% pg provides a process group facility. Messages
%% can be multicasted to all members in the group
diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl
index 1eb6fc2e86..bf2a4e7ac5 100644
--- a/lib/stdlib/src/proc_lib.erl
+++ b/lib/stdlib/src/proc_lib.erl
@@ -216,10 +216,8 @@ ensure_link(SpawnOpts) ->
init_p(Parent, Ancestors, Fun) when is_function(Fun) ->
put('$ancestors', [Parent|Ancestors]),
- {module,Mod} = erlang:fun_info(Fun, module),
- {name,Name} = erlang:fun_info(Fun, name),
- {arity,Arity} = erlang:fun_info(Fun, arity),
- put('$initial_call', {Mod,Name,Arity}),
+ Mfa = erlang:fun_info_mfa(Fun),
+ put('$initial_call', Mfa),
try
Fun()
catch
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index 3b90542452..679c13f0cf 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -371,6 +371,14 @@ expand_expr({bc,L,E,Qs}, C) ->
{bc,L,expand_expr(E, C),expand_quals(Qs, C)};
expand_expr({tuple,L,Elts}, C) ->
{tuple,L,expand_exprs(Elts, C)};
+expand_expr({map,L,Es}, C) ->
+ {map,L,expand_exprs(Es, C)};
+expand_expr({map,L,Arg,Es}, C) ->
+ {map,L,expand_expr(Arg, C),expand_exprs(Es, C)};
+expand_expr({map_field_assoc,L,K,V}, C) ->
+ {map_field_assoc,L,expand_expr(K, C),expand_expr(V, C)};
+expand_expr({map_field_exact,L,K,V}, C) ->
+ {map_field_exact,L,expand_expr(K, C),expand_expr(V, C)};
expand_expr({record_index,L,Name,F}, C) ->
{record_index,L,Name,expand_expr(F, C)};
expand_expr({record,L,Name,Is}, C) ->
diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl
index 3e647635bc..1898dc8aba 100644
--- a/lib/stdlib/src/slave.erl
+++ b/lib/stdlib/src/slave.erl
@@ -290,7 +290,10 @@ register_unique_name(Number) ->
%% no need to use rsh.
mk_cmd(Host, Name, Args, Waiter, Prog0) ->
- Prog = quote_progname(Prog0),
+ Prog = case os:type() of
+ {ose,_} -> mk_ose_prog(Prog0);
+ _ -> quote_progname(Prog0)
+ end,
BasicCmd = lists:concat([Prog,
" -detached -noinput -master ", node(),
" ", long_or_short(), Name, "@", Host,
@@ -310,6 +313,24 @@ mk_cmd(Host, Name, Args, Waiter, Prog0) ->
end
end.
+%% On OSE we have to pass the beam arguments directory to the slave
+%% process. To find out what arguments that should be passed on we
+%% make an assumption. All arguments after the last "--" should be
+%% skipped. So given these arguments:
+%% -Muycs256 -A 1 -- -root /mst/ -progname beam.debug.smp -- -home /mst/ -- -kernel inetrc '"/mst/inetrc.conf"' -- -name test@localhost
+%% we send
+%% -Muycs256 -A 1 -- -root /mst/ -progname beam.debug.smp -- -home /mst/ -- -kernel inetrc '"/mst/inetrc.conf"' --
+%% to the slave with whatever other args that are added in mk_cmd.
+mk_ose_prog(Prog) ->
+ SkipTail = fun("--",[]) ->
+ ["--"];
+ (_,[]) ->
+ [];
+ (Arg,Args) ->
+ [Arg," "|Args]
+ end,
+ [Prog,tl(lists:foldr(SkipTail,[],erlang:system_info(emu_args)))].
+
%% This is an attempt to distinguish between spaces in the program
%% path and spaces that separate arguments. The program is quoted to
%% allow spaces in the path.
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index d388410de0..aa9899da3b 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -103,7 +103,7 @@
dets]},
{applications, [kernel]},
{env, []},
- {runtime_dependencies, ["sasl-2.4","kernel-3.0","erts-6.0","crypto-3.3",
+ {runtime_dependencies, ["sasl-2.4","kernel-3.0.2","erts-6.2","crypto-3.3",
"compiler-5.0"]}
]}.
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 22eefb2514..99d9b8b431 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -17,9 +17,11 @@
%% %CopyrightEnd%
{"%VSN%",
%% Up from - max one major revision back
- [{<<"2\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R17
+ [{<<"2\\.1(\\.[0-9]+)*">>,[restart_new_emulator]}, %% 17.1
+ {<<"2\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, %% 17.0
{<<"1\\.19(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R16
%% Down to - max one major revision back
- [{<<"2\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R17
+ [{<<"2\\.1(\\.[0-9]+)*">>,[restart_new_emulator]}, %% 17.1
+ {<<"2\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, %% 17.0
{<<"1\\.19(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R16
}.
diff --git a/lib/stdlib/src/sys.erl b/lib/stdlib/src/sys.erl
index e25cc25f57..d3ba09ce82 100644
--- a/lib/stdlib/src/sys.erl
+++ b/lib/stdlib/src/sys.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. 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
@@ -46,7 +46,7 @@
{N :: non_neg_integer(),
[{Event :: system_event(),
FuncState :: _,
- FormFunc :: dbg_fun()}]}}
+ FormFunc :: format_fun()}]}}
| {'statistics', {file:date_time(),
{'reductions', non_neg_integer()},
MessagesIn :: non_neg_integer(),
@@ -57,6 +57,10 @@
Event :: system_event(),
ProcState :: _) -> 'done' | (NewFuncState :: _)).
+-type format_fun() :: fun((Device :: io:device() | file:io_device(),
+ Event :: system_event(),
+ Extra :: term()) -> any()).
+
%%-----------------------------------------------------------------
%% System messages
%%-----------------------------------------------------------------
@@ -346,7 +350,7 @@ handle_system_msg(SysState, Msg, From, Parent, Mod, Debug, Misc, Hib) ->
%%-----------------------------------------------------------------
-spec handle_debug(Debug, FormFunc, Extra, Event) -> [dbg_opt()] when
Debug :: [dbg_opt()],
- FormFunc :: dbg_fun(),
+ FormFunc :: format_fun(),
Extra :: term(),
Event :: system_event().
handle_debug([{trace, true} | T], FormFunc, State, Event) ->
diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl
index c40ce8e203..b768c6d0b9 100644
--- a/lib/stdlib/src/zip.erl
+++ b/lib/stdlib/src/zip.erl
@@ -203,8 +203,18 @@
zip_comment_length}).
--type zip_file() :: #zip_file{}.
+-type create_option() :: memory | cooked | verbose | {comment, string()}
+ | {cwd, file:filename()}
+ | {compress, extension_spec()}
+ | {uncompress, extension_spec()}.
+-type extension() :: string().
+-type extension_spec() :: all | [extension()] | {add, [extension()]} | {del, [extension()]}.
+-type filename() :: file:filename().
+
-type zip_comment() :: #zip_comment{}.
+-type zip_file() :: #zip_file{}.
+
+-export_type([create_option/0, filename/0]).
%% Open a zip archive with options
%%
@@ -340,13 +350,13 @@ unzip(F) -> unzip(F, []).
-spec(unzip(Archive, Options) -> RetValue when
Archive :: file:name() | binary(),
Options :: [Option],
- Option :: {file_list, FileList}
+ Option :: {file_list, FileList} | cooked
| keep_old_files | verbose | memory |
{file_filter, FileFilter} | {cwd, CWD},
FileList :: [file:name()],
FileBinList :: [{file:name(),binary()}],
FileFilter :: fun((ZipFile) -> boolean()),
- CWD :: string(),
+ CWD :: file:filename(),
ZipFile :: zip_file(),
RetValue :: {ok, FileList}
| {ok, FileBinList}
@@ -430,7 +440,7 @@ zip(F, Files) -> zip(F, Files, []).
What :: all | [Extension] | {add, [Extension]} | {del, [Extension]},
Extension :: string(),
Comment :: string(),
- CWD :: string(),
+ CWD :: file:filename(),
RetValue :: {ok, FileName :: file:name()}
| {ok, {FileName :: file:name(), binary()}}
| {error, Reason :: term()}).
@@ -712,8 +722,8 @@ table(F, O) -> list_dir(F, O).
FileList :: [FileSpec],
FileSpec :: file:name() | {file:name(), binary()}
| {file:name(), binary(), file:file_info()},
- RetValue :: {ok, FileName :: file:name()}
- | {ok, {FileName :: file:name(), binary()}}
+ RetValue :: {ok, FileName :: filename()}
+ | {ok, {FileName :: filename(), binary()}}
| {error, Reason :: term()}).
create(F, Fs) -> zip(F, Fs).
@@ -724,14 +734,9 @@ create(F, Fs) -> zip(F, Fs).
FileSpec :: file:name() | {file:name(), binary()}
| {file:name(), binary(), file:file_info()},
Options :: [Option],
- Option :: memory | cooked | verbose | {comment, Comment}
- | {cwd, CWD} | {compress, What} | {uncompress, What},
- What :: all | [Extension] | {add, [Extension]} | {del, [Extension]},
- Extension :: string(),
- Comment :: string(),
- CWD :: string(),
- RetValue :: {ok, FileName :: file:name()}
- | {ok, {FileName :: file:name(), binary()}}
+ Option :: create_option(),
+ RetValue :: {ok, FileName :: filename()}
+ | {ok, {FileName :: filename(), binary()}}
| {error, Reason :: term()}).
create(F, Fs, O) -> zip(F, Fs, O).
@@ -755,7 +760,7 @@ extract(F) -> unzip(F).
FileList :: [file:name()],
FileBinList :: [{file:name(),binary()}],
FileFilter :: fun((ZipFile) -> boolean()),
- CWD :: string(),
+ CWD :: file:filename(),
ZipFile :: zip_file(),
RetValue :: {ok, FileList}
| {ok, FileBinList}
@@ -1153,7 +1158,7 @@ zip_open(Archive) -> zip_open(Archive, []).
Archive :: file:name() | binary(),
ZipHandle :: pid(),
Options :: [Option],
- Option :: cooked | memory | {cwd, CWD :: string()},
+ Option :: cooked | memory | {cwd, CWD :: file:filename()},
Reason :: term()).
zip_open(Archive, Options) ->
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index 39f6ce423a..a271229c59 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -85,7 +85,8 @@ MODULES= \
zip_SUITE \
random_unicode_list \
random_iolist \
- error_logger_forwarder
+ error_logger_forwarder \
+ maps_SUITE
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl
index d5a0fe21b4..32cec0db6f 100644
--- a/lib/stdlib/test/binary_module_SUITE.erl
+++ b/lib/stdlib/test/binary_module_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. 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
@@ -40,7 +40,7 @@
-export([init_per_testcase/2, end_per_testcase/2]).
% Default timetrap timeout (set in init_per_testcase).
% Some of these testcases are really heavy...
--define(default_timeout, ?t:minutes(20)).
+-define(default_timeout, ?t:minutes(30)).
-endif.
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index 00a5da42ad..119b4dc7cb 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -2032,6 +2032,12 @@ match(Config, Version) ->
CrashPos = if Version =:= 8 -> 5; Version =:= 9 -> 1 end,
crash(Fname, ObjPos2+CrashPos),
{ok, _} = dets:open_file(T, Args),
+ case dets:insert_new(T, Obj) of % OTP-12024
+ ok ->
+ bad_object(dets:sync(T), Fname);
+ Else3 ->
+ bad_object(Else3, Fname)
+ end,
io:format("Expect corrupt table:~n"),
case ins(T, N) of
ok ->
@@ -3953,15 +3959,6 @@ otp_11709(Config) when is_list(Config) ->
%% Parts common to several test cases
%%
-start_node_rel(Name, Rel, How) ->
- Release = [{release, atom_to_list(Rel)}],
- Pa = filename:dirname(code:which(?MODULE)),
- test_server:start_node(Name, How,
- [{args,
- " -kernel net_setuptime 100 "
- " -pa " ++ Pa},
- {erl, Release}]).
-
crash(File, Where) ->
crash(File, Where, 10).
@@ -4352,7 +4349,7 @@ check_badarg({'EXIT', {badarg, [{M,F,Args,_} | _]}}, M, F, Args) ->
check_badarg({'EXIT', {badarg, [{M,F,A,_} | _]}}, M, F, Args) ->
true = test_server:is_native(M) andalso length(Args) =:= A.
-check_pps(P0) ->
+check_pps({Ports0,Procs0} = P0) ->
case pps() of
P0 ->
ok;
@@ -4364,22 +4361,28 @@ check_pps(P0) ->
case pps() of
P0 ->
ok;
- P1 ->
- io:format("failure, got ~p~n, expected ~p\n", [P1, P0]),
- {Ports0,Procs0} = P0,
- {Ports1,Procs1} = P1,
- show("Old ports", Ports0 -- Ports1),
- show("New ports", Ports1 -- Ports0),
- show("Old procs", Procs0 -- Procs1),
- show("New procs", Procs1 -- Procs0),
- ?t:fail()
- end
+ {Ports1,Procs1} = P1 ->
+ case {Ports1 -- Ports0, Procs1 -- Procs0} of
+ {[], []} -> ok;
+ {PortsDiff,ProcsDiff} ->
+ io:format("failure, got ~p~n, expected ~p\n", [P1, P0]),
+ show("Old port", Ports0 -- Ports1),
+ show("New port", PortsDiff),
+ show("Old proc", Procs0 -- Procs1),
+ show("New proc", ProcsDiff),
+ ?t:fail()
+ end
+ end
end.
show(_S, []) ->
ok;
-show(S, L) ->
- io:format("~s: ~p~n", [S, L]).
+show(S, [Pid|Pids]) when is_pid(Pid) ->
+ io:format("~s: ~p~n", [S, erlang:process_info(Pid)]),
+ show(S, Pids);
+show(S, [Port|Ports]) when is_port(Port)->
+ io:format("~s: ~p~n", [S, erlang:port_info(Port)]),
+ show(S, Ports).
pps() ->
dets:start(),
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index b91d14b5b8..b55324161b 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1451,6 +1451,13 @@ eep43(Config) when is_list(Config) ->
" {Map#{a := B},Map#{a => c},Map#{d => e}} "
"end.",
{#{a => b},#{a => c},#{a => b,d => e}}),
+ check(fun () ->
+ lists:map(fun (X) -> X#{price := 0} end,
+ [#{hello => 0, price => nil}])
+ end,
+ "lists:map(fun (X) -> X#{price := 0} end,
+ [#{hello => 0, price => nil}]).",
+ [#{hello => 0, price => 0}]),
error_check("[camembert]#{}.", {badarg,[camembert]}),
error_check("#{} = 1.", {badmatch,1}),
ok.
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index f822986981..ea61b2082b 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -52,7 +52,7 @@
guard/1, otp_4886/1, otp_4988/1, otp_5091/1, otp_5276/1, otp_5338/1,
otp_5362/1, otp_5371/1, otp_7227/1, otp_5494/1, otp_5644/1, otp_5878/1,
otp_5917/1, otp_6585/1, otp_6885/1, otp_10436/1, otp_11254/1,
- otp_11772/1, otp_11771/1,
+ otp_11772/1, otp_11771/1, otp_11872/1,
export_all/1,
bif_clash/1,
behaviour_basic/1, behaviour_multiple/1,
@@ -88,7 +88,7 @@ all() ->
otp_4886, otp_4988, otp_5091, otp_5276, otp_5338,
otp_5362, otp_5371, otp_7227, otp_5494, otp_5644,
otp_5878, otp_5917, otp_6585, otp_6885, otp_10436, otp_11254,
- otp_11772, otp_11771, export_all,
+ otp_11772, otp_11771, otp_11872, export_all,
bif_clash, behaviour_basic, behaviour_multiple,
otp_7550, otp_8051, format_warn, {group, on_load},
too_many_arguments, basic_errors, bin_syntax_errors, predef,
@@ -1279,10 +1279,9 @@ guard(Config) when is_list(Config) ->
tuple.
">>,
[nowarn_obsolete_guard],
- {error,
+ {errors,
[{6,erl_lint,illegal_guard_expr},{18,erl_lint,illegal_guard_expr}],
- [{18,erl_lint,{removed,{erlang,is_constant,1},
- "Removed in R13B"}}]}},
+ []}},
{guard2,
<<"-record(apa,{}).
t1(A) when atom(A), atom(A) ->
@@ -1341,14 +1340,11 @@ guard(Config) when is_list(Config) ->
tuple.
">>,
[nowarn_obsolete_guard],
- {error,[{6,erl_lint,illegal_guard_expr},
- {6,erl_lint,illegal_guard_expr},
- {18,erl_lint,illegal_guard_expr},
- {18,erl_lint,illegal_guard_expr}],
- [{18,erl_lint,{removed,{erlang,is_constant,1},
- "Removed in R13B"}},
- {18,erl_lint,{removed,{erlang,is_constant,1},
- "Removed in R13B"}}]}},
+ {errors,[{6,erl_lint,illegal_guard_expr},
+ {6,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr}],
+ []}},
{guard3,
<<"-record(apa,{}).
t2(A) when atom(A); atom(A) ->
@@ -2634,6 +2630,29 @@ otp_11771(Config) when is_list(Config) ->
[]} = run_test2(Config, Ts, []),
ok.
+otp_11872(doc) ->
+ "OTP-11872. The type map() undefined when exported.";
+otp_11872(suite) -> [];
+otp_11872(Config) when is_list(Config) ->
+ Ts = <<"
+ -module(map).
+
+ -compile(export_all).
+
+ -export_type([map/0, product/0]).
+
+ -opaque map() :: dict().
+
+ -spec t() -> map().
+
+ t() ->
+ 1.
+ ">>,
+ {error,[{6,erl_lint,{undefined_type,{product,0}}}],
+ [{8,erl_lint,{new_var_arity_type,map}}]} =
+ run_test2(Config, Ts, []),
+ ok.
+
export_all(doc) ->
"OTP-7392. Warning for export_all.";
export_all(Config) when is_list(Config) ->
@@ -3410,7 +3429,19 @@ maps(Config) ->
{4,erl_lint,illegal_map_key},
{6,erl_lint,illegal_map_key},
{8,erl_lint,illegal_map_key},
- {10,erl_lint,illegal_map_key}],[]}}],
+ {10,erl_lint,illegal_map_key}],[]}},
+ {errors_in_map_keys_pattern,
+ <<"t(#{ a := 2,
+ #{} := A,
+ #{ 3 => 33 } := hi,
+ #{ 3 := 33 } := hi,
+ #{ hi => 54, \"hello\" => 45 } := hi,
+ #{ V => 33 } := hi }) ->
+ A.
+ ">>,
+ [],
+ {errors,[{4,erl_lint,illegal_map_key},
+ {6,erl_lint,{illegal_map_key_variable,'V'}}],[]}}],
[] = run(Config, Ts),
ok.
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index 390322a5fa..babf3a49eb 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -993,6 +993,16 @@ maps_syntax(Config) when is_list(Config) ->
ok = pp_expr(<<"#{ a => 1, <<\"hi\">> => \"world\", 33 => 1.0 }">>),
ok = pp_expr(<<"#{ a := V1, <<\"hi\">> := V2 } = M">>),
ok = pp_expr(<<"M#{ a => V1, <<\"hi\">> := V2 }">>),
+ F = <<"-module(maps_type_syntax).\n"
+ "-compile(export_all).\n"
+ "-type t1() :: map().\n"
+ "-type t2() :: #{ atom() => integer(), atom() => float() }.\n"
+ "-spec f1(t1()) -> 'true'.\n"
+ "f1(M) when is_map(M) -> true.\n"
+ "-spec f2(t2()) -> integer().\n"
+ "f2(#{a := V1,b := V2}) -> V1 + V2.\n"
+ "\n">>,
+ ok = pp_forms(F),
ok.
diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl
index 35067e8116..9be9f641c8 100644
--- a/lib/stdlib/test/erl_scan_SUITE.erl
+++ b/lib/stdlib/test/erl_scan_SUITE.erl
@@ -204,20 +204,20 @@ reserved_words() ->
[begin
?line {RW, true} = {RW, erl_scan:reserved_word(RW)},
S = atom_to_list(RW),
- Ts = [{RW,1}],
+ Ts = [{RW,{1,1}}],
?line test_string(S, Ts)
end || RW <- L],
ok.
atoms() ->
- ?line test_string("a
- b", [{atom,1,a},{atom,2,b}]),
- ?line test_string("'a b'", [{atom,1,'a b'}]),
- ?line test_string("a", [{atom,1,a}]),
- ?line test_string("a@2", [{atom,1,a@2}]),
- ?line test_string([39,65,200,39], [{atom,1,'AÈ'}]),
- ?line test_string("ärlig östen", [{atom,1,ärlig},{atom,1,östen}]),
+ test_string("a
+ b", [{atom,{1,1},a},{atom,{2,18},b}]),
+ test_string("'a b'", [{atom,{1,1},'a b'}]),
+ test_string("a", [{atom,{1,1},a}]),
+ test_string("a@2", [{atom,{1,1},a@2}]),
+ test_string([39,65,200,39], [{atom,{1,1},'AÈ'}]),
+ test_string("ärlig östen", [{atom,{1,1},ärlig},{atom,{1,7},östen}]),
?line {ok,[{atom,_,'$a'}],{1,6}} =
erl_scan:string("'$\\a'", {1,1}),
?line test("'$\\a'"),
@@ -230,7 +230,7 @@ punctuations() ->
%% One token at a time:
[begin
W = list_to_atom(S),
- Ts = [{W,1}],
+ Ts = [{W,{1,1}}],
?line test_string(S, Ts)
end || S <- L],
Three = ["/=:=", "<=:=", "==:=", ">=:="], % three tokens...
@@ -246,53 +246,60 @@ punctuations() ->
[begin
W1 = list_to_atom(S1),
W2 = list_to_atom(S2),
- Ts = [{W1,1},{W2,1}],
+ Ts = [{W1,{1,1}},{W2,{1,-L2+1}}],
?line test_string(S, Ts)
- end || {S,[{_,S1,S2}|_]} <- SL],
+ end || {S,[{L2,S1,S2}|_]} <- SL],
- PTs1 = [{'!',1},{'(',1},{')',1},{',',1},{';',1},{'=',1},{'[',1},
- {']',1},{'{',1},{'|',1},{'}',1}],
+ PTs1 = [{'!',{1,1}},{'(',{1,2}},{')',{1,3}},{',',{1,4}},{';',{1,5}},
+ {'=',{1,6}},{'[',{1,7}},{']',{1,8}},{'{',{1,9}},{'|',{1,10}},
+ {'}',{1,11}}],
?line test_string("!(),;=[]{|}", PTs1),
- PTs2 = [{'#',1},{'&',1},{'*',1},{'+',1},{'/',1},
- {':',1},{'<',1},{'>',1},{'?',1},{'@',1},
- {'\\',1},{'^',1},{'`',1},{'~',1}],
+ PTs2 = [{'#',{1,1}},{'&',{1,2}},{'*',{1,3}},{'+',{1,4}},{'/',{1,5}},
+ {':',{1,6}},{'<',{1,7}},{'>',{1,8}},{'?',{1,9}},{'@',{1,10}},
+ {'\\',{1,11}},{'^',{1,12}},{'`',{1,13}},{'~',{1,14}}],
?line test_string("#&*+/:<>?@\\^`~", PTs2),
- ?line test_string(".. ", [{'..',1}]),
- ?line test("1 .. 2"),
- ?line test_string("...", [{'...',1}]),
+ test_string(".. ", [{'..',{1,1}}]),
+ test_string("1 .. 2",
+ [{integer,{1,1},1},{'..',{1,3}},{integer,{1,6},2}]),
+ test_string("...", [{'...',{1,1}}]),
ok.
comments() ->
?line test("a %%\n b"),
?line {ok,[],1} = erl_scan:string("%"),
?line test("a %%\n b"),
- ?line {ok,[{atom,_,a},{atom,_,b}],{2,3}} =
+ {ok,[{atom,{1,1},a},{atom,{2,2},b}],{2,3}} =
erl_scan:string("a %%\n b",{1,1}),
- ?line {ok,[{atom,_,a},{comment,_,"%%"},{atom,_,b}],{2,3}} =
+ {ok,[{atom,{1,1},a},{comment,{1,3},"%%"},{atom,{2,2},b}],{2,3}} =
erl_scan:string("a %%\n b",{1,1}, [return_comments]),
- ?line {ok,[{atom,_,a},
- {white_space,_," "},
- {white_space,_,"\n "},
- {atom,_,b}],
- {2,3}} =
+ {ok,[{atom,{1,1},a},
+ {white_space,{1,2}," "},
+ {white_space,{1,5},"\n "},
+ {atom,{2,2},b}],
+ {2,3}} =
erl_scan:string("a %%\n b",{1,1},[return_white_spaces]),
- ?line {ok,[{atom,_,a},
- {white_space,_," "},
- {comment,_,"%%"},
- {white_space,_,"\n "},
- {atom,_,b}],
- {2,3}} = erl_scan:string("a %%\n b",{1,1},[return]),
+ {ok,[{atom,{1,1},a},
+ {white_space,{1,2}," "},
+ {comment,{1,3},"%%"},
+ {white_space,{1,5},"\n "},
+ {atom,{2,2},b}],
+ {2,3}} = erl_scan:string("a %%\n b",{1,1},[return]),
ok.
errors() ->
?line {error,{1,erl_scan,{string,$',"qa"}},1} = erl_scan:string("'qa"), %'
+ {error,{{1,1},erl_scan,{string,$',"qa"}},{1,4}} = %'
+ erl_scan:string("'qa", {1,1}, []), %'
?line {error,{1,erl_scan,{string,$","str"}},1} = %"
erl_scan:string("\"str"), %"
+ {error,{{1,1},erl_scan,{string,$","str"}},{1,5}} = %"
+ erl_scan:string("\"str", {1,1}, []), %"
?line {error,{1,erl_scan,char},1} = erl_scan:string("$"),
- ?line test_string([34,65,200,34], [{string,1,"AÈ"}]),
- ?line test_string("\\", [{'\\',1}]),
+ {error,{{1,1},erl_scan,char},{1,2}} = erl_scan:string("$", {1,1}, []),
+ test_string([34,65,200,34], [{string,{1,1},"AÈ"}]),
+ test_string("\\", [{'\\',{1,1}}]),
?line {'EXIT',_} =
(catch {foo, erl_scan:string('$\\a', {1,1})}), % type error
?line {'EXIT',_} =
@@ -304,7 +311,7 @@ errors() ->
integers() ->
[begin
I = list_to_integer(S),
- Ts = [{integer,1,I}],
+ Ts = [{integer,{1,1},I}],
?line test_string(S, Ts)
end || S <- [[N] || N <- lists:seq($0, $9)] ++ ["2323","000"] ],
ok.
@@ -313,14 +320,16 @@ base_integers() ->
[begin
B = list_to_integer(BS),
I = erlang:list_to_integer(S, B),
- Ts = [{integer,1,I}],
+ Ts = [{integer,{1,1},I}],
?line test_string(BS++"#"++S, Ts)
end || {BS,S} <- [{"2","11"}, {"5","23234"}, {"12","05a"},
{"16","abcdef"}, {"16","ABCDEF"}] ],
?line {error,{1,erl_scan,{base,1}},1} = erl_scan:string("1#000"),
+ {error,{{1,1},erl_scan,{base,1}},{1,2}} =
+ erl_scan:string("1#000", {1,1}, []),
- ?line test_string("12#bc", [{integer,1,11},{atom,1,c}]),
+ test_string("12#bc", [{integer,{1,1},11},{atom,{1,5},c}]),
[begin
Str = BS ++ "#" ++ S,
@@ -329,40 +338,53 @@ base_integers() ->
end || {BS,S} <- [{"3","3"},{"15","f"}, {"12","c"}] ],
?line {ok,[{integer,1,239},{'@',1}],1} = erl_scan:string("16#ef@"),
- ?line {ok,[{integer,1,14},{atom,1,g@}],1} = erl_scan:string("16#eg@"),
+ {ok,[{integer,{1,1},239},{'@',{1,6}}],{1,7}} =
+ erl_scan:string("16#ef@", {1,1}, []),
+ {ok,[{integer,{1,1},14},{atom,{1,5},g@}],{1,7}} =
+ erl_scan:string("16#eg@", {1,1}, []),
ok.
floats() ->
[begin
F = list_to_float(FS),
- Ts = [{float,1,F}],
+ Ts = [{float,{1,1},F}],
?line test_string(FS, Ts)
end || FS <- ["1.0","001.17","3.31200","1.0e0","1.0E17",
"34.21E-18", "17.0E+14"]],
- ?line test_string("1.e2", [{integer,1,1},{'.',1},{atom,1,e2}]),
+ test_string("1.e2", [{integer,{1,1},1},{'.',{1,2}},{atom,{1,3},e2}]),
?line {error,{1,erl_scan,{illegal,float}},1} =
erl_scan:string("1.0e400"),
+ {error,{{1,1},erl_scan,{illegal,float}},{1,8}} =
+ erl_scan:string("1.0e400", {1,1}, []),
[begin
- ?line {error,{1,erl_scan,{illegal,float}},1} = erl_scan:string(S)
+ {error,{1,erl_scan,{illegal,float}},1} = erl_scan:string(S),
+ {error,{{1,1},erl_scan,{illegal,float}},{1,_}} =
+ erl_scan:string(S, {1,1}, [])
end || S <- ["1.14Ea"]],
ok.
dots() ->
- Dot = [{".", {ok,[{dot,1}],1}},
- {". ", {ok,[{dot,1}],1}},
- {".\n", {ok,[{dot,1}],2}},
- {".%", {ok,[{dot,1}],1}},
- {".\210",{ok,[{dot,1}],1}},
- {".% öh",{ok,[{dot,1}],1}},
- {".%\n", {ok,[{dot,1}],2}},
- {".$", {error,{1,erl_scan,char},1}},
- {".$\\", {error,{1,erl_scan,char},1}},
- {".a", {ok,[{'.',1},{atom,1,a}],1}}
+ Dot = [{".", {ok,[{dot,1}],1}, {ok,[{dot,{1,1}}],{1,2}}},
+ {". ", {ok,[{dot,1}],1}, {ok,[{dot,{1,1}}],{1,3}}},
+ {".\n", {ok,[{dot,1}],2}, {ok,[{dot,{1,1}}],{2,1}}},
+ {".%", {ok,[{dot,1}],1}, {ok,[{dot,{1,1}}],{1,3}}},
+ {".\210",{ok,[{dot,1}],1}, {ok,[{dot,{1,1}}],{1,3}}},
+ {".% öh",{ok,[{dot,1}],1}, {ok,[{dot,{1,1}}],{1,6}}},
+ {".%\n", {ok,[{dot,1}],2}, {ok,[{dot,{1,1}}],{2,1}}},
+ {".$", {error,{1,erl_scan,char},1},
+ {error,{{1,2},erl_scan,char},{1,3}}},
+ {".$\\", {error,{1,erl_scan,char},1},
+ {error,{{1,2},erl_scan,char},{1,4}}},
+ {".a", {ok,[{'.',1},{atom,1,a}],1},
+ {ok,[{'.',{1,1}},{atom,{1,2},a}],{1,3}}}
],
- ?line [R = erl_scan:string(S) || {S, R} <- Dot],
+ [begin
+ R = erl_scan:string(S),
+ R2 = erl_scan:string(S, {1,1}, [])
+ end || {S, R, R2} <- Dot],
?line {ok,[{dot,_}=T1],{1,2}} = erl_scan:string(".", {1,1}, text),
?line [{column,1},{length,1},{line,1},{text,"."}] =
@@ -379,55 +401,55 @@ dots() ->
?line {error,{{1,2},erl_scan,char},{1,4}} =
erl_scan:string(".$\\", {1,1}),
- ?line test(". "),
- ?line test(". "),
- ?line test(".\n"),
- ?line test(".\n\n"),
- ?line test(".\n\r"),
- ?line test(".\n\n\n"),
- ?line test(".\210"),
- ?line test(".%\n"),
- ?line test(".a"),
-
- ?line test("%. \n. "),
+ test_string(". ", [{dot,{1,1}}]),
+ test_string(". ", [{dot,{1,1}}]),
+ test_string(".\n", [{dot,{1,1}}]),
+ test_string(".\n\n", [{dot,{1,1}}]),
+ test_string(".\n\r", [{dot,{1,1}}]),
+ test_string(".\n\n\n", [{dot,{1,1}}]),
+ test_string(".\210", [{dot,{1,1}}]),
+ test_string(".%\n", [{dot,{1,1}}]),
+ test_string(".a", [{'.',{1,1}},{atom,{1,2},a}]),
+
+ test_string("%. \n. ", [{dot,{2,1}}]),
?line {more,C} = erl_scan:tokens([], "%. ",{1,1}, return),
- ?line {done,{ok,[{comment,_,"%. "},
- {white_space,_,"\n"},
- {dot,_}],
- {2,3}}, ""} =
+ {done,{ok,[{comment,{1,1},"%. "},
+ {white_space,{1,4},"\n"},
+ {dot,{2,1}}],
+ {2,3}}, ""} =
erl_scan:tokens(C, "\n. ", {1,1}, return), % any loc, any options
?line [test_string(S, R) ||
- {S, R} <- [{".$\n", [{'.',1},{char,1,$\n}]},
- {"$\\\n", [{char,1,$\n}]},
- {"'\\\n'", [{atom,1,'\n'}]},
- {"$\n", [{char,1,$\n}]}] ],
+ {S, R} <- [{".$\n", [{'.',{1,1}},{char,{1,2},$\n}]},
+ {"$\\\n", [{char,{1,1},$\n}]},
+ {"'\\\n'", [{atom,{1,1},'\n'}]},
+ {"$\n", [{char,{1,1},$\n}]}] ],
ok.
chars() ->
[begin
L = lists:flatten(io_lib:format("$\\~.8b", [C])),
- Ts = [{char,1,C}],
+ Ts = [{char,{1,1},C}],
?line test_string(L, Ts)
end || C <- lists:seq(0, 255)],
%% Leading zeroes...
[begin
L = lists:flatten(io_lib:format("$\\~3.8.0b", [C])),
- Ts = [{char,1,C}],
+ Ts = [{char,{1,1},C}],
?line test_string(L, Ts)
end || C <- lists:seq(0, 255)],
%% $\^\n now increments the line...
[begin
L = "$\\^" ++ [C],
- Ts = [{char,1,C band 2#11111}],
+ Ts = [{char,{1,1},C band 2#11111}],
?line test_string(L, Ts)
end || C <- lists:seq(0, 255)],
[begin
L = "$\\" ++ [C],
- Ts = [{char,1,V}],
+ Ts = [{char,{1,1},V}],
?line test_string(L, Ts)
end || {C,V} <- [{$n,$\n}, {$r,$\r}, {$t,$\t}, {$v,$\v},
{$b,$\b}, {$f,$\f}, {$e,$\e}, {$s,$\s},
@@ -440,45 +462,45 @@ chars() ->
No = EC ++ Ds ++ X ++ New,
[begin
L = "$\\" ++ [C],
- Ts = [{char,1,C}],
+ Ts = [{char,{1,1},C}],
?line test_string(L, Ts)
end || C <- lists:seq(0, 255) -- No],
[begin
L = "'$\\" ++ [C] ++ "'",
- Ts = [{atom,1,list_to_atom("$"++[C])}],
+ Ts = [{atom,{1,1},list_to_atom("$"++[C])}],
?line test_string(L, Ts)
end || C <- lists:seq(0, 255) -- No],
- ?line test_string("\"\\013a\\\n\"", [{string,1,"\va\n"}]),
+ test_string("\"\\013a\\\n\"", [{string,{1,1},"\va\n"}]),
- ?line test_string("'\n'", [{atom,1,'\n'}]),
- ?line test_string("\"\n\a\"", [{string,1,"\na"}]),
+ test_string("'\n'", [{atom,{1,1},'\n'}]),
+ test_string("\"\n\a\"", [{string,{1,1},"\na"}]),
%% No escape
[begin
L = "$" ++ [C],
- Ts = [{char,1,C}],
+ Ts = [{char,{1,1},C}],
?line test_string(L, Ts)
end || C <- lists:seq(0, 255) -- (No ++ [$\\])],
- ?line test_string("$\n", [{char,1,$\n}]),
+ test_string("$\n", [{char,{1,1},$\n}]),
?line {error,{{1,1},erl_scan,char},{1,4}} =
erl_scan:string("$\\^",{1,1}),
- ?line test_string("$\\\n", [{char,1,$\n}]),
+ test_string("$\\\n", [{char,{1,1},$\n}]),
%% Robert's scanner returns line 1:
- ?line test_string("$\\\n", [{char,1,$\n}]),
- ?line test_string("$\n\n", [{char,1,$\n}]),
+ test_string("$\\\n", [{char,{1,1},$\n}]),
+ test_string("$\n\n", [{char,{1,1},$\n}]),
?line test("$\n\n"),
ok.
variables() ->
- ?line test_string(" \237_Aouåeiyäö", [{var,1,'_Aouåeiyäö'}]),
- ?line test_string("A_b_c@", [{var,1,'A_b_c@'}]),
- ?line test_string("V@2", [{var,1,'V@2'}]),
- ?line test_string("ABDÀ", [{var,1,'ABDÀ'}]),
- ?line test_string("Ärlig Östen", [{var,1,'Ärlig'},{var,1,'Östen'}]),
+ test_string(" \237_Aouåeiyäö", [{var,{1,7},'_Aouåeiyäö'}]),
+ test_string("A_b_c@", [{var,{1,1},'A_b_c@'}]),
+ test_string("V@2", [{var,{1,1},'V@2'}]),
+ test_string("ABDÀ", [{var,{1,1},'ABDÀ'}]),
+ test_string("Ärlig Östen", [{var,{1,1},'Ärlig'},{var,{1,7},'Östen'}]),
ok.
eof() ->
@@ -508,11 +530,25 @@ eof() ->
?line {done,{ok,[{atom,1,a}],1},eof} =
erl_scan:tokens(C5,eof,1),
+ %% With column.
+ {more, C6} = erl_scan:tokens([], "a", {1,1}),
+ %% An error before R13A.
+ %% {done,{error,{1,erl_scan,scan},1},eof} =
+ {done,{ok,[{atom,{1,1},a}],{1,2}},eof} =
+ erl_scan:tokens(C6,eof,1),
+
%% A dot followed by eof is special:
?line {more, C} = erl_scan:tokens([], "a.", 1),
?line {done,{ok,[{atom,1,a},{dot,1}],1},eof} = erl_scan:tokens(C,eof,1),
?line {ok,[{atom,1,foo},{dot,1}],1} = erl_scan:string("foo."),
+ %% With column.
+ {more, CCol} = erl_scan:tokens([], "a.", {1,1}),
+ {done,{ok,[{atom,{1,1},a},{dot,{1,2}}],{1,3}},eof} =
+ erl_scan:tokens(CCol,eof,1),
+ {ok,[{atom,{1,1},foo},{dot,{1,4}}],{1,5}} =
+ erl_scan:string("foo.", {1,1}, []),
+
ok.
illegal() ->
@@ -816,34 +852,34 @@ unicode() ->
erl_scan:string([1089]),
?line {error,{{1,1},erl_scan,{illegal,character}},{1,2}} =
erl_scan:string([1089], {1,1}),
- ?line {error,{1,erl_scan,{illegal,atom}},1} =
+ {error,{1,erl_scan,{illegal,atom}},1} =
erl_scan:string("'a"++[1089]++"b'", 1),
- ?line {error,{{1,1},erl_scan,{illegal,atom}},{1,6}} =
+ {error,{{1,1},erl_scan,{illegal,atom}},{1,6}} =
erl_scan:string("'a"++[1089]++"b'", {1,1}),
?line test("\"a"++[1089]++"b\""),
- ?line {ok,[{char,1,1}],1} =
+ {ok,[{char,1,1}],1} =
erl_scan:string([$$,$\\,$^,1089], 1),
- ?line {error,{1,erl_scan,Error},1} =
+ {error,{1,erl_scan,Error},1} =
erl_scan:string("\"qa\x{aaa}", 1),
- ?line "unterminated string starting with \"qa"++[2730]++"\"" =
+ "unterminated string starting with \"qa"++[2730]++"\"" =
erl_scan:format_error(Error),
?line {error,{{1,1},erl_scan,_},{1,11}} =
erl_scan:string("\"qa\\x{aaa}",{1,1}),
- ?line {error,{{1,1},erl_scan,{illegal,atom}},{1,12}} =
+ {error,{{1,1},erl_scan,{illegal,atom}},{1,12}} =
erl_scan:string("'qa\\x{aaa}'",{1,1}),
- ?line {ok,[{char,1,1089}],1} =
+ {ok,[{char,1,1089}],1} =
erl_scan:string([$$,1089], 1),
- ?line {ok,[{char,1,1089}],1} =
+ {ok,[{char,1,1089}],1} =
erl_scan:string([$$,$\\,1089], 1),
Qs = "$\\x{aaa}",
- ?line {ok,[{char,1,$\x{aaa}}],1} =
+ {ok,[{char,1,$\x{aaa}}],1} =
erl_scan:string(Qs, 1),
- ?line {ok,[Q2],{1,9}} =
+ {ok,[Q2],{1,9}} =
erl_scan:string("$\\x{aaa}", {1,1}, [text]),
- ?line [{category,char},{column,1},{length,8},
+ [{category,char},{column,1},{length,8},
{line,1},{symbol,16#aaa},{text,Qs}] =
erl_scan:token_info(Q2),
@@ -1164,7 +1200,13 @@ otp_11807(Config) when is_list(Config) ->
(catch erl_parse:abstract("string", [{encoding,bad}])),
ok.
-test_string(String, Expected) ->
+test_string(String, ExpectedWithCol) ->
+ {ok, ExpectedWithCol, _EndWithCol} = erl_scan:string(String, {1, 1}, []),
+ Expected = [ begin
+ {L,_C} = element(2, T),
+ setelement(2, T, L)
+ end
+ || T <- ExpectedWithCol ],
{ok, Expected, _End} = erl_scan:string(String),
test(String).
diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl
index 4a67d68428..040ae1effc 100644
--- a/lib/stdlib/test/filelib_SUITE.erl
+++ b/lib/stdlib/test/filelib_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2014. 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
@@ -23,7 +23,8 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
wildcard_one/1,wildcard_two/1,wildcard_errors/1,
- fold_files/1,otp_5960/1,ensure_dir_eexist/1]).
+ fold_files/1,otp_5960/1,ensure_dir_eexist/1,ensure_dir_symlink/1,
+ wildcard_symlink/1, is_file_symlink/1, file_props_symlink/1]).
-import(lists, [foreach/2]).
@@ -43,7 +44,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[wildcard_one, wildcard_two, wildcard_errors,
- fold_files, otp_5960, ensure_dir_eexist].
+ fold_files, otp_5960, ensure_dir_eexist, ensure_dir_symlink,
+ wildcard_symlink, is_file_symlink, file_props_symlink].
groups() ->
[].
@@ -366,3 +368,139 @@ ensure_dir_eexist(Config) when is_list(Config) ->
?line {error, eexist} = filelib:ensure_dir(NeedFile),
?line {error, eexist} = filelib:ensure_dir(NeedFileB),
ok.
+
+ensure_dir_symlink(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ Dir = filename:join(PrivDir, "ensure_dir_symlink"),
+ Name = filename:join(Dir, "same_name_as_file_and_dir"),
+ ok = filelib:ensure_dir(Name),
+ ok = file:write_file(Name, <<"some string\n">>),
+ %% With a symlink to the directory.
+ Symlink = filename:join(PrivDir, "ensure_dir_symlink_link"),
+ case file:make_symlink(Dir, Symlink) of
+ {error,enotsup} ->
+ {skip,"Symlinks not supported on this platform"};
+ {error,eperm} ->
+ {win32,_} = os:type(),
+ {skip,"Windows user not privileged to create symlinks"};
+ ok ->
+ SymlinkedName = filename:join(Symlink, "same_name_as_file_and_dir"),
+ ok = filelib:ensure_dir(SymlinkedName)
+ end.
+
+wildcard_symlink(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ Dir = filename:join(PrivDir, ?MODULE_STRING++"_wildcard_symlink"),
+ SubDir = filename:join(Dir, "sub"),
+ AFile = filename:join(SubDir, "a_file"),
+ Alias = filename:join(Dir, "symlink"),
+ ok = file:make_dir(Dir),
+ ok = file:make_dir(SubDir),
+ ok = file:write_file(AFile, "not that big\n"),
+ case file:make_symlink(AFile, Alias) of
+ {error, enotsup} ->
+ {skip, "Links not supported on this platform"};
+ {error, eperm} ->
+ {win32,_} = os:type(),
+ {skip, "Windows user not privileged to create symlinks"};
+ ok ->
+ ["sub","symlink"] =
+ basenames(Dir, filelib:wildcard(filename:join(Dir, "*"))),
+ ["symlink"] =
+ basenames(Dir, filelib:wildcard(filename:join(Dir, "symlink"))),
+ ["sub","symlink"] =
+ basenames(Dir, filelib:wildcard(filename:join(Dir, "*"),
+ erl_prim_loader)),
+ ["symlink"] =
+ basenames(Dir, filelib:wildcard(filename:join(Dir, "symlink"),
+ erl_prim_loader)),
+ ["sub","symlink"] =
+ basenames(Dir, filelib:wildcard(filename:join(Dir, "*"),
+ prim_file)),
+ ["symlink"] =
+ basenames(Dir, filelib:wildcard(filename:join(Dir, "symlink"),
+ prim_file)),
+ ok = file:delete(AFile),
+ %% The symlink should still be visible even when its target
+ %% has been deleted.
+ ["sub","symlink"] =
+ basenames(Dir, filelib:wildcard(filename:join(Dir, "*"))),
+ ["symlink"] =
+ basenames(Dir, filelib:wildcard(filename:join(Dir, "symlink"))),
+ ["sub","symlink"] =
+ basenames(Dir, filelib:wildcard(filename:join(Dir, "*"),
+ erl_prim_loader)),
+ ["symlink"] =
+ basenames(Dir, filelib:wildcard(filename:join(Dir, "symlink"),
+ erl_prim_loader)),
+ ["sub","symlink"] =
+ basenames(Dir, filelib:wildcard(filename:join(Dir, "*"),
+ prim_file)),
+ ["symlink"] =
+ basenames(Dir, filelib:wildcard(filename:join(Dir, "symlink"),
+ prim_file)),
+ ok
+ end.
+
+basenames(Dir, Files) ->
+ [begin
+ Dir = filename:dirname(F),
+ filename:basename(F)
+ end || F <- Files].
+
+is_file_symlink(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ Dir = filename:join(PrivDir, ?MODULE_STRING++"_is_file_symlink"),
+ SubDir = filename:join(Dir, "sub"),
+ AFile = filename:join(SubDir, "a_file"),
+ DirAlias = filename:join(Dir, "dir_symlink"),
+ FileAlias = filename:join(Dir, "file_symlink"),
+ ok = file:make_dir(Dir),
+ ok = file:make_dir(SubDir),
+ ok = file:write_file(AFile, "not that big\n"),
+ case file:make_symlink(SubDir, DirAlias) of
+ {error, enotsup} ->
+ {skip, "Links not supported on this platform"};
+ {error, eperm} ->
+ {win32,_} = os:type(),
+ {skip, "Windows user not privileged to create symlinks"};
+ ok ->
+ true = filelib:is_dir(DirAlias),
+ true = filelib:is_dir(DirAlias, erl_prim_loader),
+ true = filelib:is_dir(DirAlias, prim_file),
+ true = filelib:is_file(DirAlias),
+ true = filelib:is_file(DirAlias, erl_prim_loader),
+ true = filelib:is_file(DirAlias, prim_file),
+ ok = file:make_symlink(AFile,FileAlias),
+ true = filelib:is_file(FileAlias),
+ true = filelib:is_file(FileAlias, erl_prim_loader),
+ true = filelib:is_file(FileAlias, prim_file),
+ true = filelib:is_regular(FileAlias),
+ true = filelib:is_regular(FileAlias, erl_prim_loader),
+ true = filelib:is_regular(FileAlias, prim_file),
+ ok
+ end.
+
+file_props_symlink(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ Dir = filename:join(PrivDir, ?MODULE_STRING++"_file_props_symlink"),
+ AFile = filename:join(Dir, "a_file"),
+ Alias = filename:join(Dir, "symlink"),
+ ok = file:make_dir(Dir),
+ ok = file:write_file(AFile, "not that big\n"),
+ case file:make_symlink(AFile, Alias) of
+ {error, enotsup} ->
+ {skip, "Links not supported on this platform"};
+ {error, eperm} ->
+ {win32,_} = os:type(),
+ {skip, "Windows user not privileged to create symlinks"};
+ ok ->
+ {_,_} = LastMod = filelib:last_modified(AFile),
+ LastMod = filelib:last_modified(Alias),
+ LastMod = filelib:last_modified(Alias, erl_prim_loader),
+ LastMod = filelib:last_modified(Alias, prim_file),
+ FileSize = filelib:file_size(AFile),
+ FileSize = filelib:file_size(Alias),
+ FileSize = filelib:file_size(Alias, erl_prim_loader),
+ FileSize = filelib:file_size(Alias, prim_file)
+ end.
diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl
index 8aeec07ae8..336065b258 100644
--- a/lib/stdlib/test/gen_fsm_SUITE.erl
+++ b/lib/stdlib/test/gen_fsm_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. 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
@@ -31,7 +31,9 @@
-export([shutdown/1]).
--export([ sys1/1, call_format_status/1, error_format_status/1, get_state/1, replace_state/1]).
+-export([ sys1/1,
+ call_format_status/1, error_format_status/1, terminate_crash_format/1,
+ get_state/1, replace_state/1]).
-export([hibernate/1,hiber_idle/3,hiber_wakeup/3,hiber_idle/2,hiber_wakeup/2]).
@@ -66,7 +68,8 @@ groups() ->
start8, start9, start10, start11, start12]},
{abnormal, [], [abnormal1, abnormal2]},
{sys, [],
- [sys1, call_format_status, error_format_status, get_state, replace_state]}].
+ [sys1, call_format_status, error_format_status, terminate_crash_format,
+ get_state, replace_state]}].
init_per_suite(Config) ->
Config.
@@ -403,7 +406,7 @@ error_format_status(Config) when is_list(Config) ->
receive
{error,_GroupLeader,{Pid,
"** State machine"++_,
- [Pid,{_,_,badreturn},idle,StateData,_]}} ->
+ [Pid,{_,_,badreturn},idle,{formatted,StateData},_]}} ->
ok;
Other ->
?line io:format("Unexpected: ~p", [Other]),
@@ -413,6 +416,29 @@ error_format_status(Config) when is_list(Config) ->
process_flag(trap_exit, OldFl),
ok.
+terminate_crash_format(Config) when is_list(Config) ->
+ error_logger_forwarder:register(),
+ OldFl = process_flag(trap_exit, true),
+ StateData = crash_terminate,
+ {ok, Pid} = gen_fsm:start(gen_fsm_SUITE, {state_data, StateData}, []),
+ stop_it(Pid),
+ receive
+ {error,_GroupLeader,{Pid,
+ "** State machine"++_,
+ [Pid,{_,_,_},idle,{formatted, StateData},_]}} ->
+ ok;
+ Other ->
+ io:format("Unexpected: ~p", [Other]),
+ ?t:fail()
+ after 5000 ->
+ io:format("Timeout: expected error logger msg", []),
+ ?t:fail()
+ end,
+ [] = ?t:messages_get(),
+ process_flag(trap_exit, OldFl),
+ ok.
+
+
get_state(Config) when is_list(Config) ->
State = self(),
{ok, Pid} = gen_fsm:start(?MODULE, {state_data, State}, []),
@@ -867,7 +893,8 @@ init({state_data, StateData}) ->
init(_) ->
{ok, idle, state_data}.
-
+terminate(_, _State, crash_terminate) ->
+ exit({crash, terminate});
terminate({From, stopped}, State, _Data) ->
From ! {self(), {stopped, State}},
ok;
@@ -1005,6 +1032,6 @@ handle_sync_event({get, _Pid}, _From, State, Data) ->
{reply, {state, State, Data}, State, Data}.
format_status(terminate, [_Pdict, StateData]) ->
- StateData;
+ {formatted, StateData};
format_status(normal, [_Pdict, _StateData]) ->
[format_status_called].
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index 960e7f60e7..42694d8b5d 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. 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
@@ -32,7 +32,8 @@
spec_init_local_registered_parent/1,
spec_init_global_registered_parent/1,
otp_5854/1, hibernate/1, otp_7669/1, call_format_status/1,
- error_format_status/1, get_state/1, replace_state/1, call_with_huge_message_queue/1
+ error_format_status/1, terminate_crash_format/1,
+ get_state/1, replace_state/1, call_with_huge_message_queue/1
]).
% spawn export
@@ -56,7 +57,8 @@ all() ->
call_remote_n3, spec_init,
spec_init_local_registered_parent,
spec_init_global_registered_parent, otp_5854, hibernate,
- otp_7669, call_format_status, error_format_status,
+ otp_7669,
+ call_format_status, error_format_status, terminate_crash_format,
get_state, replace_state,
call_with_huge_message_queue].
@@ -273,7 +275,7 @@ crash(Config) when is_list(Config) ->
receive
{error,_GroupLeader4,{Pid4,
"** Generic server"++_,
- [Pid4,crash,state4,crashed]}} ->
+ [Pid4,crash,{formatted, state4},crashed]}} ->
ok;
Other4a ->
?line io:format("Unexpected: ~p", [Other4a]),
@@ -1024,7 +1026,7 @@ error_format_status(Config) when is_list(Config) ->
receive
{error,_GroupLeader,{Pid,
"** Generic server"++_,
- [Pid,crash,State,crashed]}} ->
+ [Pid,crash,{formatted, State},crashed]}} ->
ok;
Other ->
?line io:format("Unexpected: ~p", [Other]),
@@ -1034,6 +1036,31 @@ error_format_status(Config) when is_list(Config) ->
process_flag(trap_exit, OldFl),
ok.
+%% Verify that error when terminating correctly calls our format_status/2 fun
+%%
+terminate_crash_format(Config) when is_list(Config) ->
+ error_logger_forwarder:register(),
+ OldFl = process_flag(trap_exit, true),
+ State = crash_terminate,
+ {ok, Pid} = gen_server:start_link(?MODULE, {state, State}, []),
+ gen_server:call(Pid, stop),
+ receive {'EXIT', Pid, {crash, terminate}} -> ok end,
+ receive
+ {error,_GroupLeader,{Pid,
+ "** Generic server"++_,
+ [Pid,stop, {formatted, State},{crash, terminate}]}} ->
+ ok;
+ Other ->
+ io:format("Unexpected: ~p", [Other]),
+ ?t:fail()
+ after 5000 ->
+ io:format("Timeout: expected error logger msg", []),
+ ?t:fail()
+ end,
+ ?t:messages_get(),
+ process_flag(trap_exit, OldFl),
+ ok.
+
%% Verify that sys:get_state correctly returns gen_server state
%%
get_state(suite) ->
@@ -1323,10 +1350,12 @@ terminate({From, stopped}, _State) ->
terminate({From, stopped_info}, _State) ->
From ! {self(), stopped_info},
ok;
+terminate(_, crash_terminate) ->
+ exit({crash, terminate});
terminate(_Reason, _State) ->
ok.
format_status(terminate, [_PDict, State]) ->
- State;
+ {formatted, State};
format_status(normal, [_PDict, _State]) ->
format_status_called.
diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl
index 5a8971c071..3a76275f31 100644
--- a/lib/stdlib/test/io_SUITE.erl
+++ b/lib/stdlib/test/io_SUITE.erl
@@ -30,7 +30,7 @@
io_fread_newlines/1, otp_8989/1, io_lib_fread_literal/1,
printable_range/1,
io_lib_print_binary_depth_one/1, otp_10302/1, otp_10755/1,
- otp_10836/1]).
+ otp_10836/1, io_lib_width_too_small/1]).
-export([pretty/2]).
@@ -69,7 +69,8 @@ all() ->
io_lib_collect_line_3_wb, cr_whitespace_in_string,
io_fread_newlines, otp_8989, io_lib_fread_literal,
printable_range,
- io_lib_print_binary_depth_one, otp_10302, otp_10755, otp_10836].
+ io_lib_print_binary_depth_one, otp_10302, otp_10755, otp_10836,
+ io_lib_width_too_small].
groups() ->
[].
@@ -2213,3 +2214,8 @@ compile_file(File, Text, Config) ->
try compile:file(Fname, [return])
after ok %file:delete(Fname)
end.
+
+io_lib_width_too_small(Config) ->
+ "**" = lists:flatten(io_lib:format("~2.3w", [3.14])),
+ "**" = lists:flatten(io_lib:format("~2.5w", [3.14])),
+ ok.
diff --git a/lib/stdlib/test/maps_SUITE.erl b/lib/stdlib/test/maps_SUITE.erl
new file mode 100644
index 0000000000..dda20a615b
--- /dev/null
+++ b/lib/stdlib/test/maps_SUITE.erl
@@ -0,0 +1,80 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2014. 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
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%%----------------------------------------------------------------
+%%% Purpose: Test suite for the 'maps' module.
+%%%-----------------------------------------------------------------
+
+-module(maps_SUITE).
+
+-include_lib("test_server/include/test_server.hrl").
+
+-define(default_timeout, ?t:minutes(1)).
+
+% Test server specific exports
+-export([all/0]).
+-export([suite/0]).
+-export([init_per_suite/1]).
+-export([end_per_suite/1]).
+-export([init_per_testcase/2]).
+-export([end_per_testcase/2]).
+
+-export([t_get_3/1,t_with_2/1,t_without_2/1]).
+
+suite() ->
+ [{ct_hooks, [ts_install_cth]}].
+
+all() ->
+ [t_get_3,t_with_2,t_without_2].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_Case, Config) ->
+ Dog=test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+
+end_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+t_get_3(Config) when is_list(Config) ->
+ Map = #{ key1 => value1, key2 => value2 },
+ DefaultValue = "Default value",
+ value1 = maps:get(key1, Map, DefaultValue),
+ value2 = maps:get(key2, Map, DefaultValue),
+ DefaultValue = maps:get(key3, Map, DefaultValue),
+ ok.
+
+t_without_2(_Config) ->
+ Ki = [11,22,33,44,55,66,77,88,99],
+ M0 = maps:from_list([{{k,I},{v,I}}||I<-lists:seq(1,100)]),
+ M1 = maps:from_list([{{k,I},{v,I}}||I<-lists:seq(1,100) -- Ki]),
+ M1 = maps:without([{k,I}||I <- Ki],M0),
+ ok.
+
+t_with_2(_Config) ->
+ Ki = [11,22,33,44,55,66,77,88,99],
+ M0 = maps:from_list([{{k,I},{v,I}}||I<-lists:seq(1,100)]),
+ M1 = maps:from_list([{{k,I},{v,I}}||I<-Ki]),
+ M1 = maps:with([{k,I}||I <- Ki],M0),
+ ok.
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index e016432f4d..f841e2c4a6 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -2532,6 +2532,11 @@ otp_6554(Config) when is_list(Config) ->
"\n end.\nok.\n" =
t(<<"begin F = fun() -> foo end, 1 end. B = F(). C = 17. b().">>),
+ ?line "3: command not found" = comm_err(<<"#{v(3) => v}.">>),
+ ?line "3: command not found" = comm_err(<<"#{k => v(3)}.">>),
+ ?line "3: command not found" = comm_err(<<"#{v(3) := v}.">>),
+ ?line "3: command not found" = comm_err(<<"#{k := v(3)}.">>),
+ ?line "3: command not found" = comm_err(<<"(v(3))#{}.">>),
%% Tests I'd like to do: (you should try them manually)
%% "catch spawn_link(fun() -> timer:sleep(1000), exit(foo) end)."
%% "** exception error: foo" should be output after 1 second
diff --git a/lib/stdlib/test/stdlib_SUITE.erl b/lib/stdlib/test/stdlib_SUITE.erl
index 53a34511d9..59821220b4 100644
--- a/lib/stdlib/test/stdlib_SUITE.erl
+++ b/lib/stdlib/test/stdlib_SUITE.erl
@@ -94,10 +94,10 @@ appup_tests(App,{OkVsns,NokVsns}) ->
ok.
create_test_vsns(App) ->
- This = erlang:system_info(otp_release),
- FirstMajor = previous_major(This),
+ ThisMajor = erlang:system_info(otp_release),
+ FirstMajor = previous_major(ThisMajor),
SecondMajor = previous_major(FirstMajor),
- Ok = app_vsn(App,[FirstMajor]),
+ Ok = app_vsn(App,[ThisMajor,FirstMajor]),
Nok0 = app_vsn(App,[SecondMajor]),
Nok = case Ok of
[Ok1|_] ->
@@ -108,9 +108,9 @@ create_test_vsns(App) ->
{Ok,Nok}.
previous_major("17") ->
- "r16";
-previous_major("r"++Rel) ->
- "r"++previous_major(Rel);
+ "r16b";
+previous_major("r16b") ->
+ "r15b";
previous_major(Rel) ->
integer_to_list(list_to_integer(Rel)-1).
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index ac5a34c3bc..836ea7c030 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. 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
@@ -60,7 +60,7 @@
simple_one_for_one_extra/1, simple_one_for_one_shutdown/1]).
%% Misc tests
--export([child_unlink/1, tree/1, count_children_memory/1,
+-export([child_unlink/1, tree/1, count_children/1,
do_not_save_start_parameters_for_temporary_children/1,
do_not_save_child_specs_for_temporary_children/1,
simple_one_for_one_scale_many_temporary_children/1,
@@ -82,7 +82,7 @@ all() ->
{group, normal_termination},
{group, shutdown_termination},
{group, abnormal_termination}, child_unlink, tree,
- count_children_memory, do_not_save_start_parameters_for_temporary_children,
+ count_children, do_not_save_start_parameters_for_temporary_children,
do_not_save_child_specs_for_temporary_children,
simple_one_for_one_scale_many_temporary_children, temporary_bystander,
simple_global_supervisor, hanging_restart_loop, hanging_restart_loop_simple].
@@ -129,23 +129,10 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-init_per_testcase(count_children_memory, Config) ->
- try erlang:memory() of
- _ ->
- erts_debug:set_internal_state(available_internal_state, true),
- Dog = ?t:timetrap(?TIMEOUT),
- [{watchdog,Dog}|Config]
- catch error:notsup ->
- {skip, "+Meamin used during test; erlang:memory/1 not available"}
- end;
init_per_testcase(_Case, Config) ->
Dog = ?t:timetrap(?TIMEOUT),
[{watchdog,Dog}|Config].
-end_per_testcase(count_children_memory, Config) ->
- catch erts_debug:set_internal_state(available_internal_state, false),
- ?t:timetrap_cancel(?config(watchdog,Config)),
- ok;
end_per_testcase(_Case, Config) ->
?t:timetrap_cancel(?config(watchdog,Config)),
ok.
@@ -1249,34 +1236,24 @@ tree(Config) when is_list(Config) ->
[0,0,0,0] = get_child_counts(NewSup2).
%%-------------------------------------------------------------------------
-%% Test that count_children does not eat memory.
-count_children_memory(Config) when is_list(Config) ->
+%% Test count_children
+count_children(Config) when is_list(Config) ->
process_flag(trap_exit, true),
Child = {child, {supervisor_1, start_child, []}, temporary, 1000,
worker, []},
{ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
[supervisor:start_child(sup_test, []) || _Ignore <- lists:seq(1,1000)],
- garbage_collect(),
- _Size1 = proc_memory(),
Children = supervisor:which_children(sup_test),
- _Size2 = proc_memory(),
ChildCount = get_child_counts(sup_test),
- _Size3 = proc_memory(),
[supervisor:start_child(sup_test, []) || _Ignore2 <- lists:seq(1,1000)],
- garbage_collect(),
- Children2 = supervisor:which_children(sup_test),
- Size4 = proc_memory(),
ChildCount2 = get_child_counts(sup_test),
- Size5 = proc_memory(),
+ Children2 = supervisor:which_children(sup_test),
- garbage_collect(),
- Children3 = supervisor:which_children(sup_test),
- Size6 = proc_memory(),
ChildCount3 = get_child_counts(sup_test),
- Size7 = proc_memory(),
+ Children3 = supervisor:which_children(sup_test),
1000 = length(Children),
[1,1000,0,1000] = ChildCount,
@@ -1285,27 +1262,9 @@ count_children_memory(Config) when is_list(Config) ->
Children3 = Children2,
ChildCount3 = ChildCount2,
- %% count_children consumes memory using an accumulator function,
- %% but the space can be reclaimed incrementally,
- %% which_children may generate garbage that will be reclaimed later.
- case (Size5 =< Size4) of
- true -> ok;
- false ->
- test_server:fail({count_children, used_more_memory,Size4,Size5})
- end,
- case Size7 =< Size6 of
- true -> ok;
- false ->
- test_server:fail({count_children, used_more_memory,Size6,Size7})
- end,
-
[terminate(SupPid, Pid, child, kill) || {undefined, Pid, worker, _Modules} <- Children3],
[1,0,0,0] = get_child_counts(sup_test).
-proc_memory() ->
- erts_debug:set_internal_state(wait, deallocations),
- erlang:memory(processes_used).
-
%%-------------------------------------------------------------------------
%% Temporary children shall not be restarted so they should not save
%% start parameters, as it potentially can take up a huge amount of
@@ -1483,7 +1442,7 @@ simple_one_for_one_scale_many_temporary_children(_Config) ->
if T1 > 0 ->
Scaling = T2 div T1,
- if Scaling > 20 ->
+ if Scaling > 50 ->
%% The scaling shoul be linear (i.e.10, really), but we
%% give some extra here to avoid failing the test
%% unecessarily.
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index 5bc34e35af..6349139925 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -23,7 +23,7 @@
create_long_names/1, bad_tar/1, errors/1, extract_from_binary/1,
extract_from_binary_compressed/1,
extract_from_open_file/1, symlinks/1, open_add_close/1, cooked_compressed/1,
- memory/1]).
+ memory/1,unicode/1]).
-include_lib("test_server/include/test_server.hrl").
-include_lib("kernel/include/file.hrl").
@@ -34,7 +34,7 @@ all() ->
[borderline, atomic, long_names, create_long_names,
bad_tar, errors, extract_from_binary,
extract_from_binary_compressed, extract_from_open_file,
- symlinks, open_add_close, cooked_compressed, memory].
+ symlinks, open_add_close, cooked_compressed, memory, unicode].
groups() ->
[].
@@ -73,6 +73,7 @@ borderline(Config) when is_list(Config) ->
?line lists:foreach(fun(Size) -> borderline_test(Size, TempDir) end,
[0, 1, 10, 13, 127, 333, Record-1, Record, Record+1,
+ Block-2*Record-1, Block-2*Record, Block-2*Record+1,
Block-Record-1, Block-Record, Block-Record+1,
Block-1, Block, Block+1,
Block+Record-1, Block+Record, Block+Record+1]),
@@ -726,6 +727,56 @@ memory(Config) when is_list(Config) ->
?line ok = delete_files([Name1,Name2]),
ok.
+%% Test filenames with characters outside the US ASCII range.
+unicode(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ do_unicode(PrivDir),
+ case has_transparent_naming() of
+ true ->
+ Pa = filename:dirname(code:which(?MODULE)),
+ Node = start_node(unicode, "+fnl -pa "++Pa),
+ ok = rpc:call(Node, erlang, apply,
+ [fun() -> do_unicode(PrivDir) end,[]]),
+ true = test_server:stop_node(Node),
+ ok;
+ false ->
+ ok
+ end.
+
+has_transparent_naming() ->
+ case os:type() of
+ {unix,darwin} -> false;
+ {unix,_} -> true;
+ _ -> false
+ end.
+
+do_unicode(PrivDir) ->
+ ok = file:set_cwd(PrivDir),
+ ok = file:make_dir("unicöde"),
+
+ Names = unicode_create_files(),
+ Tar = "unicöde.tar",
+ ok = erl_tar:create(Tar, ["unicöde"], []),
+ {ok,Names} = erl_tar:table(Tar, []),
+ _ = [ok = file:delete(Name) || Name <- Names],
+ ok = erl_tar:extract(Tar),
+ _ = [{ok,_} = file:read_file(Name) || Name <- Names],
+ _ = [ok = file:delete(Name) || Name <- Names],
+ ok = file:del_dir("unicöde"),
+ ok.
+
+unicode_create_files() ->
+ FileA = "unicöde/smörgåsbord",
+ ok = file:write_file(FileA, "yum!\n"),
+ [FileA|case file:native_name_encoding() of
+ utf8 ->
+ FileB = "unicöde/Хороший файл!",
+ ok = file:write_file(FileB, "But almost empty.\n"),
+ [FileB];
+ latin1 ->
+ []
+ end].
+
%% Delete the given list of files.
delete_files([]) -> ok;
delete_files([Item|Rest]) ->
@@ -791,3 +842,14 @@ make_temp_dir(Base, I) ->
ok -> Name;
{error,eexist} -> make_temp_dir(Base, I+1)
end.
+
+start_node(Name, Args) ->
+ [_,Host] = string:tokens(atom_to_list(node()), "@"),
+ ct:log("Trying to start ~w@~s~n", [Name,Host]),
+ case test_server:start_node(Name, peer, [{args,Args}]) of
+ {error,Reason} ->
+ test_server:fail(Reason);
+ {ok,Node} ->
+ ct:log("Node ~p started~n", [Node]),
+ Node
+ end.
diff --git a/lib/stdlib/test/unicode_SUITE.erl b/lib/stdlib/test/unicode_SUITE.erl
index e2d789bbe6..10b29d0d28 100644
--- a/lib/stdlib/test/unicode_SUITE.erl
+++ b/lib/stdlib/test/unicode_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2014. 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
@@ -98,7 +98,7 @@ ex_binaries_errors_utf8(Config) when is_list(Config) ->
unicode:characters_to_list(Chomped),
BrokenPart = iolist_to_binary(DeepBrokenPart2)
end || X <- lists:seq(1,OKLen) ]
- end || N <- lists:seq(1,20) ],
+ end || N <- lists:seq(1,21,4) ],
ok.
ex_binaries_errors_utf16_little(Config) when is_list(Config) ->
@@ -124,7 +124,7 @@ ex_binaries_errors_utf16_little(Config) when is_list(Config) ->
unicode:characters_to_list(Chomped,{utf16,little}),
BrokenPart = iolist_to_binary(DeepBrokenPart2)
end || X <- lists:seq(1,OKLen) ]
- end || N <- lists:seq(1,15) ],
+ end || N <- lists:seq(1,16,3) ],
ok.
ex_binaries_errors_utf16_big(Config) when is_list(Config) ->
BrokenPart = << <<X:16/big>> || X <- lists:seq(16#DC00,16#DFFF) >>,
@@ -149,7 +149,7 @@ ex_binaries_errors_utf16_big(Config) when is_list(Config) ->
unicode:characters_to_list(Chomped,{utf16,big}),
BrokenPart = iolist_to_binary(DeepBrokenPart2)
end || X <- lists:seq(1,OKLen) ]
- end || N <- lists:seq(1,15) ],
+ end || N <- lists:seq(1,16,3) ],
ok.
ex_binaries_errors_utf32_big(Config) when is_list(Config) ->
@@ -175,7 +175,7 @@ ex_binaries_errors_utf32_big(Config) when is_list(Config) ->
unicode:characters_to_list(Chomped,{utf32,big}),
BrokenPart = iolist_to_binary(DeepBrokenPart2)
end || X <- lists:seq(1,OKLen) ]
- end || N <- lists:seq(1,15) ],
+ end || N <- lists:seq(1,16,3) ],
ok.
ex_binaries_errors_utf32_little(Config) when is_list(Config) ->
@@ -201,7 +201,7 @@ ex_binaries_errors_utf32_little(Config) when is_list(Config) ->
unicode:characters_to_list(Chomped,{utf32,little}),
BrokenPart = iolist_to_binary(DeepBrokenPart2)
end || X <- lists:seq(1,OKLen) ]
- end || N <- lists:seq(1,15) ],
+ end || N <- lists:seq(1,16,3) ],
ok.
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index 37a6590b06..b522c3ea3c 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 2.0
+STDLIB_VSN = 2.2