aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.dir-locals.el15
-rw-r--r--erts/emulator/beam/beam_bif_load.c8
-rw-r--r--erts/emulator/beam/beam_emu.c10
-rw-r--r--erts/emulator/beam/erl_gc.c158
-rw-r--r--erts/emulator/beam/erl_hl_timer.c3
-rw-r--r--erts/emulator/beam/erl_message.c2
-rw-r--r--erts/emulator/beam/erl_process.c11
-rw-r--r--erts/emulator/beam/erl_process_dump.c3
-rw-r--r--erts/emulator/test/process_SUITE.erl10
-rw-r--r--lib/common_test/src/common_test.app.src1
-rw-r--r--lib/common_test/test/Makefile3
-rw-r--r--lib/common_test/test/ct_SUITE.erl53
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/chars4
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/chars.erl32
-rw-r--r--lib/hipe/cerl/erl_types.erl139
-rw-r--r--lib/kernel/doc/src/code.xml2
-rw-r--r--lib/kernel/doc/src/config.xml4
-rw-r--r--lib/kernel/doc/src/seq_trace.xml6
-rw-r--r--lib/stdlib/doc/src/ets.xml4
-rw-r--r--lib/stdlib/doc/src/gen_fsm.xml5
-rw-r--r--lib/stdlib/doc/src/gen_server.xml5
-rw-r--r--lib/stdlib/src/erl_eval.erl1
-rw-r--r--lib/stdlib/src/erl_parse.yrl1
-rw-r--r--system/doc/efficiency_guide/binaryhandling.xml81
-rw-r--r--system/doc/efficiency_guide/commoncaveats.xml8
-rw-r--r--system/doc/efficiency_guide/functions.xml11
-rw-r--r--system/doc/efficiency_guide/introduction.xml8
-rw-r--r--system/doc/efficiency_guide/listhandling.xml16
-rw-r--r--system/doc/efficiency_guide/processes.xml10
-rw-r--r--system/doc/reference_manual/character_set.xml6
-rw-r--r--system/doc/reference_manual/data_types.xml5
-rw-r--r--system/doc/reference_manual/errors.xml8
-rw-r--r--system/doc/reference_manual/expressions.xml10
-rw-r--r--system/doc/reference_manual/introduction.xml4
-rw-r--r--system/doc/reference_manual/macros.xml1
-rw-r--r--system/doc/reference_manual/records.xml6
36 files changed, 365 insertions, 289 deletions
diff --git a/.dir-locals.el b/.dir-locals.el
index 17bf4b636c..2b8f690c8d 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -1,9 +1,14 @@
;; Project-wide Emacs settings
(
- ;; `nil' settings apply to all language modes
- (nil
- ;; Use only spaces for indentation
- (indent-tabs-mode . nil))
+ (erlang-mode (indent-tabs-mode . nil))
+ (autoconf-mode (indent-tabs-mode . nil))
+ (java-mode (indent-tabs-mode . nil))
+ (perl-mode (indent-tabs-mode . nil))
+ (xml-mode (indent-tabs-mode . nil))
+ ;; In C code indentation is 4 spaces and in C++ 2 spaces
+ (c++-mode
+ (indent-tabs-mode . nil)
+ (c-basic-offset . 2))
(c-mode
- ;; In C code, indentation is four spaces
+ (indent-tabs-mode . nil)
(c-basic-offset . 4)))
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index 5c3565f498..09331eb8ad 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -670,7 +670,7 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1)
}
else if (modp->old.code_hdr) {
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- erts_dsprintf(dsbufp, "Module %T must be purged before loading\n",
+ erts_dsprintf(dsbufp, "Module %T must be purged before deleting\n",
BIF_ARG_1);
erts_send_error_to_logger(BIF_P->group_leader, dsbufp);
ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG);
@@ -998,6 +998,12 @@ erts_proc_copy_literal_area(Process *c_p, int *redsp, int fcalls, int gc_allowed
if (any_heap_refs(c_p->heap, c_p->htop, literals, lit_bsize))
goto literal_gc;
*redsp += 1;
+ if (c_p->abandoned_heap) {
+ if (any_heap_refs(c_p->abandoned_heap, c_p->abandoned_heap + c_p->heap_sz,
+ literals, lit_bsize))
+ goto literal_gc;
+ *redsp += 1;
+ }
if (any_heap_refs(c_p->old_heap, c_p->old_htop, literals, lit_bsize))
goto literal_gc;
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index f64d2df8a8..c554bd73b6 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -3549,12 +3549,6 @@ do { \
ErlHeapFragment *live_hf_end;
ErtsCodeMFA *codemfa;
- if (!((FCALLS - 1) > 0 || (FCALLS - 1) > neg_o_reds)) {
- /* If we have run out of reductions, we do a context
- switch before calling the nif */
- goto context_switch;
- }
-
ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_NIF);
codemfa = erts_code_to_codemfa(I);
@@ -3563,8 +3557,8 @@ do { \
DTRACE_NIF_ENTRY(c_p, codemfa);
- SWAPOUT;
- c_p->fcalls = FCALLS - 1;
+ HEAVY_SWAPOUT;
+
PROCESS_MAIN_CHK_LOCKS(c_p);
bif_nif_arity = codemfa->arity;
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 818f89f0e3..643b46c861 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -110,7 +110,7 @@ typedef struct {
static Uint setup_rootset(Process*, Eterm*, int, Rootset*);
static void cleanup_rootset(Rootset *rootset);
-static void remove_message_buffers(Process* p);
+static void deallocate_previous_young_generation(Process *c_p);
static Eterm *full_sweep_heaps(Process *p,
int hibernate,
Eterm *n_heap, Eterm* n_htop,
@@ -153,7 +153,7 @@ static void init_gc_info(ErtsGCInfo *gcip);
static Uint64 next_vheap_size(Process* p, Uint64 vheap, Uint64 vheap_sz);
#ifdef HARDDEBUG
-static void disallow_heap_frag_ref_in_heap(Process* p);
+static void disallow_heap_frag_ref_in_heap(Process *p, Eterm *heap, Eterm *htop);
static void disallow_heap_frag_ref_in_old_heap(Process* p);
#endif
@@ -489,24 +489,26 @@ delay_garbage_collection(Process *p, ErlHeapFragment *live_hf_end, int need, int
hsz = ssz + need + ERTS_DELAY_GC_EXTRA_FREE;
hfrag = new_message_buffer(hsz);
- hfrag->next = p->mbuf;
- p->mbuf = hfrag;
- p->mbuf_sz += hsz;
p->heap = p->htop = &hfrag->mem[0];
p->hend = hend = &hfrag->mem[hsz];
p->stop = stop = hend - ssz;
sys_memcpy((void *) stop, (void *) orig_stop, ssz * sizeof(Eterm));
if (p->abandoned_heap) {
- /* Active heap already in a fragment; adjust it... */
- ErlHeapFragment *hfrag = ((ErlHeapFragment *)
- (((char *) orig_heap)
- - offsetof(ErlHeapFragment, mem)));
- Uint unused = orig_hend - orig_htop;
- ASSERT(hfrag->used_size == hfrag->alloc_size);
- ASSERT(hfrag->used_size >= unused);
- hfrag->used_size -= unused;
- p->mbuf_sz -= unused;
+ /*
+ * Active heap already in a fragment; adjust it and
+ * save it into mbuf list...
+ */
+ ErlHeapFragment *hfrag = ((ErlHeapFragment *)
+ (((char *) orig_heap)
+ - offsetof(ErlHeapFragment, mem)));
+ Uint used = orig_htop - orig_heap;
+ hfrag->used_size = used;
+ p->mbuf_sz += used;
+ ASSERT(hfrag->used_size <= hfrag->alloc_size);
+ ASSERT(!hfrag->off_heap.first && !hfrag->off_heap.overhead);
+ hfrag->next = p->mbuf;
+ p->mbuf = hfrag;
}
else {
/* Do not leave a hole in the abandoned heap... */
@@ -568,17 +570,14 @@ young_gen_usage(Process *p)
}
}
+ hsz += p->htop - p->heap;
aheap = p->abandoned_heap;
- if (!aheap)
- hsz += p->htop - p->heap;
- else {
+ if (aheap) {
/* used in orig heap */
if (p->flags & F_ABANDONED_HEAP_USE)
hsz += aheap[p->heap_sz-1];
else
hsz += p->heap_sz;
- /* Remove unused part in latest fragment */
- hsz -= p->hend - p->htop;
}
return hsz;
}
@@ -812,6 +811,7 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj)
>= erts_proc_sched_data(p)->virtual_reds);
}
+
/*
* Place all living data on a the new heap; deallocate any old heap.
* Meant to be used by hibernate/3.
@@ -858,11 +858,11 @@ erts_garbage_collect_hibernate(Process* p)
p->arg_reg,
p->arity);
- ERTS_HEAP_FREE(ERTS_ALC_T_HEAP,
- (p->abandoned_heap
- ? p->abandoned_heap
- : p->heap),
- p->heap_sz * sizeof(Eterm));
+#ifdef HARDDEBUG
+ disallow_heap_frag_ref_in_heap(p, heap, htop);
+#endif
+
+ deallocate_previous_young_generation(p);
p->heap = heap;
p->high_water = htop;
@@ -897,8 +897,6 @@ erts_garbage_collect_hibernate(Process* p)
sys_memcpy((void *) heap, (void *) p->heap, actual_size*sizeof(Eterm));
ERTS_HEAP_FREE(ERTS_ALC_T_TMP_HEAP, p->heap, p->heap_sz*sizeof(Eterm));
- remove_message_buffers(p);
-
p->stop = p->hend = heap + heap_size;
offs = heap - p->heap;
@@ -1517,22 +1515,16 @@ do_minor(Process *p, ErlHeapFragment *live_hf_end,
}
#endif
- ERTS_HEAP_FREE(ERTS_ALC_T_HEAP,
- (p->abandoned_heap
- ? p->abandoned_heap
- : HEAP_START(p)),
- HEAP_SIZE(p) * sizeof(Eterm));
- p->abandoned_heap = NULL;
- p->flags &= ~F_ABANDONED_HEAP_USE;
+#ifdef HARDDEBUG
+ disallow_heap_frag_ref_in_heap(p, n_heap, n_htop);
+#endif
+
+ deallocate_previous_young_generation(p);
+
HEAP_START(p) = n_heap;
HEAP_TOP(p) = n_htop;
HEAP_SIZE(p) = new_sz;
HEAP_END(p) = n_heap + new_sz;
-
-#ifdef HARDDEBUG
- disallow_heap_frag_ref_in_heap(p);
-#endif
- remove_message_buffers(p);
}
/*
@@ -1621,13 +1613,12 @@ major_collection(Process* p, ErlHeapFragment *live_hf_end,
}
#endif
- ERTS_HEAP_FREE(ERTS_ALC_T_HEAP,
- (p->abandoned_heap
- ? p->abandoned_heap
- : HEAP_START(p)),
- p->heap_sz * sizeof(Eterm));
- p->abandoned_heap = NULL;
- p->flags &= ~F_ABANDONED_HEAP_USE;
+#ifdef HARDDEBUG
+ disallow_heap_frag_ref_in_heap(p, n_heap, n_htop);
+#endif
+
+ deallocate_previous_young_generation(p);
+
HEAP_START(p) = n_heap;
HEAP_TOP(p) = n_htop;
HEAP_SIZE(p) = new_sz;
@@ -1636,11 +1627,6 @@ major_collection(Process* p, ErlHeapFragment *live_hf_end,
HIGH_WATER(p) = HEAP_TOP(p);
-#ifdef HARDDEBUG
- disallow_heap_frag_ref_in_heap(p);
-#endif
- remove_message_buffers(p);
-
if (p->flags & F_ON_HEAP_MSGQ)
move_msgq_to_heap(p);
@@ -1793,22 +1779,56 @@ adjust_after_fullsweep(Process *p, int need, Eterm *objv, int nobj)
return adjusted;
}
-/*
- * Remove all message buffers.
- */
static void
-remove_message_buffers(Process* p)
+deallocate_previous_young_generation(Process *c_p)
{
- if (MBUF(p) != NULL) {
- free_message_buffer(MBUF(p));
- MBUF(p) = NULL;
+ Eterm *orig_heap;
+
+ if (!c_p->abandoned_heap) {
+ orig_heap = c_p->heap;
+ ASSERT(!(c_p->flags & F_ABANDONED_HEAP_USE));
+ }
+ else {
+ ErlHeapFragment *hfrag;
+
+ orig_heap = c_p->abandoned_heap;
+ c_p->abandoned_heap = NULL;
+ c_p->flags &= ~F_ABANDONED_HEAP_USE;
+
+ /*
+ * Temporary heap located in heap fragment
+ * only referred to by 'c_p->heap'. Add it to
+ * 'c_p->mbuf' list and deallocate it as any
+ * other heap fragment...
+ */
+ hfrag = ((ErlHeapFragment *)
+ (((char *) c_p->heap)
+ - offsetof(ErlHeapFragment, mem)));
+
+ ASSERT(!hfrag->off_heap.first);
+ ASSERT(!hfrag->off_heap.overhead);
+ ASSERT(!hfrag->next);
+ ASSERT(c_p->htop - c_p->heap <= hfrag->alloc_size);
+
+ hfrag->next = c_p->mbuf;
+ c_p->mbuf = hfrag;
+ }
+
+ if (c_p->mbuf) {
+ free_message_buffer(c_p->mbuf);
+ c_p->mbuf = NULL;
}
- if (p->msg_frag) {
- erts_cleanup_messages(p->msg_frag);
- p->msg_frag = NULL;
+ if (c_p->msg_frag) {
+ erts_cleanup_messages(c_p->msg_frag);
+ c_p->msg_frag = NULL;
}
- MBUF_SIZE(p) = 0;
+ c_p->mbuf_sz = 0;
+
+ ERTS_HEAP_FREE(ERTS_ALC_T_HEAP,
+ orig_heap,
+ c_p->heap_sz * sizeof(Eterm));
}
+
#ifdef HARDDEBUG
/*
@@ -1820,19 +1840,15 @@ remove_message_buffers(Process* p)
*/
static void
-disallow_heap_frag_ref_in_heap(Process* p)
+disallow_heap_frag_ref_in_heap(Process *p, Eterm *heap, Eterm *htop)
{
Eterm* hp;
- Eterm* htop;
- Eterm* heap;
Uint heap_size;
if (p->mbuf == 0) {
return;
}
- htop = p->htop;
- heap = p->heap;
heap_size = (htop - heap)*sizeof(Eterm);
hp = heap;
@@ -3324,13 +3340,15 @@ within2(Eterm *ptr, Process *p, Eterm *real_htop)
ErtsMessage* mp;
Eterm *htop, *heap;
- if (p->abandoned_heap)
+ if (p->abandoned_heap) {
ERTS_GET_ORIG_HEAP(p, heap, htop);
- else {
- heap = p->heap;
- htop = real_htop ? real_htop : HEAP_TOP(p);
+ if (heap <= ptr && ptr < htop)
+ return 1;
}
+ heap = p->heap;
+ htop = real_htop ? real_htop : HEAP_TOP(p);
+
if (OLD_HEAP(p) && (OLD_HEAP(p) <= ptr && ptr < OLD_HEND(p))) {
return 1;
}
diff --git a/erts/emulator/beam/erl_hl_timer.c b/erts/emulator/beam/erl_hl_timer.c
index 38bebc7576..647fa26811 100644
--- a/erts/emulator/beam/erl_hl_timer.c
+++ b/erts/emulator/beam/erl_hl_timer.c
@@ -2865,7 +2865,8 @@ btm_print(ErtsHLTimer *tmr, void *vbtmp)
if (tmr->timeout <= btmp->now)
left = 0;
- left = ERTS_CLKTCKS_TO_MSEC(tmr->timeout - btmp->now);
+ else
+ left = ERTS_CLKTCKS_TO_MSEC(tmr->timeout - btmp->now);
receiver = ((tmr->head.roflgs & ERTS_TMR_ROFLG_REG_NAME)
? tmr->receiver.name
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index 118adc0c1b..792b69bb37 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -193,7 +193,7 @@ free_message_buffer(ErlHeapFragment* bp)
erts_cleanup_offheap(&bp->off_heap);
ERTS_HEAP_FREE(ERTS_ALC_T_HEAP_FRAG, (void *) bp,
- ERTS_HEAP_FRAG_SIZE(bp->size));
+ ERTS_HEAP_FRAG_SIZE(bp->alloc_size));
bp = next_bp;
}while (bp != NULL);
}
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index a6fdd67088..6928b282ee 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -8642,8 +8642,15 @@ pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks,
* from being selected for normal execution regardless
* of locks held or not held on it...
*/
- ASSERT(!((ERTS_PSFLG_RUNNING|ERTS_PSFLG_DIRTY_RUNNING_SYS)
- & erts_smp_atomic32_read_nob(&rp->state)));
+#ifdef DEBUG
+ {
+ erts_aint32_t state;
+ state = erts_smp_atomic32_read_nob(&rp->state);
+ ASSERT((state & ERTS_PSFLG_PENDING_EXIT)
+ || !(state & (ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_DIRTY_RUNNING_SYS)));
+ }
+#endif
if (!suspend)
resume_process(rp, pid_locks|ERTS_PROC_LOCK_STATUS);
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index e534c33637..7c23b5c76a 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -90,9 +90,12 @@ Uint erts_process_memory(Process *p, int incl_msg_inq) {
erts_doforall_links(ERTS_P_LINKS(p), &erts_one_link_size, &size);
erts_doforall_monitors(ERTS_P_MONITORS(p), &erts_one_mon_size, &size);
size += (p->heap_sz + p->mbuf_sz) * sizeof(Eterm);
+ if (p->abandoned_heap)
+ size += (p->hend - p->heap) * sizeof(Eterm);
if (p->old_hend && p->old_heap)
size += (p->old_hend - p->old_heap) * sizeof(Eterm);
+
size += p->msg.len * sizeof(ErtsMessage);
for (mp = p->msg.first; mp; mp = mp->next)
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 3b8f0072f2..5712c9fa74 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -1622,6 +1622,7 @@ spawn_initial_hangarounds(_Cleaner, NP, Max, Len, HAs) when NP > Max ->
{Len, HAs};
spawn_initial_hangarounds(Cleaner, NP, Max, Len, HAs) ->
Skip = 30,
+ wait_for_proc_slots(Skip+3),
HA1 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
[{priority, low}]),
HA2 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
@@ -1631,6 +1632,15 @@ spawn_initial_hangarounds(Cleaner, NP, Max, Len, HAs) ->
spawn_drop(Skip),
spawn_initial_hangarounds(Cleaner, NP+Skip, Max, Len+3, [HA1,HA2,HA3|HAs]).
+wait_for_proc_slots(MinFreeSlots) ->
+ case erlang:system_info(process_limit) - erlang:system_info(process_count) of
+ FreeSlots when FreeSlots < MinFreeSlots ->
+ receive after 10 -> ok end,
+ wait_for_proc_slots(MinFreeSlots);
+ _FreeSlots ->
+ ok
+ end.
+
spawn_drop(N) when N =< 0 ->
ok;
spawn_drop(N) ->
diff --git a/lib/common_test/src/common_test.app.src b/lib/common_test/src/common_test.app.src
index 77588af59b..dfa321c901 100644
--- a/lib/common_test/src/common_test.app.src
+++ b/lib/common_test/src/common_test.app.src
@@ -22,6 +22,7 @@
{vsn, "%VSN%"},
{modules, [ct_cover,
ct,
+ ct_default_gl,
ct_event,
ct_framework,
ct_ftp,
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index b1eddfedd7..2f0fc2e05a 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -70,7 +70,8 @@ MODULES= \
test_server_SUITE \
test_server_test_lib \
ct_release_test_SUITE \
- ct_log_SUITE
+ ct_log_SUITE \
+ ct_SUITE
ERL_FILES= $(MODULES:%=%.erl)
HRL_FILES= test_server_test_lib.hrl
diff --git a/lib/common_test/test/ct_SUITE.erl b/lib/common_test/test/ct_SUITE.erl
new file mode 100644
index 0000000000..eb98c2544f
--- /dev/null
+++ b/lib/common_test/test/ct_SUITE.erl
@@ -0,0 +1,53 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ct_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+suite() ->
+ [{timetrap,{seconds,30}}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+all() ->
+ [app_file, appup_file].
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+
+app_file(_Config) ->
+ ok = test_server:app_test(common_test),
+ ok.
+
+appup_file(_Config) ->
+ ok = test_server:appup_test(common_test).
+
diff --git a/lib/dialyzer/test/small_SUITE_data/results/chars b/lib/dialyzer/test/small_SUITE_data/results/chars
new file mode 100644
index 0000000000..2c1f8f8d17
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/chars
@@ -0,0 +1,4 @@
+
+chars.erl:29: Invalid type specification for function chars:f/1. The success typing is (#{'b':=50}) -> 'ok'
+chars.erl:32: Function t1/0 has no local return
+chars.erl:32: The call chars:f(#{'b':=50}) breaks the contract (#{'a':=49,'b'=>50,'c'=>51}) -> 'ok'
diff --git a/lib/dialyzer/test/small_SUITE_data/src/chars.erl b/lib/dialyzer/test/small_SUITE_data/src/chars.erl
new file mode 100644
index 0000000000..1e9c8ab6b9
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/chars.erl
@@ -0,0 +1,32 @@
+-module(chars).
+
+%% ERL-313
+
+-export([t/0]).
+-export([t1/0]).
+
+-record(r, {f :: $A .. $Z}).
+
+-type cs() :: $A..$Z | $a .. $z | $/.
+
+-spec t() -> $0-$0..$9-$0| $?.
+
+t() ->
+ c(#r{f = $z - 3}),
+ c($z - 3),
+ c($B).
+
+-spec c(cs()) -> $3-$0..$9-$0.
+
+c($A + 1) -> 2;
+c(C) ->
+ case C of
+ $z - 3 -> 3;
+ #r{f = $z - 3} -> 7
+ end.
+
+%% Display contract with character in warning:
+-spec f(#{a := $1, b => $2, c => $3}) -> ok. % invalid type spec
+f(_) -> ok.
+
+t1() -> f(#{b => $2}). % breaks the contract
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 5a4cf77b81..ff62cf7499 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -3059,88 +3059,91 @@ is_compat_args([A1|Args1], [A2|Args2]) ->
is_compat_args([], []) -> true;
is_compat_args(_, _) -> false.
-is_compat_arg(A1, A2) ->
- is_specialization(A1, A2) orelse is_specialization(A2, A1).
-
--spec is_specialization(erl_type(), erl_type()) -> boolean().
-
-%% Returns true if the first argument is a specialization of the
-%% second argument in the sense that every type is a specialization of
-%% any(). For example, {_,_} is a specialization of any(), but not of
-%% tuple(). Does not handle variables, but any() and unions (sort of).
-
-is_specialization(T, T) -> true;
-is_specialization(_, ?any) -> true;
-is_specialization(?any, _) -> false;
-is_specialization(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
- (is_specialization(Domain1, Domain2) andalso
- is_specialization(Range1, Range2));
-is_specialization(?list(Contents1, Termination1, Size1),
- ?list(Contents2, Termination2, Size2)) ->
+-spec is_compat_arg(erl_type(), erl_type()) -> boolean().
+
+%% The intention is that 'true' is to be returned iff one of the
+%% arguments is a specialization of the other argument in the sense
+%% that every type is a specialization of any(). For example, {_,_} is
+%% a specialization of any(), but not of tuple(). Does not handle
+%% variables, but any() and unions (sort of). However, the
+%% implementation is more relaxed as any() is compatible to anything.
+
+is_compat_arg(T, T) -> true;
+is_compat_arg(_, ?any) -> true;
+is_compat_arg(?any, _) -> true;
+is_compat_arg(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
+ (is_compat_arg(Domain1, Domain2) andalso
+ is_compat_arg(Range1, Range2));
+is_compat_arg(?list(Contents1, Termination1, Size1),
+ ?list(Contents2, Termination2, Size2)) ->
(Size1 =:= Size2 andalso
- is_specialization(Contents1, Contents2) andalso
- is_specialization(Termination1, Termination2));
-is_specialization(?product(Types1), ?product(Types2)) ->
- specialization_list(Types1, Types2);
-is_specialization(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false;
-is_specialization(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false;
-is_specialization(?tuple(Elements1, Arity, _),
- ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
- specialization_list(Elements1, Elements2);
-is_specialization(?tuple_set([{Arity, List}]),
- ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
- specialization_list(sup_tuple_elements(List), Elements2);
-is_specialization(?tuple(Elements1, Arity, _),
- ?tuple_set([{Arity, List}])) when Arity =/= ?any ->
- specialization_list(Elements1, sup_tuple_elements(List));
-is_specialization(?tuple_set(List1), ?tuple_set(List2)) ->
+ is_compat_arg(Contents1, Contents2) andalso
+ is_compat_arg(Termination1, Termination2));
+is_compat_arg(?product(Types1), ?product(Types2)) ->
+ is_compat_list(Types1, Types2);
+is_compat_arg(?map(Pairs1, DefK1, DefV1), ?map(Pairs2, DefK2, DefV2)) ->
+ (is_compat_list(Pairs1, Pairs2) andalso
+ is_compat_arg(DefK1, DefK2) andalso
+ is_compat_arg(DefV1, DefV2));
+is_compat_arg(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false;
+is_compat_arg(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false;
+is_compat_arg(?tuple(Elements1, Arity, _),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ is_compat_list(Elements1, Elements2);
+is_compat_arg(?tuple_set([{Arity, List}]),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ is_compat_list(sup_tuple_elements(List), Elements2);
+is_compat_arg(?tuple(Elements1, Arity, _),
+ ?tuple_set([{Arity, List}])) when Arity =/= ?any ->
+ is_compat_list(Elements1, sup_tuple_elements(List));
+is_compat_arg(?tuple_set(List1), ?tuple_set(List2)) ->
try
- specialization_list_list([sup_tuple_elements(T) || {_Arity, T} <- List1],
- [sup_tuple_elements(T) || {_Arity, T} <- List2])
+ is_compat_list_list([sup_tuple_elements(T) || {_Arity, T} <- List1],
+ [sup_tuple_elements(T) || {_Arity, T} <- List2])
catch _:_ -> false
end;
-is_specialization(?opaque(_) = T1, T2) ->
- is_specialization(t_opaque_structure(T1), T2);
-is_specialization(T1, ?opaque(_) = T2) ->
- is_specialization(T1, t_opaque_structure(T2));
-is_specialization(?union(List1)=T1, ?union(List2)=T2) ->
- case specialization_union2(T1, T2) of
- {yes, Type1, Type2} -> is_specialization(Type1, Type2);
- no -> specialization_list(List1, List2)
+is_compat_arg(?opaque(_) = T1, T2) ->
+ is_compat_arg(t_opaque_structure(T1), T2);
+is_compat_arg(T1, ?opaque(_) = T2) ->
+ is_compat_arg(T1, t_opaque_structure(T2));
+is_compat_arg(?union(List1)=T1, ?union(List2)=T2) ->
+ case is_compat_union2(T1, T2) of
+ {yes, Type1, Type2} -> is_compat_arg(Type1, Type2);
+ no -> is_compat_list(List1, List2)
end;
-is_specialization(?union(List), T2) ->
+is_compat_arg(?union(List), T2) ->
case unify_union(List) of
- {yes, Type} -> is_specialization(Type, T2);
+ {yes, Type} -> is_compat_arg(Type, T2);
no -> false
end;
-is_specialization(T1, ?union(List)) ->
+is_compat_arg(T1, ?union(List)) ->
case unify_union(List) of
- {yes, Type} -> is_specialization(T1, Type);
+ {yes, Type} -> is_compat_arg(T1, Type);
no -> false
end;
-is_specialization(?var(_), _) -> exit(error);
-is_specialization(_, ?var(_)) -> exit(error);
-is_specialization(?none, _) -> false;
-is_specialization(_, ?none) -> false;
-is_specialization(?unit, _) -> false;
-is_specialization(_, ?unit) -> false;
-is_specialization(#c{}, #c{}) -> false.
+is_compat_arg(?var(_), _) -> exit(error);
+is_compat_arg(_, ?var(_)) -> exit(error);
+is_compat_arg(?none, _) -> false;
+is_compat_arg(_, ?none) -> false;
+is_compat_arg(?unit, _) -> false;
+is_compat_arg(_, ?unit) -> false;
+is_compat_arg(#c{}, #c{}) -> false.
-specialization_list_list(LL1, LL2) ->
- length(LL1) =:= length(LL2) andalso specialization_list_list1(LL1, LL2).
+is_compat_list_list(LL1, LL2) ->
+ length(LL1) =:= length(LL2) andalso is_compat_list_list1(LL1, LL2).
-specialization_list_list1([], []) -> true;
-specialization_list_list1([L1|LL1], [L2|LL2]) ->
- specialization_list(L1, L2) andalso specialization_list_list1(LL1, LL2).
+is_compat_list_list1([], []) -> true;
+is_compat_list_list1([L1|LL1], [L2|LL2]) ->
+ is_compat_list(L1, L2) andalso is_compat_list_list1(LL1, LL2).
-specialization_list(L1, L2) ->
- length(L1) =:= length(L2) andalso specialization_list1(L1, L2).
+is_compat_list(L1, L2) ->
+ length(L1) =:= length(L2) andalso is_compat_list1(L1, L2).
-specialization_list1([], []) -> true;
-specialization_list1([T1|L1], [T2|L2]) ->
- is_specialization(T1, T2) andalso specialization_list1(L1, L2).
+is_compat_list1([], []) -> true;
+is_compat_list1([T1|L1], [T2|L2]) ->
+ is_compat_arg(T1, T2) andalso is_compat_list1(L1, L2).
-specialization_union2(?union(List1)=T1, ?union(List2)=T2) ->
+is_compat_union2(?union(List1)=T1, ?union(List2)=T2) ->
case {unify_union(List1), unify_union(List2)} of
{{yes, Type1}, {yes, Type2}} -> {yes, Type1, Type2};
{{yes, Type1}, no} -> {yes, Type1, T2};
@@ -4534,6 +4537,8 @@ from_form({atom, _L, Atom}, _S, _D, L, C) ->
{t_atom(Atom), L, C};
from_form({integer, _L, Int}, _S, _D, L, C) ->
{t_integer(Int), L, C};
+from_form({char, _L, Char}, _S, _D, L, C) ->
+ {t_integer(Char), L, C};
from_form({op, _L, _Op, _Arg} = Op, _S, _D, L, C) ->
case erl_eval:partial_eval(Op) of
{integer, _, Val} ->
@@ -5048,6 +5053,7 @@ check_record_fields({remote_type, _L, [{atom, _, _}, {atom, _, _}, Args]},
list_check_record_fields(Args, S, C);
check_record_fields({atom, _L, _}, _S, C) -> C;
check_record_fields({integer, _L, _}, _S, C) -> C;
+check_record_fields({char, _L, _}, _S, C) -> C;
check_record_fields({op, _L, _Op, _Arg}, _S, C) -> C;
check_record_fields({op, _L, _Op, _Arg1, _Arg2}, _S, C) -> C;
check_record_fields({type, _L, tuple, any}, _S, C) -> C;
@@ -5149,6 +5155,7 @@ t_form_to_string({var, _L, Name}) -> atom_to_list(Name);
t_form_to_string({atom, _L, Atom}) ->
io_lib:write_string(atom_to_list(Atom), $'); % To quote or not to quote... '
t_form_to_string({integer, _L, Int}) -> integer_to_list(Int);
+t_form_to_string({char, _L, Char}) -> integer_to_list(Char);
t_form_to_string({op, _L, _Op, _Arg} = Op) ->
case erl_eval:partial_eval(Op) of
{integer, _, _} = Int -> t_form_to_string(Int);
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml
index f881fd76fd..878a450f0f 100644
--- a/lib/kernel/doc/src/code.xml
+++ b/lib/kernel/doc/src/code.xml
@@ -258,7 +258,7 @@ zip:create("mnesia-4.4.7.ez",
both strings and atoms, but a future release will probably only allow
the arguments that are documented.</p>
- <p>As from Erlang/OTP R12B, functions in this module generally fail with an
+ <p>Functions in this module generally fail with an
exception if they are passed an incorrect type (for example, an integer or a tuple
where an atom is expected). An error tuple is returned if the argument type
is correct, but there are some other errors (for example, a non-existing directory
diff --git a/lib/kernel/doc/src/config.xml b/lib/kernel/doc/src/config.xml
index c5f37fd036..c10f11b187 100644
--- a/lib/kernel/doc/src/config.xml
+++ b/lib/kernel/doc/src/config.xml
@@ -77,8 +77,8 @@
to update the application configurations.</p>
<p>This means that specifying another <c>.config</c> file, or more
<c>.config</c> files, leads to inconsistent update of application
- configurations. Therefore, in Erlang 5.4/OTP R10B, the syntax of
- <c>sys.config</c> was extended to allow pointing out other
+ configurations. There is, however, a syntax for
+ <c>sys.config</c> that allows pointing out other
<c>.config</c> files:</p>
<code type="none">
[{Application, [{Par, Val}]} | File].</code>
diff --git a/lib/kernel/doc/src/seq_trace.xml b/lib/kernel/doc/src/seq_trace.xml
index ba7259219d..b80e87c118 100644
--- a/lib/kernel/doc/src/seq_trace.xml
+++ b/lib/kernel/doc/src/seq_trace.xml
@@ -427,12 +427,6 @@ prev_cnt := tcurr</code>
built with <c>Erl_Interface</c> only maintains one trace token, which
means that the C-node appears as one process from
the sequential tracing point of view.</p>
- <p>To be able to perform sequential tracing between
- distributed Erlang nodes, the distribution protocol has been
- extended (in a backward compatible way). An Erlang node
- supporting sequential tracing can communicate with an older
- (Erlang/OTP R3B) node but messages passed within that node can
- not be traced.</p>
</section>
<section>
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index 5f5d2b7f36..05401a2d40 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -541,10 +541,6 @@ Error: fun containing local Erlang function calls
<c><anno>Tab</anno></c> is
not of the correct type, or if <c><anno>Item</anno></c> is not
one of the allowed values, a <c>badarg</c> exception is raised.</p>
- <warning>
- <p>In Erlang/OTP R11B and earlier, this function would not fail but
- return <c>undefined</c> for invalid values for <c>Item</c>.</p>
- </warning>
<p>In addition to the <c>{<anno>Item</anno>,<anno>Value</anno>}</c>
pairs defined for <seealso marker="#info/1"><c>info/1</c></seealso>,
the following items are allowed:</p>
diff --git a/lib/stdlib/doc/src/gen_fsm.xml b/lib/stdlib/doc/src/gen_fsm.xml
index de06987d38..719ab2b558 100644
--- a/lib/stdlib/doc/src/gen_fsm.xml
+++ b/lib/stdlib/doc/src/gen_fsm.xml
@@ -534,11 +534,6 @@ gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4
the function call fails.</p>
<p>Return value <c>Reply</c> is defined in the return value
of <c>Module:StateName/3</c>.</p>
- <note>
- <p>The ancient behavior of sometimes consuming the server
- exit message if the server died during the call while
- linked to the client was removed in Erlang 5.6/OTP R12B.</p>
- </note>
</desc>
</func>
</funcs>
diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml
index 4a7dd60858..662076b5f0 100644
--- a/lib/stdlib/doc/src/gen_server.xml
+++ b/lib/stdlib/doc/src/gen_server.xml
@@ -162,11 +162,6 @@ gen_server:abcast -----> Module:handle_cast/2
of <c>Module:handle_call/3</c>.</p>
<p>The call can fail for many reasons, including time-out and the
called <c>gen_server</c> process dying before or during the call.</p>
- <note>
- <p>The ancient behavior of sometimes consuming the server
- exit message if the server died during the call while
- linked to the client was removed in Erlang 5.6/OTP R12B.</p>
- </note>
</desc>
</func>
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 40a34aa30f..eafee346eb 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -1306,6 +1306,7 @@ partial_eval(Expr) ->
ev_expr({op,_,Op,L,R}) -> erlang:Op(ev_expr(L), ev_expr(R));
ev_expr({op,_,Op,A}) -> erlang:Op(ev_expr(A));
ev_expr({integer,_,X}) -> X;
+ev_expr({char,_,X}) -> X;
ev_expr({float,_,X}) -> X;
ev_expr({atom,_,X}) -> X;
ev_expr({tuple,_,Es}) ->
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 9cd95705af..fb5d05ec8e 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -156,6 +156,7 @@ type -> '#' atom '{' field_types '}' : {type, ?anno('$1'),
record, ['$2'|'$4']}.
type -> binary_type : '$1'.
type -> integer : '$1'.
+type -> char : '$1'.
type -> 'fun' '(' ')' : {type, ?anno('$1'), 'fun', []}.
type -> 'fun' '(' fun_type_100 ')' : '$3'.
diff --git a/system/doc/efficiency_guide/binaryhandling.xml b/system/doc/efficiency_guide/binaryhandling.xml
index 0295d18644..91fd9a7cd9 100644
--- a/system/doc/efficiency_guide/binaryhandling.xml
+++ b/system/doc/efficiency_guide/binaryhandling.xml
@@ -32,12 +32,9 @@
<file>binaryhandling.xml</file>
</header>
- <p>In R12B, the most natural way to construct and match binaries is
- significantly faster than in earlier releases.</p>
+ <p>Binaries can be efficiently built in the following way:</p>
- <p>To construct a binary, you can simply write as follows:</p>
-
- <p><em>DO</em> (in R12B) / <em>REALLY DO NOT</em> (in earlier releases)</p>
+ <p><em>DO</em></p>
<code type="erl"><![CDATA[
my_list_to_binary(List) ->
my_list_to_binary(List, <<>>).
@@ -47,21 +44,13 @@ my_list_to_binary([H|T], Acc) ->
my_list_to_binary([], Acc) ->
Acc.]]></code>
- <p>In releases before R12B, <c>Acc</c> is copied in every iteration.
- In R12B, <c>Acc</c> is copied only in the first iteration and extra
- space is allocated at the end of the copied binary. In the next iteration,
- <c>H</c> is written into the extra space. When the extra space runs out,
- the binary is reallocated with more extra space. The extra space allocated
- (or reallocated) is twice the size of the
- existing binary data, or 256, whichever is larger.</p>
-
- <p>The most natural way to match binaries is now the fastest:</p>
+ <p>Binaries can be efficiently matched like this:</p>
- <p><em>DO</em> (in R12B)</p>
+ <p><em>DO</em></p>
<code type="erl"><![CDATA[
my_binary_to_list(<<H,T/binary>>) ->
[H|my_binary_to_list(T)];
-my_binary_to_list(<<>>) -> [].]]></code>
+my_binary_to_list(<<>>) -> [].]]></code>
<section>
<title>How Binaries are Implemented</title>
@@ -138,10 +127,7 @@ my_binary_to_list(<<>>) -> [].]]></code>
pointer to the binary data. For each field that is matched out of
a binary, the position in the match context is incremented.</p>
- <p>In R11B, a match context was only used during a binary matching
- operation.</p>
-
- <p>In R12B, the compiler tries to avoid generating code that
+ <p>The compiler tries to avoid generating code that
creates a sub binary, only to shortly afterwards create a new match
context and discard the sub binary. Instead of creating a sub binary,
the match context is kept.</p>
@@ -155,7 +141,7 @@ my_binary_to_list(<<>>) -> [].]]></code>
<section>
<title>Constructing Binaries</title>
- <p>In R12B, appending to a binary or bitstring
+ <p>Appending to a binary or bitstring
is specially optimized by the <em>runtime system</em>:</p>
<code type="erl"><![CDATA[
@@ -292,7 +278,7 @@ Bin = <<Bin1,...>> %% Bin1 will be COPIED
<p>Let us revisit the example in the beginning of the previous section:</p>
- <p><em>DO</em> (in R12B)</p>
+ <p><em>DO</em></p>
<code type="erl"><![CDATA[
my_binary_to_list(<<H,T/binary>>) ->
[H|my_binary_to_list(T)];
@@ -304,15 +290,14 @@ my_binary_to_list(<<>>) -> [].]]></code>
byte of the binary. 1 byte is matched out and the match context
is updated to point to the second byte in the binary.</p>
- <p>In R11B, at this point a
- <seealso marker="#sub_binary">sub binary</seealso>
- would be created. In R12B,
- the compiler sees that there is no point in creating a sub binary,
- because there will soon be a call to a function (in this case,
+ <p>At this point it would make sense to create a
+ <seealso marker="#sub_binary">sub binary</seealso>,
+ but in this particular example the compiler sees that
+ there will soon be a call to a function (in this case,
to <c>my_binary_to_list/1</c> itself) that immediately will
create a new match context and discard the sub binary.</p>
- <p>Therefore, in R12B, <c>my_binary_to_list/1</c> calls itself
+ <p>Therefore <c>my_binary_to_list/1</c> calls itself
with the match context instead of with a sub binary. The instruction
that initializes the matching operation basically does nothing
when it sees that it was passed a match context instead of a binary.</p>
@@ -321,34 +306,10 @@ my_binary_to_list(<<>>) -> [].]]></code>
the match context will simply be discarded (removed in the next
garbage collection, as there is no longer any reference to it).</p>
- <p>To summarize, <c>my_binary_to_list/1</c> in R12B only needs to create
- <em>one</em> match context and no sub binaries. In R11B, if the binary
- contains <em>N</em> bytes, <em>N+1</em> match contexts and <em>N</em>
- sub binaries are created.</p>
-
- <p>In R11B, the fastest way to match binaries is as follows:</p>
+ <p>To summarize, <c>my_binary_to_list/1</c> only needs to create
+ <em>one</em> match context and no sub binaries.</p>
- <p><em>DO NOT</em> (in R12B)</p>
- <code type="erl"><![CDATA[
-my_complicated_binary_to_list(Bin) ->
- my_complicated_binary_to_list(Bin, 0).
-
-my_complicated_binary_to_list(Bin, Skip) ->
- case Bin of
- <<_:Skip/binary,Byte,_/binary>> ->
- [Byte|my_complicated_binary_to_list(Bin, Skip+1)];
- <<_:Skip/binary>> ->
- []
- end.]]></code>
-
- <p>This function cleverly avoids building sub binaries, but it cannot
- avoid building a match context in each recursion step.
- Therefore, in both R11B and R12B,
- <c>my_complicated_binary_to_list/1</c> builds <em>N+1</em> match
- contexts. (In a future Erlang/OTP release, the compiler might be able
- to generate code that reuses the match context.)</p>
-
- <p>Returning to <c>my_binary_to_list/1</c>, notice that the match context
+ <p>Notice that the match context in <c>my_binary_to_list/1</c>
was discarded when the entire binary had been traversed. What happens if
the iteration stops before it has reached the end of the binary? Will
the optimization still work?</p>
@@ -544,5 +505,15 @@ count3(<<>>, Count) -> Count.]]></code>
not matched out.</p>
</section>
</section>
+
+ <section>
+ <title>Historical Note</title>
+
+ <p>Binary handling was significantly improved in R12B. Because
+ code that was efficient in R11B might not be efficient in R12B,
+ and vice versa, earlier revisions of this Efficiency Guide contained
+ some information about binary handling in R11B.</p>
+ </section>
+
</chapter>
diff --git a/system/doc/efficiency_guide/commoncaveats.xml b/system/doc/efficiency_guide/commoncaveats.xml
index ecfeff0349..94b1c0b222 100644
--- a/system/doc/efficiency_guide/commoncaveats.xml
+++ b/system/doc/efficiency_guide/commoncaveats.xml
@@ -148,10 +148,10 @@ multiple_setelement(T0) ->
<p><c>size/1</c> returns the size for both tuples and binaries.</p>
- <p>Using the new BIFs <c>tuple_size/1</c> and <c>byte_size/1</c>, introduced
- in R12B, gives the compiler and the runtime system more opportunities for
- optimization. Another advantage is that the new BIFs can help Dialyzer to
- find more bugs in your program.</p>
+ <p>Using the BIFs <c>tuple_size/1</c> and <c>byte_size/1</c>
+ gives the compiler and the runtime system more opportunities for
+ optimization. Another advantage is that the BIFs give Dialyzer more
+ type information.</p>
</section>
<section>
diff --git a/system/doc/efficiency_guide/functions.xml b/system/doc/efficiency_guide/functions.xml
index 4a8248e65c..1d0f1f68b7 100644
--- a/system/doc/efficiency_guide/functions.xml
+++ b/system/doc/efficiency_guide/functions.xml
@@ -65,7 +65,7 @@ atom_map1(six) -> 6.</code>
thus, quite efficient even if there are many values) to select which
one of the first three clauses to execute (if any).</item>
- <item>>If none of the first three clauses match, the fourth clause
+ <item>If none of the first three clauses match, the fourth clause
match as a variable always matches.</item>
<item>If the guard test <c>is_integer(Int)</c> succeeds, the fourth
@@ -183,15 +183,6 @@ explicit_map_pairs(Map, Xs0, Ys0) ->
A fun contains an (indirect) pointer to the function that implements
the fun.</p>
- <warning><p><em>Tuples are not fun(s)</em>.
- A "tuple fun", <c>{Module,Function}</c>, is not a fun.
- The cost for calling a "tuple fun" is similar to that
- of <c>apply/3</c> or worse.
- Using "tuple funs" is <em>strongly discouraged</em>,
- as they might not be supported in a future Erlang/OTP release,
- and because there exists a superior alternative from R10B,
- namely the <c>fun Module:Function/Arity</c> syntax.</p></warning>
-
<p><c>apply/3</c> must look up the code for the function to execute
in a hash table. It is therefore always slower than a
direct call or a fun call.</p>
diff --git a/system/doc/efficiency_guide/introduction.xml b/system/doc/efficiency_guide/introduction.xml
index ca4a41c798..b650008ae8 100644
--- a/system/doc/efficiency_guide/introduction.xml
+++ b/system/doc/efficiency_guide/introduction.xml
@@ -46,14 +46,6 @@
to find out where the performance bottlenecks are and optimize only the
bottlenecks. Let other code stay as clean as possible.</p>
- <p>Fortunately, compiler and runtime optimizations introduced in
- Erlang/OTP R12B makes it easier to write code that is both clean and
- efficient. For example, the ugly workarounds needed in R11B and earlier
- releases to get the most speed out of binary pattern matching are
- no longer necessary. In fact, the ugly code is slower
- than the clean code (because the clean code has become faster, not
- because the uglier code has become slower).</p>
-
<p>This Efficiency Guide cannot really teach you how to write efficient
code. It can give you a few pointers about what to avoid and what to use,
and some understanding of how certain language features are implemented.
diff --git a/system/doc/efficiency_guide/listhandling.xml b/system/doc/efficiency_guide/listhandling.xml
index 2ebc877820..ec258d7c2a 100644
--- a/system/doc/efficiency_guide/listhandling.xml
+++ b/system/doc/efficiency_guide/listhandling.xml
@@ -90,7 +90,7 @@ tail_recursive_fib(N, Current, Next, Fibs) ->
<p>Lists comprehensions still have a reputation for being slow.
They used to be implemented using funs, which used to be slow.</p>
- <p>In recent Erlang/OTP releases (including R12B), a list comprehension:</p>
+ <p>A list comprehension:</p>
<code type="erl"><![CDATA[
[Expr(E) || E <- List]]]></code>
@@ -102,7 +102,7 @@ tail_recursive_fib(N, Current, Next, Fibs) ->
[Expr(E)|'lc^0'(Tail, Expr)];
'lc^0'([], _Expr) -> [].</code>
- <p>In R12B, if the result of the list comprehension will <em>obviously</em>
+ <p>If the result of the list comprehension will <em>obviously</em>
not be used, a list will not be constructed. For example, in this code:</p>
<code type="erl"><![CDATA[
@@ -131,6 +131,14 @@ some_function(...),
'lc^0'(Tail, Expr);
'lc^0'([], _Expr) -> [].</code>
+ <p>The compiler also understands that assigning to '_' means that
+ the value will not used. Therefore, the code in the following example
+ will also be optimized:</p>
+
+ <code type="erl"><![CDATA[
+_ = [io:put_chars(E) || E <- List],
+ok.]]></code>
+
</section>
<section>
@@ -209,11 +217,11 @@ some_function(...),
<section>
<title>Recursive List Functions</title>
- <p>In Section 7.2, the following myth was exposed:
+ <p>In section about myths, the following myth was exposed:
<seealso marker="myths#tail_recursive">Tail-Recursive Functions
are Much Faster Than Recursive Functions</seealso>.</p>
- <p>To summarize, in R12B there is usually not much difference between
+ <p>There is usually not much difference between
a body-recursive list function and tail-recursive function that reverses
the list at the end. Therefore, concentrate on writing beautiful code
and forget about the performance of your list functions. In the
diff --git a/system/doc/efficiency_guide/processes.xml b/system/doc/efficiency_guide/processes.xml
index f2d9712f51..bc9daa6666 100644
--- a/system/doc/efficiency_guide/processes.xml
+++ b/system/doc/efficiency_guide/processes.xml
@@ -146,14 +146,14 @@ loop() ->
<section>
<title>Constant Pool</title>
- <p>Constant Erlang terms (also called <em>literals</em>) are now
+ <p>Constant Erlang terms (also called <em>literals</em>) are
kept in constant pools; each loaded module has its own pool.
- The following function does no longer build the tuple every time
+ The following function does not build the tuple every time
it is called (only to have it discarded the next time the garbage
collector was run), but the tuple is located in the module's
constant pool:</p>
- <p><em>DO</em> (in R12B and later)</p>
+ <p><em>DO</em></p>
<code type="erl">
days_in_month(M) ->
element(M, {31,28,31,30,31,30,31,31,30,31,30,31}).</code>
@@ -235,9 +235,7 @@ true
return the same value. Sharing has been lost.</p>
<p>In a future Erlang/OTP release, it might be implemented a
- way to (optionally) preserve sharing. There are no plans to make
- preserving of sharing the default behaviour, as that would
- penalize the vast majority of Erlang applications.</p>
+ way to (optionally) preserve sharing.</p>
</section>
</section>
diff --git a/system/doc/reference_manual/character_set.xml b/system/doc/reference_manual/character_set.xml
index d25f2c001d..f0f4c23608 100644
--- a/system/doc/reference_manual/character_set.xml
+++ b/system/doc/reference_manual/character_set.xml
@@ -32,9 +32,9 @@
<section>
<title>Character Set</title>
- <p>Since Erlang 4.8/OTP R5A, the syntax of Erlang tokens is extended to
- allow the use of the full ISO-8859-1 (Latin-1) character set. This
- is noticeable in the following ways:</p>
+ <p>The syntax of Erlang tokens allow the use of the full
+ ISO-8859-1 (Latin-1) character set. This is noticeable in the
+ following ways:</p>
<list type="bulleted">
<item>
<p>All the Latin-1 printable characters can be used and are
diff --git a/system/doc/reference_manual/data_types.xml b/system/doc/reference_manual/data_types.xml
index e63825b97d..107e403903 100644
--- a/system/doc/reference_manual/data_types.xml
+++ b/system/doc/reference_manual/data_types.xml
@@ -50,10 +50,7 @@
<item><em><c>base</c></em><c>#</c><em><c>value</c></em> <br></br>
Integer with the base <em><c>base</c></em>, that must be an
- integer in the range 2..36. <br></br>
-
- In Erlang 5.2/OTP R9B and earlier versions, the allowed range
- is 2..16.</item>
+ integer in the range 2..36.</item>
</list>
<p><em>Examples:</em></p>
<pre>
diff --git a/system/doc/reference_manual/errors.xml b/system/doc/reference_manual/errors.xml
index e764cf431f..3e2d306561 100644
--- a/system/doc/reference_manual/errors.xml
+++ b/system/doc/reference_manual/errors.xml
@@ -49,8 +49,7 @@
The Erlang programming language has built-in features for
handling of run-time errors.</p>
<p>A run-time error can also be emulated by calling
- <c>erlang:error(Reason)</c> or <c>erlang:error(Reason, Args)</c>
- (those appeared in Erlang 5.4/OTP-R10).</p>
+ <c>erlang:error(Reason)</c> or <c>erlang:error(Reason, Args)</c>.</p>
<p>A run-time error is another name for an exception
of class <c>error</c>.
</p>
@@ -79,7 +78,6 @@
<p>Exceptions are run-time errors or generated errors and
are of three different classes, with different origins. The
<seealso marker="expressions#try">try</seealso> expression
- (new in Erlang 5.4/OTP R10B)
can distinguish between the different classes, whereas the
<seealso marker="expressions#catch">catch</seealso>
expression cannot. They are described in
@@ -94,7 +92,7 @@
<cell align="left" valign="middle"><c>error</c></cell>
<cell align="left" valign="middle">Run-time error,
for example, <c>1+a</c>, or the process called
- <c>erlang:error/1,2</c> (new in Erlang 5.4/OTP R10B)</cell>
+ <c>erlang:error/1,2</c></cell>
</row>
<row>
<cell align="left" valign="middle"><c>exit</c></cell>
@@ -111,7 +109,7 @@
and a stack trace (which aids in finding the code location of
the exception).</p>
<p>The stack trace can be retrieved using
- <c>erlang:get_stacktrace/0</c> (new in Erlang 5.4/OTP R10B)
+ <c>erlang:get_stacktrace/0</c>
from within a <c>try</c> expression, and is returned for
exceptions of class <c>error</c> from a <c>catch</c> expression.</p>
<p>An exception of class <c>error</c> is also known as a run-time
diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml
index 1a3d19aed1..acd1dec901 100644
--- a/system/doc/reference_manual/expressions.xml
+++ b/system/doc/reference_manual/expressions.xml
@@ -123,10 +123,9 @@ member(_Elem, []) ->
or <c>receive</c> expression must be bound in all branches
to have a value outside the expression. Otherwise they
are regarded as 'unsafe' outside the expression.</p>
- <p>For the <c>try</c> expression introduced in
- Erlang 5.4/OTP R10B, variable scoping is limited so that
+ <p>For the <c>try</c> expression variable scoping is limited so that
variables bound in the expression are always 'unsafe' outside
- the expression. This is to be improved.</p>
+ the expression.</p>
</section>
<section>
@@ -189,7 +188,6 @@ f([$p,$r,$e,$f,$i,$x | Str]) -> ...</pre>
<pre>
case {Value, Result} of
{?THRESHOLD+1, ok} -> ...</pre>
- <p>This feature was added in Erlang 5.0/OTP R7.</p>
</section>
</section>
@@ -1348,8 +1346,8 @@ catch
ExceptionBodyN
end</code>
<p>This is an enhancement of
- <seealso marker="#catch">catch</seealso> that appeared in
- Erlang 5.4/OTP R10B. It gives the possibility to:</p>
+ <seealso marker="#catch">catch</seealso>.
+ It gives the possibility to:</p>
<list type="bulleted">
<item>Distinguish between different exception classes.</item>
<item>Choose to handle only the desired ones.</item>
diff --git a/system/doc/reference_manual/introduction.xml b/system/doc/reference_manual/introduction.xml
index abb4ed407d..5701462443 100644
--- a/system/doc/reference_manual/introduction.xml
+++ b/system/doc/reference_manual/introduction.xml
@@ -80,8 +80,8 @@
<item>A <em>list</em> is any number of items. For example,
an argument list can consist of zero, one, or more arguments.</item>
</list>
- <p>If a feature has been added recently, in Erlang 5.0/OTP R7 or
- later, this is mentioned in the text.</p>
+ <p>If a feature has been added in R13A or later,
+ this is mentioned in the text.</p>
</section>
<section>
diff --git a/system/doc/reference_manual/macros.xml b/system/doc/reference_manual/macros.xml
index 5f24473557..b6c740dd10 100644
--- a/system/doc/reference_manual/macros.xml
+++ b/system/doc/reference_manual/macros.xml
@@ -286,7 +286,6 @@ t.erl:5: Warning: -warning("Macro VERSION not defined -- using default version."
argument, is expanded to a string containing the tokens of
the argument. This is similar to the <c>#arg</c> stringifying
construction in C.</p>
- <p>The feature was added in Erlang 5.0/OTP R7.</p>
<p><em>Example:</em></p>
<code type="none">
-define(TESTCALL(Call), io:format("Call ~s: ~w~n", [??Call, Call])).
diff --git a/system/doc/reference_manual/records.xml b/system/doc/reference_manual/records.xml
index 12a3e697cd..1eb13b353e 100644
--- a/system/doc/reference_manual/records.xml
+++ b/system/doc/reference_manual/records.xml
@@ -72,9 +72,9 @@
<pre>
#Name{Field1=Expr1,...,FieldK=ExprK, _=ExprL}</pre>
<p>Omitted fields then get the value of evaluating <c>ExprL</c>
- instead of their default values. This feature was added in
- Erlang 5.1/OTP R8 and is primarily intended to be used to create
- patterns for ETS and Mnesia match functions.</p>
+ instead of their default values. This feature is primarily
+ intended to be used to create patterns for ETS and Mnesia match
+ functions.</p>
<p><em>Example:</em></p>
<pre>
-record(person, {name, phone, address}).