aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler')
-rw-r--r--lib/compiler/Makefile2
-rw-r--r--lib/compiler/doc/src/Makefile24
-rw-r--r--lib/compiler/doc/src/book.xml2
-rw-r--r--lib/compiler/doc/src/compile.xml88
-rw-r--r--lib/compiler/doc/src/fascicules.xml15
-rw-r--r--lib/compiler/doc/src/note.gifbin1539 -> 0 bytes
-rw-r--r--lib/compiler/doc/src/notes.xml485
-rw-r--r--lib/compiler/doc/src/notes_history.xml2
-rw-r--r--lib/compiler/doc/src/part_notes.xml40
-rw-r--r--lib/compiler/doc/src/part_notes_history.xml40
-rw-r--r--lib/compiler/doc/src/ref_man.xml4
-rw-r--r--lib/compiler/doc/src/user_guide.gifbin1581 -> 0 bytes
-rw-r--r--lib/compiler/doc/src/warning.gifbin1498 -> 0 bytes
-rw-r--r--lib/compiler/src/Makefile11
-rw-r--r--lib/compiler/src/beam_a.erl5
-rw-r--r--lib/compiler/src/beam_asm.erl95
-rw-r--r--lib/compiler/src/beam_block.erl602
-rw-r--r--lib/compiler/src/beam_bool.erl765
-rw-r--r--lib/compiler/src/beam_bs.erl281
-rw-r--r--lib/compiler/src/beam_bsm.erl71
-rw-r--r--lib/compiler/src/beam_clean.erl44
-rw-r--r--lib/compiler/src/beam_dead.erl129
-rw-r--r--lib/compiler/src/beam_dict.erl43
-rw-r--r--lib/compiler/src/beam_disasm.erl10
-rw-r--r--lib/compiler/src/beam_disasm.hrl8
-rw-r--r--lib/compiler/src/beam_except.erl19
-rw-r--r--lib/compiler/src/beam_flatten.erl6
-rw-r--r--lib/compiler/src/beam_jump.erl130
-rw-r--r--lib/compiler/src/beam_listing.erl20
-rw-r--r--lib/compiler/src/beam_peep.erl52
-rw-r--r--lib/compiler/src/beam_receive.erl8
-rw-r--r--lib/compiler/src/beam_record.erl106
-rw-r--r--lib/compiler/src/beam_reorder.erl151
-rw-r--r--lib/compiler/src/beam_split.erl14
-rw-r--r--lib/compiler/src/beam_trim.erl11
-rw-r--r--lib/compiler/src/beam_type.erl272
-rw-r--r--lib/compiler/src/beam_utils.erl450
-rw-r--r--lib/compiler/src/beam_validator.erl219
-rw-r--r--lib/compiler/src/beam_z.erl17
-rw-r--r--lib/compiler/src/cerl.erl67
-rw-r--r--lib/compiler/src/cerl_clauses.erl9
-rw-r--r--lib/compiler/src/cerl_inline.erl11
-rw-r--r--lib/compiler/src/cerl_trees.erl248
-rw-r--r--lib/compiler/src/compile.erl656
-rw-r--r--lib/compiler/src/compiler.app.src10
-rw-r--r--lib/compiler/src/compiler.appup.src2
-rw-r--r--lib/compiler/src/core_lib.erl40
-rw-r--r--lib/compiler/src/core_lint.erl4
-rw-r--r--lib/compiler/src/core_parse.hrl2
-rw-r--r--lib/compiler/src/core_parse.yrl78
-rw-r--r--lib/compiler/src/core_pp.erl170
-rw-r--r--lib/compiler/src/core_scan.erl34
-rw-r--r--lib/compiler/src/erl_bifs.erl9
-rwxr-xr-xlib/compiler/src/genop.tab10
-rw-r--r--lib/compiler/src/rec_env.erl195
-rw-r--r--lib/compiler/src/sys_core_bsm.erl355
-rw-r--r--lib/compiler/src/sys_core_dsetel.erl38
-rw-r--r--lib/compiler/src/sys_core_fold.erl888
-rw-r--r--lib/compiler/src/sys_core_inline.erl2
-rw-r--r--lib/compiler/src/sys_pre_attributes.erl50
-rw-r--r--lib/compiler/src/sys_pre_expand.erl671
-rw-r--r--lib/compiler/src/v3_codegen.erl187
-rw-r--r--lib/compiler/src/v3_core.erl442
-rw-r--r--lib/compiler/src/v3_kernel.erl649
-rw-r--r--lib/compiler/src/v3_kernel.hrl5
-rw-r--r--lib/compiler/src/v3_kernel_pp.erl24
-rw-r--r--lib/compiler/src/v3_life.erl68
-rw-r--r--lib/compiler/src/v3_life.hrl10
-rw-r--r--lib/compiler/test/Makefile35
-rw-r--r--lib/compiler/test/andor_SUITE.erl359
-rw-r--r--lib/compiler/test/apply_SUITE.erl104
-rw-r--r--lib/compiler/test/beam_block_SUITE.erl244
-rw-r--r--lib/compiler/test/beam_disasm_SUITE.erl27
-rw-r--r--lib/compiler/test/beam_except_SUITE.erl28
-rw-r--r--lib/compiler/test/beam_jump_SUITE.erl74
-rw-r--r--lib/compiler/test/beam_reorder_SUITE.erl81
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl176
-rw-r--r--lib/compiler/test/beam_utils_SUITE.erl149
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl371
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/xrange.S4
-rw-r--r--lib/compiler/test/bif_SUITE.erl122
-rw-r--r--lib/compiler/test/bs_bincomp_SUITE.erl251
-rw-r--r--lib/compiler/test/bs_bit_binaries_SUITE.erl96
-rw-r--r--lib/compiler/test/bs_construct_SUITE.erl220
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl850
-rw-r--r--lib/compiler/test/bs_utf_SUITE.erl153
-rw-r--r--lib/compiler/test/compilation_SUITE.erl593
-rw-r--r--lib/compiler/test/compilation_SUITE_data/beam_compiler_1.erl32
-rw-r--r--lib/compiler/test/compilation_SUITE_data/beam_compiler_10.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/beam_compiler_11.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/beam_compiler_12.erl30
-rw-r--r--lib/compiler/test/compilation_SUITE_data/beam_compiler_2.erl36
-rw-r--r--lib/compiler/test/compilation_SUITE_data/beam_compiler_3.erl30
-rw-r--r--lib/compiler/test/compilation_SUITE_data/beam_compiler_4.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/beam_compiler_5.erl29
-rw-r--r--lib/compiler/test/compilation_SUITE_data/beam_compiler_6.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/beam_compiler_8.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/beam_compiler_9.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/bin_syntax_1.erl32
-rw-r--r--lib/compiler/test/compilation_SUITE_data/bin_syntax_2.erl42
-rw-r--r--lib/compiler/test/compilation_SUITE_data/bin_syntax_3.erl36
-rw-r--r--lib/compiler/test/compilation_SUITE_data/bin_syntax_4.erl33
-rw-r--r--lib/compiler/test/compilation_SUITE_data/bin_syntax_6.erl40
-rw-r--r--lib/compiler/test/compilation_SUITE_data/catch_in_catch.erl52
-rw-r--r--lib/compiler/test/compilation_SUITE_data/compiler_1.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/compiler_3.erl34
-rw-r--r--lib/compiler/test/compilation_SUITE_data/compiler_5.erl50
-rw-r--r--lib/compiler/test/compilation_SUITE_data/complex_guard.erl32
-rw-r--r--lib/compiler/test/compilation_SUITE_data/const_list_256.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/convopts.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/guards.erl107
-rw-r--r--lib/compiler/test/compilation_SUITE_data/live_var.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/long_string.erl671
-rw-r--r--lib/compiler/test/compilation_SUITE_data/nested_tuples_in_case_expr.erl37
-rw-r--r--lib/compiler/test/compilation_SUITE_data/opt_crash.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/other/vsn_1.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/other/vsn_3.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_2173.erl32
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_2330.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_2380.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_4790.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_5076.erl28
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_5092.erl40
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_5151.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_5235.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_5244.erl48
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_5404.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_5436.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_5481.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_5553.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_5632.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_5714.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_5872.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_6121.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_6121a.erl33
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_6121b.erl34
-rw-r--r--lib/compiler/test/compilation_SUITE_data/otp_7202.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/pattern_expr.erl31
-rw-r--r--lib/compiler/test/compilation_SUITE_data/trycatch_4.erl51
-rw-r--r--lib/compiler/test/compilation_SUITE_data/vsn_1.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/vsn_2.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/vsn_3.erl2
-rw-r--r--lib/compiler/test/compile_SUITE.erl1260
-rw-r--r--lib/compiler/test/compile_SUITE_data/attributes.erl2
-rw-r--r--lib/compiler/test/compile_SUITE_data/bad_record_use.erl29
-rw-r--r--lib/compiler/test/compile_SUITE_data/bad_record_use2.erl30
-rw-r--r--lib/compiler/test/compile_SUITE_data/big.erl2
-rw-r--r--lib/compiler/test/compile_SUITE_data/deterministic_module.erl (renamed from lib/compiler/test/compilation_SUITE_data/otp_2141.erl)16
-rw-r--r--lib/compiler/test/compile_SUITE_data/include/simple.hrl2
-rw-r--r--lib/compiler/test/compile_SUITE_data/missing_testheap1.erl36
-rw-r--r--lib/compiler/test/compile_SUITE_data/missing_testheap2.erl30
-rw-r--r--lib/compiler/test/compile_SUITE_data/record_access.erl2
-rw-r--r--lib/compiler/test/compile_SUITE_data/simple.erl7
-rw-r--r--lib/compiler/test/compile_SUITE_data/small_float.erl5
-rw-r--r--lib/compiler/test/compile_SUITE_data/wrong_module_name.erl2
-rw-r--r--lib/compiler/test/core_SUITE.erl40
-rw-r--r--lib/compiler/test/core_SUITE_data/cover_v3_kernel_1.core147
-rw-r--r--lib/compiler/test/core_SUITE_data/cover_v3_kernel_2.core98
-rw-r--r--lib/compiler/test/core_SUITE_data/cover_v3_kernel_3.core98
-rw-r--r--lib/compiler/test/core_SUITE_data/cover_v3_kernel_4.core82
-rw-r--r--lib/compiler/test/core_SUITE_data/cover_v3_kernel_5.core98
-rw-r--r--lib/compiler/test/core_SUITE_data/non_variable_apply.core80
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl203
-rw-r--r--lib/compiler/test/error_SUITE.erl123
-rw-r--r--lib/compiler/test/error_SUITE_data/head_mismatch_line.erl2
-rw-r--r--lib/compiler/test/float_SUITE.erl112
-rw-r--r--lib/compiler/test/fun_SUITE.erl51
-rw-r--r--lib/compiler/test/guard_SUITE.erl1696
-rw-r--r--lib/compiler/test/inline_SUITE.erl185
-rw-r--r--lib/compiler/test/inline_SUITE_data/attribute.erl2
-rw-r--r--lib/compiler/test/inline_SUITE_data/bsdecode.erl2
-rw-r--r--lib/compiler/test/inline_SUITE_data/bsdes.erl2
-rw-r--r--lib/compiler/test/inline_SUITE_data/decode1.erl2
-rw-r--r--lib/compiler/test/inline_SUITE_data/fname.erl2
-rw-r--r--lib/compiler/test/inline_SUITE_data/itracer.erl2
-rw-r--r--lib/compiler/test/inline_SUITE_data/maps_inline_test.erl2
-rw-r--r--lib/compiler/test/lc_SUITE.erl38
-rw-r--r--lib/compiler/test/lfe-core.patch97
-rw-r--r--lib/compiler/test/lfe-source.patch117
-rw-r--r--lib/compiler/test/lfe.readme31
-rw-r--r--lib/compiler/test/lfe_andor_SUITE.core2014
-rw-r--r--lib/compiler/test/lfe_guard_SUITE.core3438
-rw-r--r--lib/compiler/test/map_SUITE.erl73
-rw-r--r--lib/compiler/test/match_SUITE.erl309
-rw-r--r--lib/compiler/test/misc_SUITE.erl181
-rw-r--r--lib/compiler/test/num_bif_SUITE.erl285
-rw-r--r--lib/compiler/test/overridden_bif_SUITE.erl101
-rw-r--r--lib/compiler/test/receive_SUITE.erl47
-rw-r--r--lib/compiler/test/record_SUITE.erl453
-rw-r--r--lib/compiler/test/record_SUITE_data/record_access_in_guards.erl65
-rw-r--r--lib/compiler/test/regressions_SUITE.erl48
-rw-r--r--lib/compiler/test/test_lib.erl38
-rw-r--r--lib/compiler/test/trycatch_SUITE.erl580
-rw-r--r--lib/compiler/test/warnings_SUITE.erl278
-rw-r--r--lib/compiler/vsn.mk2
195 files changed, 17773 insertions, 9666 deletions
diff --git a/lib/compiler/Makefile b/lib/compiler/Makefile
index bd63f7031a..b8b2f562a2 100644
--- a/lib/compiler/Makefile
+++ b/lib/compiler/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2009. All Rights Reserved.
+# Copyright Ericsson AB 1996-2016. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/compiler/doc/src/Makefile b/lib/compiler/doc/src/Makefile
index b989325686..254445c111 100644
--- a/lib/compiler/doc/src/Makefile
+++ b/lib/compiler/doc/src/Makefile
@@ -1,8 +1,8 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2012. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 1997-2017. 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
@@ -14,7 +14,7 @@
# 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%
#
include $(ERL_TOP)/make/target.mk
@@ -38,13 +38,12 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
XML_APPLICATION_FILES = ref_man.xml
XML_REF3_FILES = compile.xml
-XML_PART_FILES = part_notes.xml part_notes_history.xml
+XML_PART_FILES =
XML_CHAPTER_FILES = notes.xml notes_history.xml
BOOK_FILES = book.xml
-GIF_FILES = \
- warning.gif
+GIF_FILES =
XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
@@ -64,9 +63,9 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
# ----------------------------------------------------
-# FLAGS
+# FLAGS
# ----------------------------------------------------
-XML_FLAGS +=
+XML_FLAGS +=
# ----------------------------------------------------
# Targets
@@ -86,17 +85,17 @@ man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-debug opt:
+debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
+ rm -f errs core *~
# ----------------------------------------------------
# Release Target
-# ----------------------------------------------------
+# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
@@ -110,4 +109,3 @@ release_docs_spec: docs
$(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
-
diff --git a/lib/compiler/doc/src/book.xml b/lib/compiler/doc/src/book.xml
index 8de3fae69a..af6b4cf47a 100644
--- a/lib/compiler/doc/src/book.xml
+++ b/lib/compiler/doc/src/book.xml
@@ -4,7 +4,7 @@
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>1997</year><year>2013</year>
+ <year>1997</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index db701409db..10164890f2 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2014</year>
+ <year>1996</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -40,6 +40,19 @@
<funcs>
<func>
+ <name>env_compiler_options()</name>
+ <fsummary>
+ Compiler options defined via the environment variable
+ <c>ERL_COMPILER_OPTIONS</c>
+ </fsummary>
+ <desc>
+ <p>Return compiler options given via the environment variable
+ <c>ERL_COMPILER_OPTIONS</c>. If the value is a list, it is
+ returned as is. If it is not a list, it is put into a list.
+ </p>
+ </desc>
+ </func>
+ <func>
<name>file(File)</name>
<fsummary>Compiles a file.</fsummary>
<desc>
@@ -119,12 +132,10 @@
<tag><c>debug_info</c></tag>
<item>
<marker id="debug_info"></marker>
- <p>Includes debug information in the form of abstract code
- (see
- <seealso marker="erts:absform">The Abstract Format</seealso>
- in ERTS User's Guide) in the compiled beam module. Tools
- such as <c>Debugger</c>, <c>Xref</c>, and <c>Cover</c> require
- the debug information to be included.</p>
+ <p>Includes debug information in the form of <seealso marker="erts:absform">
+ Erlang Abstract Format</seealso> in the <c>debug_info</c>
+ chunk of the compiled beam module. Tools such as Debugger,
+ Xref, and Cover require the debug information to be included.</p>
<p><em>Warning</em>: Source code can be reconstructed from
the debug information. Use encrypted debug information
@@ -134,6 +145,21 @@
<seealso marker="stdlib:beam_lib#debug_info">beam_lib(3)</seealso>.</p>
</item>
+ <tag><c>{debug_info, {Backend, Data}}</c></tag>
+ <item>
+ <marker id="debug_info"></marker>
+ <p>Includes custom debug information in the form of a
+ <c>Backend</c> module with custom <c>Data</c> in the compiled beam module.
+ The given module must implement a <c>debug_info/4</c> function
+ and is responsible for generating different code representations,
+ as described in the <c>debug_info</c> under
+ <seealso marker="stdlib:beam_lib#debug_info">beam_lib(3)</seealso>.</p>
+
+ <p><em>Warning</em>: Source code can be reconstructed from
+ the debug information. Use encrypted debug information
+ (<c>encrypt_debug_info</c>) to prevent this.</p>
+ </item>
+
<tag><c>{debug_info_key,KeyString}</c></tag>
<item></item>
<tag><c>{debug_info_key,{Mode,KeyString}}</c></tag>
@@ -163,6 +189,14 @@
<seealso marker="stdlib:beam_lib#debug_info">beam_lib(3)</seealso>.</p>
</item>
+ <tag><c>deterministic</c></tag>
+ <item>
+ <p>Omit the <c>options</c> and <c>source</c> tuples in
+ the list returned by <c>Module:module_info(compile)</c>.
+ This option will make it easier to achieve reproducible builds.
+ </p>
+ </item>
+
<tag><c>makedep</c></tag>
<item>
<p>Produces a Makefile rule to track headers dependencies.
@@ -397,7 +431,7 @@ module.beam: module.erl \
without module prefix to local or imported functions before
trying with auto-imported BIFs. If the BIF is to be
called, use the <c>erlang</c> module prefix in the call, not
- <c>{ no_auto_import,[{F,A}, ...]}</c>.</p>
+ <c>{no_auto_import,[{F,A}, ...]}</c>.</p>
</note>
<p>If this option is written in the source code, as a
<c>-compile</c> directive, the syntax <c>F/A</c> can be used instead
@@ -418,6 +452,15 @@ module.beam: module.erl \
</p>
</item>
+ <tag><c>{extra_chunks, [{binary(), binary()}]}</c></tag>
+ <item>
+ <p>Pass extra chunks to be stored in the <c>.beam</c> file.
+ The extra chunks must be a list of tuples with a four byte
+ binary as chunk name followed by a binary with the chunk contents.
+ See <seealso marker="stdlib:beam_lib">beam_lib</seealso> for
+ more information.
+ </p>
+ </item>
</taglist>
<p>If warnings are turned on (option <c>report_warnings</c>
@@ -485,9 +528,11 @@ module.beam: module.erl \
</warning>
</item>
- <tag><c>warn_export_all</c></tag>
+ <tag><c>nowarn_export_all</c></tag>
<item>
- <p>Emits a warning if option <c>export_all</c> is also given.</p>
+ <p>Turns off warnings for uses of the <c>export_all</c>
+ option. Default is to emit a warning if option
+ <c>export_all</c> is also given.</p>
</item>
<tag><c>warn_export_vars</c></tag>
@@ -531,7 +576,7 @@ module.beam: module.erl \
compiler to be deprecated. Notice that the compiler does not know
about attribute <c>-deprecated()</c>, but uses an
assembled list of deprecated functions in Erlang/OTP. To
- do a more general check, the <c>Xref</c> tool can be used.
+ do a more general check, the Xref tool can be used.
See also
<seealso marker="tools:xref#deprecated_function">xref(3)</seealso>
and the function
@@ -555,13 +600,13 @@ module.beam: module.erl \
to be deprecated.</p>
</item>
- <tag><c>warn_obsolete_guard</c></tag>
+ <tag><c>nowarn_obsolete_guard</c></tag>
<item>
- <p>Emits warnings for calls to old type testing BIFs,
+ <p>Turns off warnings for calls to old type testing BIFs,
such as <c>pid/1</c> and <c>list/1</c>. See the
<seealso marker="doc/reference_manual:expressions#guards">Erlang Reference Manual</seealso>
for a complete list of type testing BIFs and their old
- equivalents. Default is to emit no warnings for calls to
+ equivalents. Default is to emit warnings for calls to
old type testing BIFs.</p>
</item>
@@ -584,6 +629,14 @@ module.beam: module.erl \
<p>Turns off warnings for unused record types. Default is to
emit warnings for unused locally defined record types.</p>
</item>
+
+ <tag><c>nowarn_get_stacktrace</c></tag>
+ <item>
+ <p>Turns off warnings for using <c>get_stacktrace/0</c> in a context
+ where it will probably not work in a future release. For example,
+ by default there will be a warning if <c>get_stacktrace/0</c> is
+ used following a <c>catch</c> expression.</p>
+ </item>
</taglist>
<p>Another class of warnings is generated by the compiler
@@ -656,7 +709,7 @@ module.beam: module.erl \
<fsummary>Compiles a list of forms.</fsummary>
<desc>
<p>Is the same as
- <c>forms(File, [verbose,report_errors,report_warnings])</c>.
+ <c>forms(Forms, [verbose,report_errors,report_warnings])</c>.
</p>
</desc>
</func>
@@ -768,6 +821,9 @@ module.beam: module.erl \
if you do not want the environment variable to be consulted,
for example, if you are calling the compiler recursively from
inside a parse transform.</p>
+
+ <p>The list can be retrieved with
+ <seealso marker="#env_compiler_options/0">env_compiler_options/0</seealso>.</p>
</section>
<section>
@@ -830,7 +886,7 @@ pi() -> 3.1416.
<section>
<title>Inlining of List Functions</title>
<p>The compiler can also inline various list manipulation functions
- from the module <c>list</c> in <c>STDLIB</c>.</p>
+ from the module <c>list</c> in STDLIB.</p>
<p>This feature must be explicitly enabled with a compiler option or a
<c>-compile()</c> attribute in the source module.</p>
diff --git a/lib/compiler/doc/src/fascicules.xml b/lib/compiler/doc/src/fascicules.xml
deleted file mode 100644
index fadd37eefb..0000000000
--- a/lib/compiler/doc/src/fascicules.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
-
-<fascicules>
- <fascicule file="ref_man" href="ref_man_frame.html" entry="yes">
- Reference Manual
- </fascicule>
- <fascicule file="part_notes" href="part_notes_frame.html" entry="no">
- Release Notes
- </fascicule>
- <fascicule file="" href="../../../../doc/print.html" entry="no">
- Off-Print
- </fascicule>
-</fascicules>
-
diff --git a/lib/compiler/doc/src/note.gif b/lib/compiler/doc/src/note.gif
deleted file mode 100644
index 6fffe30419..0000000000
--- a/lib/compiler/doc/src/note.gif
+++ /dev/null
Binary files differ
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index de39b019de..2aec75a2aa 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2013</year>
+ <year>2004</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,269 @@
<p>This document describes the changes made to the Compiler
application.</p>
-<section><title>Compiler 6.0.3.1</title>
+<section><title>Compiler 7.1.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The compiler could issue an incorrect internal
+ consistency failure diagnostic for some complicated bit
+ syntax maches.</p>
+ <p>
+ Own Id: OTP-14640 Aux Id: ERL-490 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fail labels on guard BIFs weren't taken into account
+ during an optimization pass, and a bug in the validation
+ pass sometimes prevented this from being noticed when a
+ fault occurred.</p>
+ <p>
+ Own Id: OTP-14522 Aux Id: ERIERL-48 </p>
+ </item>
+ <item>
+ <p>
+ When compiling from Core Erlang, an 'apply' with a nested
+ apply in the function position would be treated as an
+ invalid call. Corrected. (Thanks to Mikael Pettersson for
+ reporting this bug.)</p>
+ <p>
+ Own Id: OTP-14526</p>
+ </item>
+ <item>
+ <p>Fixed checking of binary matching in the
+ <c>beam_validator</c> module to ensure that potential
+ compiler bugs are found at compile-time instead as
+ emulator crash at run-time.</p>
+ <p>
+ Own Id: OTP-14591</p>
+ </item>
+ <item>
+ <p>There could be false warnings for
+ <c>erlang:get_stacktrace/0</c> being used outside of a
+ <c>try</c> block when using multiple <c>catch</c>
+ clauses.</p>
+ <p>
+ Own Id: OTP-14600 Aux Id: ERL-478 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The Erlang code linter no longer checks that the
+ functions mentioned in <c>nowarn_deprecated_function</c>
+ options are declared in the module. </p>
+ <p>
+ Own Id: OTP-14378</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fail labels on guard BIFs weren't taken into account
+ during an optimization pass, and a bug in the validation
+ pass sometimes prevented this from being noticed when a
+ fault occurred.</p>
+ <p>
+ Own Id: OTP-14522 Aux Id: ERIERL-48 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>For many releases, it has been legal to override a BIF
+ with a local function having the same name. However,
+ calling a local function with the same name as guard BIF
+ as filter in a list comprehension was not allowed.</p>
+ <p>
+ Own Id: OTP-13690</p>
+ </item>
+ <item>
+ <p>compile:forms/2 would not return the module name as
+ documented when one of the options '<c>from_core</c>',
+ '<c>from_asm</c>', or '<c>from_beam</c>' was given. Also,
+ the compiler would crash if one of those options was
+ combined with '<c>native</c>'.</p>
+ <p>
+ Own Id: OTP-14408 Aux Id: ERL-417 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Optimized test for tuples with an atom as first element.</p>
+ <p>
+ Own Id: OTP-12148</p>
+ </item>
+ <item>
+ <p>
+ Compilation of modules with huge literal binary strings
+ is now much faster.</p>
+ <p>
+ Own Id: OTP-13794</p>
+ </item>
+ <item>
+ <p>Replaced usage of deprecated symbolic <seealso
+ marker="erts:erlang#type-time_unit"><c>time
+ unit</c></seealso> representations.</p>
+ <p>
+ Own Id: OTP-13831 Aux Id: OTP-13735 </p>
+ </item>
+ <item>
+ <p>The undocumented and unsupported module
+ <c>sys_pre_expand</c> has been removed. As a partial
+ replacement for the functionality, there is a new
+ function <c>erl_internal:add_predefined_functions/1</c>
+ and <c>erl_expand_records</c> will now add a module
+ prefix to calls to BIFs and imported functions.</p>
+ <p>
+ Own Id: OTP-13856</p>
+ </item>
+ <item>
+ <p>The internal compiler passes now start all generated
+ variables with "@" to avoid any conflicts with variables
+ in languages such as Elixir or LFE.</p>
+ <p>
+ Own Id: OTP-13924</p>
+ </item>
+ <item>
+ <p>The function <c>fmod/2</c> has been added to the
+ <c>math</c> module.</p>
+ <p>
+ Own Id: OTP-14000</p>
+ </item>
+ <item>
+ <p>Code generation for complicated guards have been
+ improved.</p>
+ <p>
+ Own Id: OTP-14042</p>
+ </item>
+ <item>
+ <p>
+ The compiler has new warnings for repeated identical map
+ keys.</p>
+ <p>
+ A map expression such as,</p>
+ <p>
+ <c> #{'a' => 1, 'b' => 2, 'a' => 3}.</c></p>
+ <p>
+ will produce a warning for the repeated key 'a'.</p>
+ <p>
+ Own Id: OTP-14058</p>
+ </item>
+ <item>
+ <p>By default, there will now be a warning when
+ <c>export_all</c> is used. The warning can be disabled
+ using <c>nowarn_export_all</c>.</p>
+ <p>
+ Own Id: OTP-14071</p>
+ </item>
+ <item>
+ <p>
+ Optimize maps pattern matching by only examining the
+ common keys in each clause first instead of all keys.
+ This will reduce the number of lookups of each key in
+ maps pattern matching.</p>
+ <p>
+ Own Id: OTP-14072</p>
+ </item>
+ <item>
+ <p>There is a new '<c>deterministic</c>' option to omit
+ '<c>source</c>' and '<c>options</c>' tuples in the BEAM
+ file.</p>
+ <p>
+ Own Id: OTP-14087</p>
+ </item>
+ <item>
+ <p>
+ Analyzing modules with binary construction with huge
+ strings is now much faster. The compiler also compiles
+ such modules slightly faster.</p>
+ <p>
+ Own Id: OTP-14125 Aux Id: ERL-308 </p>
+ </item>
+ <item>
+ <p>Atoms may now contain arbitrary Unicode
+ characters.</p>
+ <p>
+ Own Id: OTP-14178</p>
+ </item>
+ <item>
+ <p><c>compile:file/2</c> now accepts the option
+ <c>extra_chunks</c> to include extra chunks in the BEAM
+ file.</p>
+ <p>
+ Own Id: OTP-14221</p>
+ </item>
+ <item>
+ <p>The format of debug information that is stored in BEAM
+ files (when <c>debug_info</c> is used) has been changed.
+ The purpose of the change is to better support other
+ BEAM-based languages such as Elixir or LFE.</p>
+ <p>All tools included in OTP (dialyzer, debugger, cover,
+ and so on) will handle both the new format and the
+ previous format. Tools that retrieve the debug
+ information using <c>beam_lib:chunk(Beam,
+ [abstract_code])</c> will continue to work with both the
+ new and old format. Tools that call
+ <c>beam_lib:chunk(Beam, ["Abst"])</c> will not work with
+ the new format.</p>
+ <p>For more information, see the description of
+ <c>debug_info</c> in the documentation for
+ <c>beam_lib</c> and the description of the
+ <c>{debug_info,{Backend,Data}}</c> option in the
+ documentation for <c>compile</c>.</p>
+ <p>
+ Own Id: OTP-14369 Aux Id: PR-1367 </p>
+ </item>
+ <item>
+ <p>In a future release, <c>erlang:get_stacktrace/0</c>
+ will probably only work when called from within a
+ '<c>try</c>' expression (otherwise it will return
+ <c>[]</c>.</p>
+ <p>To help prepare for that change, the compiler will now
+ by default warn if '<c>get_stacktrace/0</c>' is used in a
+ way that will not work in the future. Note that the
+ warning will not be issued if '<c>get_stacktrace/0</c>'
+ is used in a function that uses neither '<c>catch</c>'
+ nor '<c>try</c>' (because that could be a legal use if
+ the function is called from within a '<c>try</c>'.</p>
+ <p>
+ Own Id: OTP-14401</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.0.4.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
@@ -49,6 +311,221 @@
</section>
+<section><title>Compiler 7.0.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Minor internal changes. A typo in the documentation was
+ also fixed.</p>
+ <p>
+ Own Id: OTP-14240</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a compiler crash when maps were matched.</p>
+ <p>
+ Own Id: OTP-13931 Aux Id: ERL-266 </p>
+ </item>
+ <item>
+ <p>
+ Fixed a compiler crash having to with the delayed
+ sub-creation optimization. (Thanks to Jose Valim for
+ reporting this bug.)</p>
+ <p>
+ Own Id: OTP-13947 Aux Id: ERL-268 </p>
+ </item>
+ <item>
+ <p>The compiler option <c>inline_list_funcs</c>
+ accidentally turned off some other optimizations.</p>
+ <p>
+ Own Id: OTP-13985</p>
+ </item>
+ <item>
+ <p>The compiler could sometimes generate spurious
+ warnings when inlining was enabled.</p>
+ <p>
+ Own Id: OTP-14040 Aux Id: ERL-301 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ If the compiler fails to write the BEAM file, it will now
+ report the reason of the error for the write operation.</p>
+ <p>
+ Own Id: OTP-13701</p>
+ </item>
+ <item>
+ <p>
+ Fixed an internal compiler error. (Thanks to Svilen
+ Ivanov for reporting this bug.)</p>
+ <p>
+ Own Id: OTP-13780 Aux Id: ERL-202 </p>
+ </item>
+ <item>
+ <p>
+ The compiler could crash when trying to compile a
+ complicated expression with multiple catches all on one
+ line . (Thanks to Thomas Arts for reporting this bug.)</p>
+ <p>
+ Own Id: OTP-13804 Aux Id: ERL-209 </p>
+ </item>
+ <item>
+ <p>
+ Eliminated a few internal compiler failures.</p>
+ <p>
+ Own Id: OTP-13863</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A literal binary matching regression was introduced in
+ 19.0 where a match could fail to resolve to the right
+ clause. This has now been fixed.</p>
+ <p>
+ Own Id: OTP-13738</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p><c>compile:forms/1,2</c> would crash when used in a
+ working directory that had been deleted by another
+ process.</p>
+ <p>
+ Own Id: OTP-13430 Aux Id: ERL-113 </p>
+ </item>
+ <item>
+ <p>Dialyzer no longer crashes when there is an invalid
+ function call such as <c>42(7)</c> in a module being
+ analyzed. The compiler will now warn for invalid function
+ calls such as <c>X = 42, x(7)</c>.</p>
+ <p>
+ Own Id: OTP-13552 Aux Id: ERL-138 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Optimization of tuple matching has been slightly
+ improved.</p>
+ <p>
+ Own Id: OTP-12951</p>
+ </item>
+ <item>
+ <p>Five deprecated and undocumented functions in the
+ module <c>core_lib</c> have been removed. The functions
+ are: <c>get_anno/{1,2}</c>, <c>is_literal/1</c>,
+ <c>is_literal_list/1</c>, and <c>literal_value</c>. Use
+ the appropriate functions in the <c>cerl</c> module
+ instead.</p>
+ <p>
+ Own Id: OTP-12979</p>
+ </item>
+ <item>
+ <p>The pre-processor can now expand the ?FUNCTION_NAME
+ and ?FUNCTION_ARITY macros.</p>
+ <p>
+ Own Id: OTP-13059</p>
+ </item>
+ <item>
+ <p>The function mapfold/4 has been added to the
+ <c>cerl_trees</c> module.</p>
+ <p>
+ Own Id: OTP-13280</p>
+ </item>
+ <item>
+ <p>Bitstring comprehensions have been generalized to
+ allow arbitrary expressions in the construction part.</p>
+ <p>
+ Own Id: OTP-13289</p>
+ </item>
+ <item>
+ <p>The compiler will now produce warnings for binary
+ patterns that will never match (example:
+ <c>&lt;&lt;-1/unsigned&gt;&gt; = Bin</c>). </p>
+ <p>
+ Own Id: OTP-13374 Aux Id: ERL-44 </p>
+ </item>
+ <item>
+ <p>The compiler will no longer put the compilation date
+ and time into BEAM files. That means that two BEAM files
+ compiled on the same computer from the same source code
+ and compilation options will be identical.</p>
+ <p>Note: If you want to find out whether a BEAM file on
+ disk is different from the loaded code, compared the MD5
+ value obtained from <c>Mod:module_info(md5)</c> with the
+ MD5 value obtained from
+ <c>beam_lib:md5(BeamFileForMod)</c></p>.
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13504</p>
+ </item>
+ <item>
+ <p>The function <c>compile:env_compiler_options/0</c> has
+ been added to allow tools to pick up the same default
+ compiler options as the compiler itself.</p>
+ <p>
+ Own Id: OTP-13654</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+
+<section><title>Compiler 6.0.3.1</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fail labels on guard BIFs weren't taken into account
+ during an optimization pass, and a bug in the validation
+ pass sometimes prevented this from being noticed when a
+ fault occurred.</p>
+ <p>
+ Own Id: OTP-14522 Aux Id: ERIERL-48 </p>
+ </item>
+ </list>
+ </section>
+</section>
+
<section><title>Compiler 6.0.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -186,7 +663,7 @@
<item>
<p>
The <c>cerl</c> and <c>cerl_trees</c> modules in the
- <c>compiler</c> application are now documented.</p>
+ Compiler application are now documented.</p>
<p>
Own Id: OTP-11978</p>
</item>
@@ -1888,7 +2365,7 @@
<c>RightExpr</c> or vice versa. The evaluation order is
only important if the expressions contains and/or depends
on operations with side-effects, such as message passing
- or <c>ets</c> operations.</p>
+ or ETS operations.</p>
<p>
Own Id: OTP-7206</p>
</item>
diff --git a/lib/compiler/doc/src/notes_history.xml b/lib/compiler/doc/src/notes_history.xml
index 85216b2c66..16bfb3d34b 100644
--- a/lib/compiler/doc/src/notes_history.xml
+++ b/lib/compiler/doc/src/notes_history.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2006</year><year>2013</year>
+ <year>2006</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/compiler/doc/src/part_notes.xml b/lib/compiler/doc/src/part_notes.xml
deleted file mode 100644
index 5000f50dca..0000000000
--- a/lib/compiler/doc/src/part_notes.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2004</year><year>2013</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- 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.
-
- </legalnotice>
-
- <title>Compiler Release Notes</title>
- <prepared></prepared>
- <docno></docno>
- <date>2004-09-07</date>
- <rev>1.0</rev>
- </header>
- <description>
- <p>The <em>Compiler</em> application compiles Erlang
- code to byte-code. The highly compact byte-code is executed by
- the Erlang emulator.</p>
- <p>For information about older versions, see
- <url href="part_notes_history_frame.html">Release Notes History</url>.</p>
- </description>
- <xi:include href="notes.xml"/>
-</part>
-
diff --git a/lib/compiler/doc/src/part_notes_history.xml b/lib/compiler/doc/src/part_notes_history.xml
deleted file mode 100644
index 046b4893c3..0000000000
--- a/lib/compiler/doc/src/part_notes_history.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part>
- <header>
- <copyright>
- <year>2006</year>
- <year>2013</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- 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.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>Compiler Release Notes History</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <description>
- <p>The <em>Compiler</em> application compiles Erlang
- code to byte-code. The highly compact byte-code is executed by
- the Erlang emulator.</p>
- </description>
- <include file="notes_history"></include>
-</part>
-
diff --git a/lib/compiler/doc/src/ref_man.xml b/lib/compiler/doc/src/ref_man.xml
index d360e7963f..c32c499008 100644
--- a/lib/compiler/doc/src/ref_man.xml
+++ b/lib/compiler/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -30,7 +30,7 @@
<file>application.sgml</file>
</header>
<description>
- <p>The <c>Compiler</c> application compiles Erlang
+ <p>The Compiler application compiles Erlang
code to byte-code. The highly compact byte-code is executed by
the Erlang emulator.</p>
</description>
diff --git a/lib/compiler/doc/src/user_guide.gif b/lib/compiler/doc/src/user_guide.gif
deleted file mode 100644
index e6275a803d..0000000000
--- a/lib/compiler/doc/src/user_guide.gif
+++ /dev/null
Binary files differ
diff --git a/lib/compiler/doc/src/warning.gif b/lib/compiler/doc/src/warning.gif
deleted file mode 100644
index 96af52360e..0000000000
--- a/lib/compiler/doc/src/warning.gif
+++ /dev/null
Binary files differ
diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile
index 299b2892fc..ef6db66ff6 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2013. All Rights Reserved.
+# Copyright Ericsson AB 1996-2017. 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.
@@ -49,7 +49,7 @@ MODULES = \
beam_a \
beam_asm \
beam_block \
- beam_bool \
+ beam_bs \
beam_bsm \
beam_clean \
beam_dead \
@@ -62,6 +62,8 @@ MODULES = \
beam_opcodes \
beam_peep \
beam_receive \
+ beam_reorder \
+ beam_record \
beam_split \
beam_trim \
beam_type \
@@ -81,12 +83,12 @@ MODULES = \
core_scan \
erl_bifs \
rec_env \
+ sys_core_bsm \
sys_core_dsetel \
sys_core_fold \
sys_core_fold_lists \
sys_core_inline \
sys_pre_attributes \
- sys_pre_expand \
v3_codegen \
v3_core \
v3_kernel \
@@ -126,7 +128,7 @@ ERL_COMPILE_FLAGS += +native
endif
ERL_COMPILE_FLAGS += +inline +warn_unused_import \
-Werror \
- -I../../stdlib/include -I$(EGEN) -W
+ -I../../stdlib/include -I$(EGEN) -W +warn_missing_spec
# ----------------------------------------------------
# Targets
@@ -196,7 +198,6 @@ $(EBIN)/sys_core_dsetel.beam: core_parse.hrl
$(EBIN)/sys_core_fold.beam: core_parse.hrl
$(EBIN)/sys_core_fold_lists.beam: core_parse.hrl
$(EBIN)/sys_core_inline.beam: core_parse.hrl
-$(EBIN)/sys_pre_expand.beam: ../../stdlib/include/erl_bits.hrl
$(EBIN)/v3_codegen.beam: v3_life.hrl
$(EBIN)/v3_core.beam: core_parse.hrl
$(EBIN)/v3_kernel.beam: core_parse.hrl v3_kernel.hrl
diff --git a/lib/compiler/src/beam_a.erl b/lib/compiler/src/beam_a.erl
index f0f2ee08c2..cdb32d5d55 100644
--- a/lib/compiler/src/beam_a.erl
+++ b/lib/compiler/src/beam_a.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2012-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.
@@ -25,6 +25,9 @@
-export([module/2]).
+-spec module(beam_asm:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
Fs = [function(F) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
diff --git a/lib/compiler/src/beam_asm.erl b/lib/compiler/src/beam_asm.erl
index a3201b0f4a..f7c838e392 100644
--- a/lib/compiler/src/beam_asm.erl
+++ b/lib/compiler/src/beam_asm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. 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.
@@ -21,22 +21,54 @@
-module(beam_asm).
--export([module/4]).
+-export([module/5]).
-export([encode/2]).
+-export_type([fail/0,label/0,reg/0,src/0,module_code/0,function_name/0]).
+
-import(lists, [map/2,member/2,keymember/3,duplicate/2,splitwith/2]).
-include("beam_opcodes.hrl").
-module(Code, Abst, SourceFile, Opts) ->
- {ok,assemble(Code, Abst, SourceFile, Opts)}.
+%% Common types for describing operands for BEAM instructions.
+-type reg_num() :: 0..1023.
+-type reg() :: {'x',reg_num()} | {'y',reg_num()}.
+-type src() :: reg() |
+ {'literal',term()} |
+ {'atom',atom()} |
+ {'integer',integer()} |
+ 'nil' |
+ {'float',float()}.
+-type label() :: pos_integer().
+-type fail() :: {'f',label() | 0}.
+
+%% asm_instruction() describes only the instructions that
+%% are used in BEAM files (as opposed to internal instructions
+%% used only during optimization).
+
+-type asm_instruction() :: atom() | tuple().
+
+-type function_name() :: atom().
+
+-type asm_function() ::
+ {'function',function_name(),arity(),label(),[asm_instruction()]}.
+
+-type module_code() ::
+ {module(),[_],[_],[asm_function()],pos_integer()}.
+
+-spec module(module_code(), [{binary(), binary()}], [_], [compile:option()], [compile:option()]) ->
+ {'ok',binary()}.
-assemble({Mod,Exp,Attr0,Asm0,NumLabels}, Abst, SourceFile, Opts) ->
+module(Code, ExtraChunks, SourceFile, Opts, CompilerOpts) ->
+ {ok,assemble(Code, ExtraChunks, SourceFile, Opts, CompilerOpts)}.
+
+assemble({Mod,Exp0,Attr0,Asm0,NumLabels}, ExtraChunks, SourceFile, Opts, CompilerOpts) ->
{1,Dict0} = beam_dict:atom(Mod, beam_dict:new()),
{0,Dict1} = beam_dict:fname(atom_to_list(Mod) ++ ".erl", Dict0),
NumFuncs = length(Asm0),
{Asm,Attr} = on_load(Asm0, Attr0),
+ Exp = cerl_sets:from_list(Exp0),
{Code,Dict2} = assemble_1(Asm, Exp, Dict1, []),
- build_file(Code, Attr, Dict2, NumLabels, NumFuncs, Abst, SourceFile, Opts).
+ build_file(Code, Attr, Dict2, NumLabels, NumFuncs, ExtraChunks, SourceFile, Opts, CompilerOpts).
on_load(Fs0, Attr0) ->
case proplists:get_value(on_load, Attr0) of
@@ -61,7 +93,7 @@ insert_on_load_instruction(Is0, Entry) ->
Bef ++ [El,on_load|Is].
assemble_1([{function,Name,Arity,Entry,Asm}|T], Exp, Dict0, Acc) ->
- Dict1 = case member({Name,Arity}, Exp) of
+ Dict1 = case cerl_sets:is_element({Name,Arity}, Exp) of
true ->
beam_dict:export(Name, Arity, Entry, Dict0);
false ->
@@ -79,7 +111,7 @@ assemble_function([H|T], Acc, Dict0) ->
assemble_function([], Code, Dict) ->
{Code, Dict}.
-build_file(Code, Attr, Dict, NumLabels, NumFuncs, Abst, SourceFile, Opts) ->
+build_file(Code, Attr, Dict, NumLabels, NumFuncs, ExtraChunks, SourceFile, Opts, CompilerOpts) ->
%% Create the code chunk.
CodeChunk = chunk(<<"Code">>,
@@ -91,9 +123,9 @@ build_file(Code, Attr, Dict, NumLabels, NumFuncs, Abst, SourceFile, Opts) ->
Code),
%% Create the atom table chunk.
-
- {NumAtoms, AtomTab} = beam_dict:atom_table(Dict),
- AtomChunk = chunk(<<"Atom">>, <<NumAtoms:32>>, AtomTab),
+ AtomEncoding = atom_encoding(CompilerOpts),
+ {NumAtoms, AtomTab} = beam_dict:atom_table(Dict, AtomEncoding),
+ AtomChunk = chunk(atom_chunk_name(AtomEncoding), <<NumAtoms:32>>, AtomTab),
%% Create the import table chunk.
@@ -150,25 +182,35 @@ build_file(Code, Attr, Dict, NumLabels, NumFuncs, Abst, SourceFile, Opts) ->
Essentials1 = [iolist_to_binary(C) || C <- Essentials0],
MD5 = module_md5(Essentials1),
Essentials = finalize_fun_table(Essentials1, MD5),
- {Attributes,Compile} = build_attributes(Opts, SourceFile, Attr, MD5),
+ {Attributes,Compile} = build_attributes(Opts, CompilerOpts, SourceFile,
+ Attr, MD5),
AttrChunk = chunk(<<"Attr">>, Attributes),
CompileChunk = chunk(<<"CInf">>, Compile),
- %% Create the abstract code chunk.
+ %% Compile all extra chunks.
- AbstChunk = chunk(<<"Abst">>, Abst),
+ CheckedChunks = [chunk(Key, Value) || {Key, Value} <- ExtraChunks],
%% Create IFF chunk.
Chunks = case member(slim, Opts) of
true ->
- [Essentials,AttrChunk,AbstChunk];
+ [Essentials,AttrChunk];
false ->
[Essentials,LocChunk,AttrChunk,
- CompileChunk,AbstChunk,LineChunk]
+ CompileChunk,CheckedChunks,LineChunk]
end,
build_form(<<"BEAM">>, Chunks).
+atom_encoding(Opts) ->
+ case proplists:get_bool(no_utf8_atoms, Opts) of
+ false -> utf8;
+ true -> latin1
+ end.
+
+atom_chunk_name(utf8) -> <<"AtU8">>;
+atom_chunk_name(latin1) -> <<"Atom">>.
+
%% finalize_fun_table(Essentials, MD5) -> FinalizedEssentials
%% Update the 'old_uniq' field in the entry for each fun in the
%% 'FunT' chunk. We'll use part of the MD5 for the module as a
@@ -223,14 +265,21 @@ flatten_exports(Exps) ->
flatten_imports(Imps) ->
list_to_binary(map(fun({M,F,A}) -> <<M:32,F:32,A:32>> end, Imps)).
-build_attributes(Opts, SourceFile, Attr, MD5) ->
- Misc = case member(slim, Opts) of
- false ->
- {{Y,Mo,D},{H,Mi,S}} = erlang:universaltime(),
- [{time,{Y,Mo,D,H,Mi,S}},{source,SourceFile}];
+build_attributes(Opts, CompilerOpts, SourceFile, Attr, MD5) ->
+ Misc0 = case SourceFile of
+ [] -> [];
+ [_|_] -> [{source,SourceFile}]
+ end,
+ Misc = case member(slim, CompilerOpts) of
+ false -> Misc0;
true -> []
end,
- Compile = [{options,Opts},{version,?COMPILER_VSN}|Misc],
+ Compile = case member(deterministic, CompilerOpts) of
+ false ->
+ [{options,Opts},{version,?COMPILER_VSN}|Misc];
+ true ->
+ [{version,?COMPILER_VSN}]
+ end,
{term_to_binary(set_vsn_attribute(Attr, MD5)),term_to_binary(Compile)}.
build_line_table(Dict) ->
@@ -431,6 +480,8 @@ encode_alloc_list_1([{floats,Floats}|T], Dict, Acc0) ->
encode_alloc_list_1([], Dict, Acc) ->
{iolist_to_binary(Acc),Dict}.
+-spec encode(non_neg_integer(), pos_integer()) -> iodata().
+
encode(Tag, N) when N < 0 ->
encode1(Tag, negative_to_bytes(N));
encode(Tag, N) when N < 16 ->
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index 0321b1c07b..6543e05e20 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,14 +23,16 @@
-module(beam_block).
-export([module/2]).
--import(lists, [mapfoldl/3,reverse/1,reverse/2,foldl/3,member/2]).
--define(MAXREG, 1024).
+-import(lists, [reverse/1,reverse/2,foldl/3,member/2]).
-module({Mod,Exp,Attr,Fs0,Lc0}, _Opt) ->
- {Fs,Lc} = mapfoldl(fun function/2, Lc0, Fs0),
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
+module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
+ Fs = [function(F) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
-function({function,Name,Arity,CLabel,Is0}, Lc0) ->
+function({function,Name,Arity,CLabel,Is0}) ->
try
%% Collect basic blocks and optimize them.
Is1 = blockify(Is0),
@@ -40,11 +42,8 @@ function({function,Name,Arity,CLabel,Is0}, Lc0) ->
Is5 = opt_blocks(Is4),
Is6 = beam_utils:delete_live_annos(Is5),
- %% Optimize bit syntax.
- {Is,Lc} = bsm_opt(Is6, Lc0),
-
%% Done.
- {{function,Name,Arity,CLabel,Is},Lc}
+ {function,Name,Arity,CLabel,Is6}
catch
Class:Error ->
Stack = erlang:get_stacktrace(),
@@ -62,56 +61,15 @@ blockify(Is) ->
blockify([{loop_rec,{f,Fail},{x,0}},{loop_rec_end,_Lbl},{label,Fail}|Is], Acc) ->
%% Useless instruction sequence.
blockify(Is, Acc);
-blockify([{test,is_atom,{f,Fail},[Reg]}=I|
- [{select,select_val,Reg,{f,Fail},
- [{atom,false},{f,_}=BrFalse,
- {atom,true}=AtomTrue,{f,_}=BrTrue]}|Is]=Is0],
- [{block,Bl}|_]=Acc) ->
- case is_last_bool(Bl, Reg) of
- false ->
- blockify(Is0, [I|Acc]);
- true ->
- %% The last instruction is a boolean operator/guard BIF that can't fail.
- %% We can convert the three-way branch to a two-way branch (eliminating
- %% the reference to the failure label).
- blockify(Is, [{jump,BrTrue},
- {test,is_eq_exact,BrFalse,[Reg,AtomTrue]}|Acc])
- end;
-blockify([{test,is_atom,{f,Fail},[Reg]}=I|
- [{select,select_val,Reg,{f,Fail},
- [{atom,true}=AtomTrue,{f,_}=BrTrue,
- {atom,false},{f,_}=BrFalse]}|Is]=Is0],
- [{block,Bl}|_]=Acc) ->
- case is_last_bool(Bl, Reg) of
- false ->
- blockify(Is0, [I|Acc]);
- true ->
- blockify(Is, [{jump,BrTrue},
- {test,is_eq_exact,BrFalse,[Reg,AtomTrue]}|Acc])
- end;
blockify([I|Is0]=IsAll, Acc) ->
- case is_bs_put(I) of
- true ->
- {BsPuts0,Is} = collect_bs_puts(IsAll),
- BsPuts = opt_bs_puts(BsPuts0),
- blockify(Is, reverse(BsPuts, Acc));
- false ->
- case collect(I) of
- error -> blockify(Is0, [I|Acc]);
- Instr when is_tuple(Instr) ->
- {Block,Is} = collect_block(IsAll),
- blockify(Is, [{block,Block}|Acc])
- end
+ case collect(I) of
+ error -> blockify(Is0, [I|Acc]);
+ Instr when is_tuple(Instr) ->
+ {Block,Is} = collect_block(IsAll),
+ blockify(Is, [{block,Block}|Acc])
end;
blockify([], Acc) -> reverse(Acc).
-is_last_bool([{set,[Reg],As,{bif,N,_}}], Reg) ->
- Ar = length(As),
- erl_internal:new_type_test(N, Ar) orelse erl_internal:comp_op(N, Ar)
- orelse erl_internal:bool_op(N, Ar);
-is_last_bool([_|Is], Reg) -> is_last_bool(Is, Reg);
-is_last_bool([], _) -> false.
-
collect_block(Is) ->
collect_block(Is, []).
@@ -126,7 +84,9 @@ collect_block([I|Is]=Is0, Acc) ->
case collect(I) of
error -> {reverse(Acc),Is0};
Instr -> collect_block(Is, [Instr|Acc])
- end.
+ end;
+collect_block([], Acc) ->
+ {reverse(Acc),[]}.
collect({allocate,N,R}) -> {set,[],[],{alloc,R,{nozero,N,0,[]}}};
collect({allocate_zero,N,R}) -> {set,[],[],{alloc,R,{zero,N,0,[]}}};
@@ -146,10 +106,10 @@ collect({get_list,S,D1,D2}) -> {set,[D1,D2],[S],get_list};
collect(remove_message) -> {set,[],[],remove_message};
collect({put_map,F,Op,S,D,R,{list,Puts}}) ->
{set,[D],[S|Puts],{alloc,R,{put_map,Op,F}}};
-collect({get_map_elements,F,S,{list,Gets}}) ->
- {Ss,Ds} = beam_utils:split_even(Gets),
- {set,Ds,[S|Ss],{get_map_elements,F}};
-collect({'catch',R,L}) -> {set,[R],[],{'catch',L}};
+collect({'catch'=Op,R,L}) ->
+ {set,[R],[],{try_catch,Op,L}};
+collect({'try'=Op,R,L}) ->
+ {set,[R],[],{try_catch,Op,L}};
collect(fclearerror) -> {set,[],[],fclearerror};
collect({fcheckerror,{f,0}}) -> {set,[],[],fcheckerror};
collect({fmove,S,D}) -> {set,[D],[S],fmove};
@@ -183,7 +143,9 @@ opt_blocks([I|Is]) ->
opt_blocks([]) -> [].
opt_block(Is0) ->
- Is = find_fixpoint(fun opt/1, Is0),
+ Is = find_fixpoint(fun(Is) ->
+ opt_tuple_element(opt(Is))
+ end, Is0),
opt_alloc(Is).
find_fixpoint(OptFun, Is0) ->
@@ -193,14 +155,43 @@ find_fixpoint(OptFun, Is0) ->
end.
%% move_allocates(Is0) -> Is
-%% Move allocate instructions upwards in the instruction stream, in the
-%% hope of getting more possibilities for optimizing away moves later.
+%% Move allocate instructions upwards in the instruction stream
+%% (within the same block), in the hope of getting more possibilities
+%% for optimizing away moves later.
+%%
+%% For example, we can transform the following instructions:
+%%
+%% get_tuple_element x(1) Element => x(2)
+%% allocate_zero StackSize 3 %% x(0), x(1), x(2) are live
+%%
+%% to the following instructions:
+%%
+%% allocate_zero StackSize 2 %% x(0) and x(1) are live
+%% get_tuple_element x(1) Element => x(2)
+%%
+%% NOTE: Since the beam_reorder pass has been run, it is no longer
+%% safe to assume that if x(N) is initialized, then all lower-numbered
+%% x registers are also initialized.
+%%
+%% For example, in general it is not safe to transform the following
+%% instructions:
%%
-%% NOTE: Moving allocation instructions is only safe because it is done
-%% immediately after code generation so that we KNOW that if {x,X} is
-%% initialized, all x registers with lower numbers are also initialized.
-%% That assumption may not be true after other optimizations, such as
-%% the beam_utils:live_opt/1 optimization.
+%% get_tuple_element x(0) Element => x(1)
+%% allocate_zero StackSize 3 %x(0), x(1), x(2) are live
+%%
+%% to the following instructions:
+%%
+%% allocate_zero StackSize 3
+%% get_tuple_element x(0) Element => x(1)
+%%
+%% The transformation is safe if and only if x(1) has been
+%% initialized previously. Unfortunately, beam_reorder may have moved
+%% a get_tuple_element instruction so that x(1) is not always
+%% initialized when this code is reached. To find whether or not x(1)
+%% is initialized, we would need to analyze all code preceding these
+%% two instructions (across branches). Since we currently don't have
+%% any practical mechanism for doing that, we will have to
+%% conservatively assume that the transformation is unsafe.
move_allocates([{block,Bl0}|Is]) ->
Bl = move_allocates_1(reverse(Bl0), []),
@@ -209,38 +200,26 @@ move_allocates([I|Is]) ->
[I|move_allocates(Is)];
move_allocates([]) -> [].
-move_allocates_1([{set,[],[],{alloc,_,_}=Alloc}|Is0], Acc0) ->
- {Is,Acc} = move_allocates_2(Alloc, Is0, Acc0),
- move_allocates_1(Is, Acc);
+move_allocates_1([I|Is], [{set,[],[],{alloc,Live0,Info}}|Acc]=Acc0) ->
+ case {alloc_may_pass(I),alloc_live_regs(I, Live0)} of
+ {false,_} ->
+ move_allocates_1(Is, [I|Acc0]);
+ {true,not_possible} ->
+ move_allocates_1(Is, [I|Acc0]);
+ {true,Live} when is_integer(Live) ->
+ A = {set,[],[],{alloc,Live,Info}},
+ move_allocates_1(Is, [A,I|Acc])
+ end;
move_allocates_1([I|Is], Acc) ->
move_allocates_1(Is, [I|Acc]);
-move_allocates_1([], Is) -> Is.
-
-move_allocates_2({alloc,Live,Info}, [{set,[],[],{alloc,Live0,Info0}}|Is], Acc) ->
- Live = Live0, % Assertion.
- Alloc = {alloc,Live,combine_alloc(Info0, Info)},
- move_allocates_2(Alloc, Is, Acc);
-move_allocates_2({alloc,Live,Info}=Alloc0, [I|Is]=Is0, Acc) ->
- case alloc_may_pass(I) of
- false ->
- {Is0,[{set,[],[],Alloc0}|Acc]};
- true ->
- Alloc = {alloc,alloc_live_regs(I, Live),Info},
- move_allocates_2(Alloc, Is, [I|Acc])
- end;
-move_allocates_2(Alloc, [], Acc) ->
- {[],[{set,[],[],Alloc}|Acc]}.
+move_allocates_1([], Acc) -> Acc.
alloc_may_pass({set,_,_,{alloc,_,_}}) -> false;
alloc_may_pass({set,_,_,{set_tuple_element,_}}) -> false;
-alloc_may_pass({set,_,_,{get_map_elements,_}}) -> false;
alloc_may_pass({set,_,_,put_list}) -> false;
alloc_may_pass({set,_,_,put}) -> false;
alloc_may_pass({set,_,_,_}) -> true.
-combine_alloc({_,Ns,Nh1,Init}, {_,nostack,Nh2,[]}) ->
- {zero,Ns,beam_utils:combine_heap_needs(Nh1, Nh2),Init}.
-
%% opt([Instruction]) -> [Instruction]
%% Optimize the instruction stream inside a basic block.
@@ -251,8 +230,6 @@ opt([{set,_,_,{line,_}}=Line1,
{set,[D2],[{integer,Idx2},Reg],{bif,element,{f,0}}}=I2|Is])
when Idx1 < Idx2, D1 =/= D2, D1 =/= Reg, D2 =/= Reg ->
opt([Line2,I2,Line1,I1|Is]);
-opt([{set,[_|_],_Ss,{get_map_elements,_F}}=I|Is]) ->
- [I|opt(Is)];
opt([{set,Ds0,Ss,Op}|Is0]) ->
{Ds,Is} = opt_moves(Ds0, Is0),
[{set,Ds,Ss,Op}|opt(Is)];
@@ -279,78 +256,167 @@ opt_moves([X0,Y0], Is0) ->
not_possible -> {[X,Y0],Is2};
{X,_} -> {[X,Y0],Is2};
{Y,Is} -> {[X,Y],Is}
- end;
-opt_moves(Ds, Is) ->
- %% multiple destinations -> pass through
- {Ds,Is}.
-
+ end.
%% opt_move(Dest, [Instruction]) -> {UpdatedDest,[Instruction]} | not_possible
%% If there is a {move,Dest,FinalDest} instruction
%% in the instruction stream, remove the move instruction
%% and let FinalDest be the destination.
-%%
-%% For this optimization to be safe, we must be sure that
-%% Dest will not be referenced in any other by other instructions
-%% in the rest of the instruction stream. Not even the indirect
-%% reference by an instruction that may allocate (such as
-%% test_heap/2 or a GC Bif) is allowed.
opt_move(Dest, Is) ->
- opt_move_1(Dest, Is, ?MAXREG, []).
-
-opt_move_1(R, [{set,_,_,{alloc,Live,_}}|_]=Is, SafeRegs, Acc) when Live < SafeRegs ->
- %% Downgrade number of safe regs and rescan the instruction, as it most probably
- %% is a gc_bif instruction.
- opt_move_1(R, Is, Live, Acc);
-opt_move_1(R, [{set,[{x,X}=D],[R],move}|Is], SafeRegs, Acc) ->
- case X < SafeRegs andalso beam_utils:is_killed_block(R, Is) of
- true -> opt_move_2(D, Acc, Is);
- false -> not_possible
+ opt_move_1(Dest, Is, []).
+
+opt_move_1(R, [{set,[D],[R],move}|Is0], Acc) ->
+ %% Provided that the source register is killed by instructions
+ %% that follow, the optimization is safe.
+ case eliminate_use_of_from_reg(Is0, R, D, []) of
+ {yes,Is} -> opt_move_rev(D, Acc, Is);
+ no -> not_possible
end;
-opt_move_1(R, [{set,[D],[R],move}|Is], _SafeRegs, Acc) ->
- case beam_utils:is_killed_block(R, Is) of
- true -> opt_move_2(D, Acc, Is);
- false -> not_possible
+opt_move_1(_R, [{set,_,_,{alloc,_,_}}|_], _) ->
+ %% The optimization is either not possible or not safe.
+ %%
+ %% If R is an X register killed by allocation, the optimization is
+ %% not safe. On the other hand, if the X register is killed, there
+ %% will not follow a 'move' instruction with this X register as
+ %% the source.
+ %%
+ %% If R is a Y register, the optimization is still not safe
+ %% because the new target register is an X register that cannot
+ %% safely pass the alloc instruction.
+ not_possible;
+opt_move_1(R, [{set,_,_,_}=I|Is], Acc) ->
+ %% If the source register is either killed or used by this
+ %% instruction, the optimimization is not possible.
+ case is_killed_or_used(R, I) of
+ true -> not_possible;
+ false -> opt_move_1(R, Is, [I|Acc])
end;
-opt_move_1(R, [I|Is], SafeRegs, Acc) ->
- case is_transparent(R, I) of
- false -> not_possible;
- true -> opt_move_1(R, Is, SafeRegs, [I|Acc])
- end.
+opt_move_1(_, _, _) ->
+ not_possible.
+
+%% opt_tuple_element([Instruction]) -> [Instruction]
+%% If possible, move get_tuple_element instructions forward
+%% in the instruction stream to a move instruction, eliminating
+%% the move instruction. Example:
+%%
+%% get_tuple_element Tuple Pos Dst1
+%% ...
+%% move Dst1 Dst2
+%%
+%% This code may be possible to rewrite to:
+%%
+%% %%(Moved get_tuple_element instruction)
+%% ...
+%% get_tuple_element Tuple Pos Dst2
+%%
+
+opt_tuple_element([{set,[D],[S],{get_tuple_element,_}}=I|Is0]) ->
+ case opt_tuple_element_1(Is0, I, {S,D}, []) of
+ no ->
+ [I|opt_tuple_element(Is0)];
+ {yes,Is} ->
+ opt_tuple_element(Is)
+ end;
+opt_tuple_element([I|Is]) ->
+ [I|opt_tuple_element(Is)];
+opt_tuple_element([]) -> [].
+
+opt_tuple_element_1([{set,_,_,{alloc,_,_}}|_], _, _, _) ->
+ no;
+opt_tuple_element_1([{set,_,_,{try_catch,_,_}}|_], _, _, _) ->
+ no;
+opt_tuple_element_1([{set,[D],[S],move}|Is0], I0, {_,S}, Acc) ->
+ case eliminate_use_of_from_reg(Is0, S, D, []) of
+ no ->
+ no;
+ {yes,Is} ->
+ {set,[S],Ss,Op} = I0,
+ I = {set,[D],Ss,Op},
+ {yes,reverse(Acc, [I|Is])}
+ end;
+opt_tuple_element_1([{set,Ds,Ss,_}=I|Is], MovedI, {S,D}=Regs, Acc) ->
+ case member(S, Ds) orelse member(D, Ss) of
+ true ->
+ no;
+ false ->
+ opt_tuple_element_1(Is, MovedI, Regs, [I|Acc])
+ end;
+opt_tuple_element_1(_, _, _, _) -> no.
-%% Reverse the instructions, while checking that there are no instructions that
-%% would interfere with using the new destination register chosen.
+%% Reverse the instructions, while checking that there are no
+%% instructions that would interfere with using the new destination
+%% register (D).
-opt_move_2(D, [I|Is], Acc) ->
- case is_transparent(D, I) of
- false -> not_possible;
- true -> opt_move_2(D, Is, [I|Acc])
+opt_move_rev(D, [I|Is], Acc) ->
+ case is_killed_or_used(D, I) of
+ true -> not_possible;
+ false -> opt_move_rev(D, Is, [I|Acc])
end;
-opt_move_2(D, [], Acc) -> {D,Acc}.
-
-%% is_transparent(Register, Instruction) -> true | false
-%% Returns true if Instruction does not in any way references Register
-%% (even indirectly by an allocation instruction).
-%% Returns false if Instruction does reference Register, or we are
-%% not sure.
-
-is_transparent({x,X}, {set,_,_,{alloc,Live,_}}) when X < Live ->
- false;
-is_transparent(R, {set,Ds,Ss,_Op}) ->
- case member(R, Ds) of
- true -> false;
- false -> not member(R, Ss)
+opt_move_rev(D, [], Acc) -> {D,Acc}.
+
+%% is_killed_or_used(Register, {set,_,_,_}) -> bool()
+%% Test whether the register is used by the instruction.
+
+is_killed_or_used(R, {set,Ss,Ds,_}) ->
+ member(R, Ds) orelse member(R, Ss).
+
+%% eliminate_use_of_from_reg([Instruction], FromRegister, ToRegister, Acc) ->
+%% {yes,Is} | no
+%% Eliminate any use of FromRegister in the instruction sequence
+%% by replacing uses of FromRegister with ToRegister. If FromRegister
+%% is referenced by an allocation instruction, return 'no' to indicate
+%% that FromRegister is still used and that the optimization is not
+%% possible.
+
+eliminate_use_of_from_reg([{set,_,_,{alloc,Live,_}}|_]=Is0, {x,X}, _, Acc) ->
+ if
+ X < Live ->
+ no;
+ true ->
+ {yes,reverse(Acc, Is0)}
+ end;
+eliminate_use_of_from_reg([{set,Ds,Ss0,Op}=I0|Is], From, To, Acc) ->
+ I = case member(From, Ss0) of
+ true ->
+ Ss = [case S of
+ From -> To;
+ _ -> S
+ end || S <- Ss0],
+ {set,Ds,Ss,Op};
+ false ->
+ I0
+ end,
+ case member(From, Ds) of
+ true ->
+ {yes,reverse(Acc, [I|Is])};
+ false ->
+ eliminate_use_of_from_reg(Is, From, To, [I|Acc])
end;
-is_transparent(_, _) -> false.
+eliminate_use_of_from_reg([I]=Is, From, _To, Acc) ->
+ case beam_utils:is_killed_block(From, [I]) of
+ true ->
+ {yes,reverse(Acc, Is)};
+ false ->
+ no
+ end.
%% opt_alloc(Instructions) -> Instructions'
%% Optimises all allocate instructions.
+opt_alloc([{set,[],[],{alloc,Live0,Info0}},
+ {set,[],[],{alloc,Live,Info}}|Is]) ->
+ Live = Live0, %Assertion.
+ Alloc = combine_alloc(Info0, Info),
+ I = {set,[],[],{alloc,Live,Alloc}},
+ opt_alloc([I|Is]);
opt_alloc([{set,[],[],{alloc,R,{_,Ns,Nh,[]}}}|Is]) ->
- [{set,[],[],opt_alloc(Is, Ns, Nh, R)}|opt(Is)];
+ [{set,[],[],opt_alloc(Is, Ns, Nh, R)}|Is];
opt_alloc([I|Is]) -> [I|opt_alloc(Is)];
opt_alloc([]) -> [].
+
+combine_alloc({_,Ns,Nh1,Init}, {_,nostack,Nh2,[]}) ->
+ {zero,Ns,beam_utils:combine_heap_needs(Nh1, Nh2),Init}.
%% opt_alloc(Instructions, FrameSize, HeapNeed, LivingRegs) -> [Instr]
%% Generates the optimal sequence of instructions for
@@ -399,13 +465,14 @@ count_ones(Bits, Acc) ->
alloc_live_regs({set,Ds,Ss,_}, Regs0) ->
Rset = x_live(Ss, x_dead(Ds, (1 bsl Regs0)-1)),
- live_regs(Rset).
-
-live_regs(Regs) ->
- live_regs_1(0, Regs).
+ live_regs(0, Rset).
-live_regs_1(N, 0) -> N;
-live_regs_1(N, Regs) -> live_regs_1(N+1, Regs bsr 1).
+live_regs(N, 0) ->
+ N;
+live_regs(N, Regs) when Regs band 1 =:= 1 ->
+ live_regs(N+1, Regs bsr 1);
+live_regs(_, _) ->
+ not_possible.
x_dead([{x,N}|Rs], Regs) -> x_dead(Rs, Regs band (bnot (1 bsl N)));
x_dead([_|Rs], Regs) -> x_dead(Rs, Regs);
@@ -414,234 +481,3 @@ x_dead([], Regs) -> Regs.
x_live([{x,N}|Rs], Regs) -> x_live(Rs, Regs bor (1 bsl N));
x_live([_|Rs], Regs) -> x_live(Rs, Regs);
x_live([], Regs) -> Regs.
-
-%%%
-%%% Evaluation of constant bit fields.
-%%%
-
-is_bs_put({bs_put,_,{bs_put_integer,_,_},_}) -> true;
-is_bs_put({bs_put,_,{bs_put_float,_,_},_}) -> true;
-is_bs_put(_) -> false.
-
-collect_bs_puts(Is) ->
- collect_bs_puts_1(Is, []).
-
-collect_bs_puts_1([I|Is]=Is0, Acc) ->
- case is_bs_put(I) of
- false -> {reverse(Acc),Is0};
- true -> collect_bs_puts_1(Is, [I|Acc])
- end.
-
-opt_bs_puts(Is) ->
- opt_bs_1(Is, []).
-
-opt_bs_1([{bs_put,Fail,
- {bs_put_float,1,Flags0},[{integer,Sz},Src]}=I0|Is], Acc) ->
- try eval_put_float(Src, Sz, Flags0) of
- <<Int:Sz>> ->
- Flags = force_big(Flags0),
- I = {bs_put,Fail,{bs_put_integer,1,Flags},
- [{integer,Sz},{integer,Int}]},
- opt_bs_1([I|Is], Acc)
- catch
- error:_ ->
- opt_bs_1(Is, [I0|Acc])
- end;
-opt_bs_1([{bs_put,_,{bs_put_integer,1,_},[{integer,8},{integer,_}]}|_]=IsAll,
- Acc0) ->
- {Is,Acc} = bs_collect_string(IsAll, Acc0),
- opt_bs_1(Is, Acc);
-opt_bs_1([{bs_put,Fail,{bs_put_integer,1,F},[{integer,Sz},{integer,N}]}=I|Is0],
- Acc) when Sz > 8 ->
- case field_endian(F) of
- big ->
- %% We can do this optimization for any field size without risk
- %% for code explosion.
- case bs_split_int(N, Sz, Fail, Is0) of
- no_split -> opt_bs_1(Is0, [I|Acc]);
- Is -> opt_bs_1(Is, Acc)
- end;
- little when Sz < 128 ->
- %% We only try to optimize relatively small fields, to avoid
- %% an explosion in code size.
- <<Int:Sz>> = <<N:Sz/little>>,
- Flags = force_big(F),
- Is = [{bs_put,Fail,{bs_put_integer,1,Flags},
- [{integer,Sz},{integer,Int}]}|Is0],
- opt_bs_1(Is, Acc);
- _ -> %native or too wide little field
- opt_bs_1(Is0, [I|Acc])
- end;
-opt_bs_1([{bs_put,Fail,{Op,U,F},[{integer,Sz},Src]}|Is], Acc) when U > 1 ->
- opt_bs_1([{bs_put,Fail,{Op,1,F},[{integer,U*Sz},Src]}|Is], Acc);
-opt_bs_1([I|Is], Acc) ->
- opt_bs_1(Is, [I|Acc]);
-opt_bs_1([], Acc) -> reverse(Acc).
-
-eval_put_float(Src, Sz, Flags) when Sz =< 256 -> %Only evaluate if Sz is reasonable.
- Val = value(Src),
- case field_endian(Flags) of
- little -> <<Val:Sz/little-float-unit:1>>;
- big -> <<Val:Sz/big-float-unit:1>>
- %% native intentionally not handled here - we can't optimize it.
- end.
-
-value({integer,I}) -> I;
-value({float,F}) -> F.
-
-bs_collect_string(Is, [{bs_put,_,{bs_put_string,Len,{string,Str}},[]}|Acc]) ->
- bs_coll_str_1(Is, Len, reverse(Str), Acc);
-bs_collect_string(Is, Acc) ->
- bs_coll_str_1(Is, 0, [], Acc).
-
-bs_coll_str_1([{bs_put,_,{bs_put_integer,U,_},[{integer,Sz},{integer,V}]}|Is],
- Len, StrAcc, IsAcc) when U*Sz =:= 8 ->
- Byte = V band 16#FF,
- bs_coll_str_1(Is, Len+1, [Byte|StrAcc], IsAcc);
-bs_coll_str_1(Is, Len, StrAcc, IsAcc) ->
- {Is,[{bs_put,{f,0},{bs_put_string,Len,{string,reverse(StrAcc)}},[]}|IsAcc]}.
-
-field_endian({field_flags,F}) -> field_endian_1(F).
-
-field_endian_1([big=E|_]) -> E;
-field_endian_1([little=E|_]) -> E;
-field_endian_1([native=E|_]) -> E;
-field_endian_1([_|Fs]) -> field_endian_1(Fs).
-
-force_big({field_flags,F}) ->
- {field_flags,force_big_1(F)}.
-
-force_big_1([big|_]=Fs) -> Fs;
-force_big_1([little|Fs]) -> [big|Fs];
-force_big_1([F|Fs]) -> [F|force_big_1(Fs)].
-
-bs_split_int(0, Sz, _, _) when Sz > 64 ->
- %% We don't want to split in this case because the
- %% string will consist of only zeroes.
- no_split;
-bs_split_int(-1, Sz, _, _) when Sz > 64 ->
- %% We don't want to split in this case because the
- %% string will consist of only 255 bytes.
- no_split;
-bs_split_int(N, Sz, Fail, Acc) ->
- FirstByteSz = case Sz rem 8 of
- 0 -> 8;
- Rem -> Rem
- end,
- bs_split_int_1(N, FirstByteSz, Sz, Fail, Acc).
-
-bs_split_int_1(-1, _, Sz, Fail, Acc) when Sz > 64 ->
- I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
- [{integer,Sz},{integer,-1}]},
- [I|Acc];
-bs_split_int_1(0, _, Sz, Fail, Acc) when Sz > 64 ->
- I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
- [{integer,Sz},{integer,0}]},
- [I|Acc];
-bs_split_int_1(N, ByteSz, Sz, Fail, Acc) when Sz > 0 ->
- Mask = (1 bsl ByteSz) - 1,
- I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
- [{integer,ByteSz},{integer,N band Mask}]},
- bs_split_int_1(N bsr ByteSz, 8, Sz-ByteSz, Fail, [I|Acc]);
-bs_split_int_1(_, _, _, _, Acc) -> Acc.
-
-
-%%%
-%%% Optimization of new bit syntax matching: get rid
-%%% of redundant bs_restore2/2 instructions across select_val
-%%% instructions, as well as a few other simple peep-hole optimizations.
-%%%
-
-bsm_opt(Is0, Lc0) ->
- {Is1,D0,Lc} = bsm_scan(Is0, [], Lc0, []),
- Is2 = case D0 of
- [] ->
- Is1;
- _ ->
- D = gb_trees:from_orddict(orddict:from_list(D0)),
- bsm_reroute(Is1, D, none, [])
- end,
- Is = beam_clean:bs_clean_saves(Is2),
- {bsm_opt_2(Is, []),Lc}.
-
-bsm_scan([{label,L}=Lbl,{bs_restore2,_,Save}=R|Is], D0, Lc, Acc0) ->
- D = [{{L,Save},Lc}|D0],
- Acc = [{label,Lc},R,Lbl|Acc0],
- bsm_scan(Is, D, Lc+1, Acc);
-bsm_scan([I|Is], D, Lc, Acc) ->
- bsm_scan(Is, D, Lc, [I|Acc]);
-bsm_scan([], D, Lc, Acc) ->
- {reverse(Acc),D,Lc}.
-
-bsm_reroute([{bs_save2,Reg,Save}=I|Is], D, _, Acc) ->
- bsm_reroute(Is, D, {Reg,Save}, [I|Acc]);
-bsm_reroute([{bs_restore2,Reg,Save}=I|Is], D, _, Acc) ->
- bsm_reroute(Is, D, {Reg,Save}, [I|Acc]);
-bsm_reroute([{label,_}=I|Is], D, S, Acc) ->
- bsm_reroute(Is, D, S, [I|Acc]);
-bsm_reroute([{select,select_val,Reg,F0,Lbls0}|Is], D, {_,Save}=S, Acc0) ->
- [F|Lbls] = bsm_subst_labels([F0|Lbls0], Save, D),
- Acc = [{select,select_val,Reg,F,Lbls}|Acc0],
- bsm_reroute(Is, D, S, Acc);
-bsm_reroute([{test,TestOp,F0,TestArgs}=I|Is], D, {_,Save}=S, Acc0) ->
- F = bsm_subst_label(F0, Save, D),
- Acc = [{test,TestOp,F,TestArgs}|Acc0],
- case bsm_not_bs_test(I) of
- true ->
- %% The test instruction will not update the bit offset for the
- %% binary being matched. Therefore the save position can be kept.
- bsm_reroute(Is, D, S, Acc);
- false ->
- %% The test instruction might update the bit offset. Kill our
- %% remembered Save position.
- bsm_reroute(Is, D, none, Acc)
- end;
-bsm_reroute([{test,TestOp,F0,Live,TestArgs,Dst}|Is], D, {_,Save}, Acc0) ->
- F = bsm_subst_label(F0, Save, D),
- Acc = [{test,TestOp,F,Live,TestArgs,Dst}|Acc0],
- %% The test instruction will update the bit offset. Kill our
- %% remembered Save position.
- bsm_reroute(Is, D, none, Acc);
-bsm_reroute([{block,[{set,[],[],{alloc,_,_}}]}=Bl,
- {bs_context_to_binary,_}=I|Is], D, S, Acc) ->
- %% To help further bit syntax optimizations.
- bsm_reroute([I,Bl|Is], D, S, Acc);
-bsm_reroute([I|Is], D, _, Acc) ->
- bsm_reroute(Is, D, none, [I|Acc]);
-bsm_reroute([], _, _, Acc) -> reverse(Acc).
-
-bsm_opt_2([{test,bs_test_tail2,F,[Ctx,Bits]}|Is],
- [{test,bs_skip_bits2,F,[Ctx,{integer,I},Unit,_Flags]}|Acc]) ->
- bsm_opt_2(Is, [{test,bs_test_tail2,F,[Ctx,Bits+I*Unit]}|Acc]);
-bsm_opt_2([{test,bs_skip_bits2,F,[Ctx,{integer,I1},Unit1,_]}|Is],
- [{test,bs_skip_bits2,F,[Ctx,{integer,I2},Unit2,Flags]}|Acc]) ->
- bsm_opt_2(Is, [{test,bs_skip_bits2,F,
- [Ctx,{integer,I1*Unit1+I2*Unit2},1,Flags]}|Acc]);
-bsm_opt_2([I|Is], Acc) ->
- bsm_opt_2(Is, [I|Acc]);
-bsm_opt_2([], Acc) -> reverse(Acc).
-
-%% bsm_not_bs_test({test,Name,_,Operands}) -> true|false.
-%% Test whether is the test is a "safe", i.e. does not move the
-%% bit offset for a binary.
-%%
-%% 'true' means that the test is safe, 'false' that we don't know or
-%% that the test moves the offset (e.g. bs_get_integer2).
-
-bsm_not_bs_test({test,bs_test_tail2,_,[_,_]}) -> true;
-bsm_not_bs_test(Test) -> beam_utils:is_pure_test(Test).
-
-bsm_subst_labels(Fs, Save, D) ->
- bsm_subst_labels_1(Fs, Save, D, []).
-
-bsm_subst_labels_1([F|Fs], Save, D, Acc) ->
- bsm_subst_labels_1(Fs, Save, D, [bsm_subst_label(F, Save, D)|Acc]);
-bsm_subst_labels_1([], _, _, Acc) ->
- reverse(Acc).
-
-bsm_subst_label({f,Lbl0}=F, Save, D) ->
- case gb_trees:lookup({Lbl0,Save}, D) of
- {value,Lbl} -> {f,Lbl};
- none -> F
- end;
-bsm_subst_label(Other, _, _) -> Other.
diff --git a/lib/compiler/src/beam_bool.erl b/lib/compiler/src/beam_bool.erl
deleted file mode 100644
index d14be83496..0000000000
--- a/lib/compiler/src/beam_bool.erl
+++ /dev/null
@@ -1,765 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2013. 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%
-%%
-%% Purpose: Optimizes booleans in guards.
-
--module(beam_bool).
-
--export([module/2]).
-
--import(lists, [reverse/1,reverse/2,foldl/3,mapfoldl/3,map/2]).
-
--define(MAXREG, 1024).
-
--record(st,
- {next, %Next label number.
- ll %Live regs at labels.
- }).
-
-module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
- %%io:format("~p:\n", [Mod]),
- {Fs,_} = mapfoldl(fun(Fn, Lbl) -> function(Fn, Lbl) end, 100000000, Fs0),
- {ok,{Mod,Exp,Attr,Fs,Lc}}.
-
-function({function,Name,Arity,CLabel,Is0}, Lbl0) ->
- try
- {Is,#st{next=Lbl}} = bool_opt(Is0, Lbl0),
- {{function,Name,Arity,CLabel,Is},Lbl}
- catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-%%
-%% Optimize boolean expressions that use guard bifs. Rewrite to
-%% use test instructions if possible.
-%%
-
-bool_opt(Asm, Lbl) ->
- LiveInfo = beam_utils:index_labels(Asm),
- bopt(Asm, [], #st{next=Lbl,ll=LiveInfo}).
-
-bopt([{block,Bl0}=Block|
- [{jump,{f,Succ}},
- {label,Fail},
- {block,[{set,[Dst],[{atom,false}],move}]},
- {label,Succ}|Is]=Is0], Acc0, St) ->
- case split_block(Bl0, Dst, Fail, Acc0, true) of
- failed ->
- bopt(Is0, [Block|Acc0], St);
- {Bl,PreBlock} ->
- Acc1 = case PreBlock of
- [] -> Acc0;
- _ -> [{block,PreBlock}|Acc0]
- end,
- Acc = [{protected,[Dst],Bl,{Fail,Succ}}|Acc1],
- bopt(Is, Acc, St)
- end;
-bopt([{test,is_eq_exact,{f,Fail},[Reg,{atom,true}]}=I|Is], [{block,_}|_]=Acc0, St0) ->
- case bopt_block(Reg, Fail, Is, Acc0, St0) of
- failed -> bopt(Is, [I|Acc0], St0);
- {Acc,St} -> bopt(Is, Acc, St)
- end;
-bopt([I|Is], Acc, St) ->
- bopt(Is, [I|Acc], St);
-bopt([], Acc, St) ->
- {bopt_reverse(Acc, []),St}.
-
-bopt_reverse([{protected,[Dst],Block,{Fail,Succ}}|Is], Acc0) ->
- Acc = [{block,Block},{jump,{f,Succ}},
- {label,Fail},
- {block,[{set,[Dst],[{atom,false}],move}]},
- {label,Succ}|Acc0],
- bopt_reverse(Is, Acc);
-bopt_reverse([I|Is], Acc) ->
- bopt_reverse(Is, [I|Acc]);
-bopt_reverse([], Acc) -> Acc.
-
-%% bopt_block(Reg, Fail, OldIs, Accumulator, St) -> failed | {NewAcc,St}
-%% Attempt to optimized a block of guard BIFs followed by a test
-%% instruction.
-bopt_block(Reg, Fail, OldIs, [{block,Bl0}|Acc0], St0) ->
- case split_block(Bl0, Reg, Fail, Acc0, false) of
- failed ->
- %% Reason for failure: The block either contained no
- %% guard BIFs with the failure label Fail, or the final
- %% instruction in the block did not assign the Reg register.
-
- %%io:format("split ~p: ~P\n", [Reg,Bl0,20]),
- failed;
- {Bl1,BlPre} ->
- %% The block has been splitted. Bl1 is a non-empty list
- %% of guard BIF instructions having the failure label Fail.
- %% BlPre is a (possibly empty list) of instructions preceeding
- %% Bl1.
- Acc1 = make_block(BlPre, Acc0),
- {Bl,Acc} = extend_block(Bl1, Fail, Acc1),
- try
- {NewCode,St} = bopt_tree_cg(Bl, Fail, St0),
- ensure_opt_safe(Bl, NewCode, OldIs, Fail, Acc, St),
- {NewCode++Acc,St}
- catch
- %% Not possible to rewrite because a boolean value is
- %% passed to another guard bif, e.g. 'abs(A > B)'
- %% (in this case, obviously nonsense code). Rare in
- %% practice.
- throw:mixed ->
- failed;
-
- %% There was a reference to a boolean expression
- %% from inside a protected block (try/catch), to
- %% a boolean expression outside.
- throw:protected_barrier ->
- failed;
-
- %% The 'xor' operator was used. We currently don't
- %% find it worthwile to translate 'xor' operators
- %% (the code would be clumsy).
- throw:'xor' ->
- failed;
-
- %% The block does not contain a boolean expression,
- %% but only a call to a guard BIF.
- %% For instance: ... when element(1, T) ->
- throw:not_boolean_expr ->
- failed;
-
- %% The optimization is not safe. (A register
- %% used by the instructions following the
- %% optimized code is either not assigned a
- %% value at all or assigned a different value.)
- throw:all_registers_not_killed ->
- failed;
- throw:registers_used ->
- failed;
-
- %% A protected block refered to the value
- %% returned by another protected block,
- %% probably because the Core Erlang code
- %% used nested try/catches in the guard.
- %% (v3_core never produces nested try/catches
- %% in guards, so it must have been another
- %% Core Erlang translator.)
- throw:protected_violation ->
- failed;
-
- %% Failed to work out the live registers for a GC
- %% BIF. For example, if the number of live registers
- %% needed to be 4 because {x,3} was a source register,
- %% but {x,2} was not known to be initialized, this
- %% exception would be thrown.
- throw:gc_bif_alloc_failure ->
- failed
-
- end
- end.
-
-%% ensure_opt_safe(OriginalCode, OptCode, FollowingCode, Fail,
-%% ReversedPrecedingCode, State) -> ok
-%% Comparing the original code to the optimized code, determine
-%% whether the optimized code is guaranteed to work in the same
-%% way as the original code.
-%%
-%% Throw an exception if the optimization is not safe.
-%%
-ensure_opt_safe(Bl, NewCode, OldIs, Fail, PrecedingCode, St) ->
- %% Here are the conditions that must be true for the
- %% optimization to be safe.
- %%
- %% 1. If a register is INITIALIZED by PrecedingCode,
- %% then if that register assigned a value in the original
- %% code, but not in the optimized code, it must be UNUSED or KILLED
- %% in the code that follows.
- %%
- %% 2. If a register is not known to be INITIALIZED by PreccedingCode,
- %% then if that register assigned a value in the original
- %% code, but not in the optimized code, it must be KILLED
- %% by the code that follows.
- %%
- %% 3. Any register that is assigned a value in the optimized
- %% code must be UNUSED or KILLED in the following code,
- %% unless we can be sure that it is always assigned the same
- %% value.
-
- InitInPreceding = initialized_regs(PrecedingCode),
-
- PrevDst = dst_regs(Bl),
- NewDst = dst_regs(NewCode),
- NotSet = ordsets:subtract(PrevDst, NewDst),
- MustBeKilled = ordsets:subtract(NotSet, InitInPreceding),
-
- case all_killed(MustBeKilled, OldIs, Fail, St) of
- false -> throw(all_registers_not_killed);
- true -> ok
- end,
- MustBeUnused = ordsets:subtract(ordsets:union(NotSet, NewDst),
- MustBeKilled),
- case none_used(MustBeUnused, OldIs, Fail, St) of
- false -> throw(registers_used);
- true -> ok
- end,
- ok.
-
-update_fail_label([{set,Ds,As,{bif,N,{f,_}}}|Is], Fail, Acc) ->
- update_fail_label(Is, Fail, [{set,Ds,As,{bif,N,{f,Fail}}}|Acc]);
-update_fail_label([{set,Ds,As,{alloc,Regs,{gc_bif,N,{f,_}}}}|Is], Fail, Acc) ->
- update_fail_label(Is, Fail,
- [{set,Ds,As,{alloc,Regs,{gc_bif,N,{f,Fail}}}}|Acc]);
-update_fail_label([], _, Acc) -> reverse(Acc).
-
-make_block(Bl) ->
- make_block(Bl, []).
-
-make_block([], Acc) -> Acc;
-make_block(Bl, Acc) -> [{block,Bl}|Acc].
-
-extend_block(BlAcc, Fail, [{protected,_,_,_}=Prot|OldAcc]) ->
- extend_block([Prot|BlAcc], Fail, OldAcc);
-extend_block(BlAcc0, Fail, [{block,Is0}|OldAcc]) ->
- case extend_block_1(reverse(Is0), Fail, BlAcc0) of
- {BlAcc,[]} -> extend_block(BlAcc, Fail, OldAcc);
- {BlAcc,Is} -> {BlAcc,[{block,Is}|OldAcc]}
- end;
-extend_block(BlAcc, _, OldAcc) -> {BlAcc,OldAcc}.
-
-extend_block_1([{set,[_],_,{bif,_,{f,Fail}}}=I|Is], Fail, Acc) ->
- extend_block_1(Is, Fail, [I|Acc]);
-extend_block_1([{set,[_],As,{bif,Bif,_}}=I|Is]=Is0, Fail, Acc) ->
- case safe_bool_op(Bif, length(As)) of
- false -> {Acc,reverse(Is0)};
- true -> extend_block_1(Is, Fail, [I|Acc])
- end;
-extend_block_1([_|_]=Is, _, Acc) -> {Acc,reverse(Is)};
-extend_block_1([], _, Acc) -> {Acc,[]}.
-
-%% split_block([Instruction], Destination, FailLabel, [PreInstruction],
-%% ProhibitFailLabelInPreBlock) -> failed | {Block,PreBlock}
-%% Split a sequence of instructions into two blocks - one containing
-%% all guard bif instructions and a pre-block all instructions before
-%% the guard BIFs.
-
-split_block(Is0, Dst, Fail, PreIs, ProhibitFailLabel) ->
- case ProhibitFailLabel andalso beam_jump:is_label_used_in(Fail, PreIs) of
- true ->
- %% The failure label was used in one of the instructions (most
- %% probably bit syntax construction) preceeding the block,
- %% the caller might eliminate the label.
- failed;
- false ->
- case reverse(Is0) of
- [{set,[Dst],_,_}|_]=Is ->
- split_block_1(Is, Fail, ProhibitFailLabel);
- _ -> failed
- end
- end.
-
-split_block_1(Is, Fail, ProhibitFailLabel) ->
- case split_block_2(Is, Fail, []) of
- {[],_} -> failed;
- {_,PreBlock}=Res ->
- case ProhibitFailLabel andalso
- split_block_label_used(PreBlock, Fail) of
- true ->
- %% The failure label was used in the pre-block;
- %% not allowed, because the label may be removed.
- failed;
- false ->
- Res
- end
- end.
-
-split_block_2([{set,[_],_,{bif,_,{f,Fail}}}=I|Is], Fail, Acc) ->
- split_block_2(Is, Fail, [I|Acc]);
-split_block_2([{set,[_],_,{alloc,_,{gc_bif,_,{f,Fail}}}}=I|Is], Fail, Acc) ->
- split_block_2(Is, Fail, [I|Acc]);
-split_block_2(Is0, _, Acc) ->
- Is = reverse(Is0),
- {Acc,Is}.
-
-split_block_label_used([{set,[_],_,{bif,_,{f,Fail}}}|_], Fail) ->
- true;
-split_block_label_used([{set,[_],_,{alloc,_,{gc_bif,_,{f,Fail}}}}|_], Fail) ->
- true;
-split_block_label_used([{set,[_],_,{alloc,_,{put_map,_,{f,Fail}}}}|_], Fail) ->
- true;
-split_block_label_used([_|Is], Fail) ->
- split_block_label_used(Is, Fail);
-split_block_label_used([], _) -> false.
-
-dst_regs(Is) ->
- dst_regs(Is, []).
-
-dst_regs([{block,Bl}|Is], Acc) ->
- dst_regs(Bl, dst_regs(Is, Acc));
-dst_regs([{set,[D],_,{bif,_,{f,_}}}|Is], Acc) ->
- dst_regs(Is, [D|Acc]);
-dst_regs([{set,[D],_,{alloc,_,{gc_bif,_,{f,_}}}}|Is], Acc) ->
- dst_regs(Is, [D|Acc]);
-dst_regs([_|Is], Acc) ->
- dst_regs(Is, Acc);
-dst_regs([], Acc) -> ordsets:from_list(Acc).
-
-all_killed([R|Rs], OldIs, Fail, St) ->
- case is_killed(R, OldIs, Fail, St) of
- false -> false;
- true -> all_killed(Rs, OldIs, Fail, St)
- end;
-all_killed([], _, _, _) -> true.
-
-none_used([R|Rs], OldIs, Fail, St) ->
- case is_not_used(R, OldIs, Fail, St) of
- false -> false;
- true -> none_used(Rs, OldIs, Fail, St)
- end;
-none_used([], _, _, _) -> true.
-
-bopt_tree_cg(Block0, Fail, St) ->
- Free = free_variables(Block0),
- Block = ssa_block(Block0),
-%% io:format("~p\n", [Block0]),
-%% io:format("~p\n", [Block]),
-%% io:format("~p\n", [gb_trees:to_list(Free)]),
- case bopt_tree(Block, Free, []) of
- {Pre0,[{_,Tree}]} ->
- Pre1 = update_fail_label(Pre0, Fail, []),
- Regs0 = init_regs(gb_trees:keys(Free)),
-%% io:format("~p\n", [dst_regs(Block0)]),
-%% io:format("~p\n", [Pre1]),
-%% io:format("~p\n", [Tree]),
-%% io:nl(),
- {Pre,Regs} = rename_regs(Pre1, Regs0),
-%% io:format("~p\n", [Regs0]),
-%% io:format("~p\n", [Pre]),
- bopt_cg(Tree, Fail, Regs, make_block(Pre), St);
- _Res ->
- throw(not_boolean_expr)
- end.
-
-bopt_tree([{set,[Dst],As0,{bif,'not',_}}|Is], Forest0, Pre) ->
- {[Arg],Forest1} = bopt_bool_args(As0, Forest0),
- Forest = gb_trees:enter(Dst, {'not',Arg}, Forest1),
- bopt_tree(Is, Forest, Pre);
-bopt_tree([{set,[Dst],As0,{bif,'and',_}}|Is], Forest0, Pre) ->
- {As,Forest1} = bopt_bool_args(As0, Forest0),
- Node = make_and_node(As),
- Forest = gb_trees:enter(Dst, Node, Forest1),
- bopt_tree(Is, Forest, Pre);
-bopt_tree([{set,[Dst],As0,{bif,'or',_}}|Is], Forest0, Pre) ->
- {As,Forest1} = bopt_bool_args(As0, Forest0),
- Node = make_or_node(As),
- Forest = gb_trees:enter(Dst, Node, Forest1),
- bopt_tree(Is, Forest, Pre);
-bopt_tree([{set,_,_,{bif,'xor',_}}|_], _, _) ->
- throw('xor');
-bopt_tree([{protected,[Dst],Code,_}|Is], Forest0, Pre) ->
- ProtForest0 = gb_trees:from_orddict([P || {_,any}=P <- gb_trees:to_list(Forest0)]),
- case bopt_tree(Code, ProtForest0, []) of
- {ProtPre,[{_,ProtTree}]} ->
- Prot = {prot,ProtPre,ProtTree},
- Forest = gb_trees:enter(Dst, Prot, Forest0),
- bopt_tree(Is, Forest, Pre);
- _Res ->
- throw(not_boolean_expr)
- end;
-bopt_tree([{set,[Dst],As,{bif,N,_}}=Bif|Is], Forest0, Pre) ->
- Ar = length(As),
- case safe_bool_op(N, Ar) of
- false ->
- bopt_good_args(As, Forest0),
- Forest = gb_trees:enter(Dst, any, Forest0),
- bopt_tree(Is, Forest, [Bif|Pre]);
- true ->
- bopt_good_args(As, Forest0),
- Test = bif_to_test(Dst, N, As),
- Forest = gb_trees:enter(Dst, Test, Forest0),
- bopt_tree(Is, Forest, Pre)
- end;
-bopt_tree([{set,[Dst],As,{alloc,_,{gc_bif,_,_}}}=Bif|Is], Forest0, Pre) ->
- bopt_good_args(As, Forest0),
- Forest = gb_trees:enter(Dst, any, Forest0),
- bopt_tree(Is, Forest, [Bif|Pre]);
-bopt_tree([], Forest, Pre) ->
- {reverse(Pre),[R || {_,V}=R <- gb_trees:to_list(Forest), V =/= any]}.
-
-safe_bool_op(N, Ar) ->
- erl_internal:new_type_test(N, Ar) orelse erl_internal:comp_op(N, Ar).
-
-bopt_bool_args([V0,V0], Forest0) ->
- {V,Forest} = bopt_bool_arg(V0, Forest0),
- {[V,V],Forest};
-bopt_bool_args(As, Forest) ->
- mapfoldl(fun bopt_bool_arg/2, Forest, As).
-
-bopt_bool_arg({T,_}=R, Forest) when T =:= x; T =:= y; T =:= tmp ->
- Val = case gb_trees:lookup(R, Forest) of
- {value,any} -> {test,is_eq_exact,fail,[R,{atom,true}]};
- {value,Val0} -> Val0;
- none -> throw(mixed)
- end,
- {Val,gb_trees:delete(R, Forest)};
-bopt_bool_arg(Term, Forest) ->
- {Term,Forest}.
-
-bopt_good_args([A|As], Regs) ->
- bopt_good_arg(A, Regs),
- bopt_good_args(As, Regs);
-bopt_good_args([], _) -> ok.
-
-bopt_good_arg({Tag,_}=X, Regs) when Tag =:= x; Tag =:= tmp ->
- case gb_trees:lookup(X, Regs) of
- {value,any} -> ok;
- {value,_} -> throw(mixed);
- none -> throw(protected_barrier)
- end;
-bopt_good_arg(_, _) -> ok.
-
-bif_to_test(_, N, As) ->
- beam_utils:bif_to_test(N, As, fail).
-
-make_and_node(Is) ->
- AndList0 = make_and_list(Is),
- case simplify_and_list(AndList0) of
- [] -> {atom,true};
- [Op] -> Op;
- AndList -> {'and',AndList}
- end.
-
-make_and_list([{'and',As}|Is]) ->
- make_and_list(As++Is);
-make_and_list([I|Is]) ->
- [I|make_and_list(Is)];
-make_and_list([]) -> [].
-
-simplify_and_list([{atom,true}|T]) ->
- simplify_and_list(T);
-simplify_and_list([{atom,false}=False|_]) ->
- [False];
-simplify_and_list([H|T]) ->
- [H|simplify_and_list(T)];
-simplify_and_list([]) -> [].
-
-make_or_node(Is) ->
- OrList0 = make_or_list(Is),
- case simplify_or_list(OrList0) of
- [] -> {atom,false};
- [Op] -> Op;
- OrList -> {'or',OrList}
- end.
-
-make_or_list([{'or',As}|Is]) ->
- make_or_list(As++Is);
-make_or_list([I|Is]) ->
- [I|make_or_list(Is)];
-make_or_list([]) -> [].
-
-simplify_or_list([{atom,false}|T]) ->
- simplify_or_list(T);
-simplify_or_list([{atom,true}=True|_]) ->
- [True];
-simplify_or_list([H|T]) ->
- [H|simplify_or_list(T)];
-simplify_or_list([]) -> [].
-
-%% Code generation for a boolean tree.
-
-bopt_cg({'not',Arg}, Fail, Rs, Acc, St) ->
- I = bopt_cg_not(Arg),
- bopt_cg(I, Fail, Rs, Acc, St);
-bopt_cg({'and',As}, Fail, Rs, Acc, St) ->
- bopt_cg_and(As, Fail, Rs, Acc, St);
-bopt_cg({'or',As}, Fail, Rs, Acc, St0) ->
- {Succ,St} = new_label(St0),
- bopt_cg_or(As, Succ, Fail, Rs, Acc, St);
-bopt_cg({test,N,fail,As0}, Fail, Rs, Acc, St) ->
- As = rename_sources(As0, Rs),
- Test = {test,N,{f,Fail},As},
- {[Test|Acc],St};
-bopt_cg({inverted_test,N,fail,As0}, Fail, Rs, Acc, St0) ->
- As = rename_sources(As0, Rs),
- {Lbl,St} = new_label(St0),
- {[{label,Lbl},{jump,{f,Fail}},{test,N,{f,Lbl},As}|Acc],St};
-bopt_cg({prot,Pre0,Tree}, Fail, Rs0, Acc, St0) ->
- Pre1 = update_fail_label(Pre0, Fail, []),
- {Pre,Rs} = rename_regs(Pre1, Rs0),
- bopt_cg(Tree, Fail, Rs, make_block(Pre, Acc), St0);
-bopt_cg({atom,true}, _Fail, _Rs, Acc, St) ->
- {Acc,St};
-bopt_cg({atom,false}, Fail, _Rs, Acc, St) ->
- {[{jump,{f,Fail}}|Acc],St};
-bopt_cg(_, _, _, _, _) ->
- throw(not_boolean_expr).
-
-bopt_cg_not({'and',As0}) ->
- As = [bopt_cg_not(A) || A <- As0],
- {'or',As};
-bopt_cg_not({'or',As0}) ->
- As = [bopt_cg_not(A) || A <- As0],
- {'and',As};
-bopt_cg_not({'not',Arg}) ->
- bopt_cg_not_not(Arg);
-bopt_cg_not({test,Test,Fail,As}) ->
- {inverted_test,Test,Fail,As};
-bopt_cg_not({atom,Bool}) when is_boolean(Bool) ->
- {atom,not Bool};
-bopt_cg_not(_) ->
- throw(not_boolean_expr).
-
-bopt_cg_not_not({'and',As}) ->
- {'and',[bopt_cg_not_not(A) || A <- As]};
-bopt_cg_not_not({'or',As}) ->
- {'or',[bopt_cg_not_not(A) || A <- As]};
-bopt_cg_not_not({'not',Arg}) ->
- bopt_cg_not(Arg);
-bopt_cg_not_not(Leaf) -> Leaf.
-
-bopt_cg_and([I|Is], Fail, Rs, Acc0, St0) ->
- {Acc,St} = bopt_cg(I, Fail, Rs, Acc0, St0),
- bopt_cg_and(Is, Fail, Rs, Acc, St);
-bopt_cg_and([], _, _, Acc, St) -> {Acc,St}.
-
-bopt_cg_or([I], Succ, Fail, Rs, Acc0, St0) ->
- {Acc,St} = bopt_cg(I, Fail, Rs, Acc0, St0),
- {[{label,Succ}|Acc],St};
-bopt_cg_or([I|Is], Succ, Fail, Rs, Acc0, St0) ->
- {Lbl,St1} = new_label(St0),
- {Acc,St} = bopt_cg(I, Lbl, Rs, Acc0, St1),
- bopt_cg_or(Is, Succ, Fail, Rs, [{label,Lbl},{jump,{f,Succ}}|Acc], St).
-
-new_label(#st{next=LabelNum}=St) when is_integer(LabelNum) ->
- {LabelNum,St#st{next=LabelNum+1}}.
-
-free_variables(Is) ->
- E = gb_sets:empty(),
- free_vars_1(Is, E, E, E).
-
-free_vars_1([{set,Ds,As,{bif,_,_}}|Is], F0, N0, A) ->
- F = gb_sets:union(F0, gb_sets:difference(var_list(As), N0)),
- N = gb_sets:union(N0, var_list(Ds)),
- free_vars_1(Is, F, N, A);
-free_vars_1([{set,Ds,As,{alloc,Regs,{gc_bif,_,_}}}|Is], F0, N0, A0) ->
- A = gb_sets:union(A0, gb_sets:from_list(free_vars_regs(Regs))),
- F = gb_sets:union(F0, gb_sets:difference(var_list(As), N0)),
- N = gb_sets:union(N0, var_list(Ds)),
- free_vars_1(Is, F, N, A);
-free_vars_1([{protected,_,Pa,_}|Is], F, N, A) ->
- free_vars_1(Pa++Is, F, N, A);
-free_vars_1([], F0, N, A) ->
- F = case gb_sets:is_empty(A) of
- true ->
- %% No GC BIFs.
- {x,X} = gb_sets:smallest(N),
- P = ordsets:from_list(free_vars_regs(X)),
- ordsets:union(gb_sets:to_list(F0), P);
- false ->
- %% At least one GC BIF.
- gb_sets:to_list(gb_sets:union(F0, gb_sets:difference(A, N)))
- end,
- gb_trees:from_orddict([{K,any} || K <- F]).
-
-var_list(Is) ->
- var_list_1(Is, gb_sets:empty()).
-
-var_list_1([{Tag,_}=X|Is], D) when Tag =:= x; Tag =:= y ->
- var_list_1(Is, gb_sets:add(X, D));
-var_list_1([_|Is], D) ->
- var_list_1(Is, D);
-var_list_1([], D) -> D.
-
-free_vars_regs(0) -> [];
-free_vars_regs(X) -> [{x,X-1}|free_vars_regs(X-1)].
-
-rename_regs(Is, Regs) ->
- rename_regs(Is, Regs, []).
-
-rename_regs([{set,[Dst0],Ss0,{alloc,_,Info}}|Is], Regs0, Acc) ->
- Live = live_regs(Regs0),
- Ss = rename_sources(Ss0, Regs0),
- Regs = put_reg(Dst0, Regs0),
- Dst = fetch_reg(Dst0, Regs),
- rename_regs(Is, Regs, [{set,[Dst],Ss,{alloc,Live,Info}}|Acc]);
-rename_regs([{set,[Dst0],Ss0,Info}|Is], Regs0, Acc) ->
- Ss = rename_sources(Ss0, Regs0),
- Regs = put_reg(Dst0, Regs0),
- Dst = fetch_reg(Dst0, Regs),
- rename_regs(Is, Regs, [{set,[Dst],Ss,Info}|Acc]);
-rename_regs([], Regs, Acc) -> {reverse(Acc),Regs}.
-
-rename_sources(Ss, Regs) ->
- map(fun({x,_}=R) -> fetch_reg(R, Regs);
- ({tmp,_}=R) -> fetch_reg(R, Regs);
- (E) -> E
- end, Ss).
-
-%%%
-%%% Keeping track of register assignments.
-%%%
-
-init_regs(Free) ->
- init_regs_1(Free, 0).
-
-init_regs_1([{x,I}=V|T], I) ->
- [{I,V}|init_regs_1(T, I+1)];
-init_regs_1([{x,X}|_]=T, I) when I < X ->
- [{I,reserved}|init_regs_1(T, I+1)];
-init_regs_1([{y,_}|_], _) -> [];
-init_regs_1([], _) -> [].
-
-put_reg(V, Rs) -> put_reg_1(V, Rs, 0).
-
-put_reg_1(V, [R|Rs], I) -> [R|put_reg_1(V, Rs, I+1)];
-put_reg_1(V, [], I) -> [{I,V}].
-
-fetch_reg(V, [{I,V}|_]) -> {x,I};
-fetch_reg(V, [_|SRs]) -> fetch_reg(V, SRs).
-
-live_regs([{_,reserved}|_]) ->
- %% We are not sure that this register is initialized, so we must
- %% abort the optimization.
- throw(gc_bif_alloc_failure);
-live_regs([{I,_}]) ->
- I+1;
-live_regs([{_,_}|Regs]) ->
- live_regs(Regs);
-live_regs([]) ->
- 0.
-
-
-%%%
-%%% Convert a block to Static Single Assignment (SSA) form.
-%%%
-
--record(ssa,
- {live=0, %Variable counter.
- sub=gb_trees:empty(), %Substitution table.
- prot=gb_sets:empty(), %Targets assigned by protecteds.
- in_prot=false %Inside a protected.
- }).
-
-ssa_block(Is0) ->
- {Is,_} = ssa_block_1(Is0, #ssa{}, []),
- Is.
-
-ssa_block_1([{protected,[_],Pa0,Pb}|Is], Sub0, Acc) ->
- {Pa,Sub1} = ssa_block_1(Pa0, Sub0#ssa{in_prot=true}, []),
- Dst = ssa_last_target(Pa),
- Sub = Sub1#ssa{prot=gb_sets:insert(Dst, Sub1#ssa.prot),
- in_prot=Sub0#ssa.in_prot},
- ssa_block_1(Is, Sub, [{protected,[Dst],Pa,Pb}|Acc]);
-ssa_block_1([{set,[Dst],As,Bif}|Is], Sub0, Acc0) ->
- Sub1 = ssa_in_use_list(As, Sub0),
- Sub = ssa_assign(Dst, Sub1),
- Acc = [{set,[ssa_sub(Dst, Sub)],ssa_sub_list(As, Sub0),Bif}|Acc0],
- ssa_block_1(Is, Sub, Acc);
-ssa_block_1([], Sub, Acc) -> {reverse(Acc),Sub}.
-
-ssa_in_use_list(As, Sub) ->
- foldl(fun ssa_in_use/2, Sub, As).
-
-ssa_in_use({x,_}=R, #ssa{sub=Sub0}=Ssa) ->
- case gb_trees:is_defined(R, Sub0) of
- true -> Ssa;
- false ->
- Sub = gb_trees:insert(R, R, Sub0),
- Ssa#ssa{sub=Sub}
- end;
-ssa_in_use(_, Ssa) -> Ssa.
-
-ssa_assign({x,_}=R, #ssa{sub=Sub0}=Ssa0) ->
- {NewReg,Ssa} = ssa_new_reg(Ssa0),
- case gb_trees:is_defined(R, Sub0) of
- false ->
- Sub = gb_trees:insert(R, NewReg, Sub0),
- Ssa#ssa{sub=Sub};
- true ->
- Sub1 = gb_trees:update(R, NewReg, Sub0),
- Sub = gb_trees:insert(NewReg, NewReg, Sub1),
- Ssa#ssa{sub=Sub}
- end.
-
-ssa_sub_list(List, Sub) ->
- [ssa_sub(E, Sub) || E <- List].
-
-ssa_sub(R0, #ssa{sub=Sub,prot=Prot,in_prot=InProt}) ->
- case gb_trees:lookup(R0, Sub) of
- none -> R0;
- {value,R} ->
- case InProt andalso gb_sets:is_element(R, Prot) of
- true ->
- throw(protected_violation);
- false ->
- R
- end
- end.
-
-ssa_new_reg(#ssa{live=Reg}=Ssa) ->
- {{tmp,Reg},Ssa#ssa{live=Reg+1}}.
-
-ssa_last_target([{set,[Dst],_,_}]) -> Dst;
-ssa_last_target([_|Is]) -> ssa_last_target(Is).
-
-%% is_killed(Register, [Instruction], FailLabel, State) -> true|false
-%% Determine whether a register is killed in the instruction sequence.
-%% The state is used to allow us to determine the kill state
-%% across branches.
-
-is_killed(R, Is, Label, #st{ll=Ll}) ->
- beam_utils:is_killed(R, Is, Ll) andalso
- beam_utils:is_killed_at(R, Label, Ll).
-
-%% is_not_used(Register, [Instruction], FailLabel, State) -> true|false
-%% Determine whether a register is never used in the instruction sequence
-%% (it could still referenced by an allocate instruction, meaning that
-%% it MUST be initialized).
-%% The state is used to allow us to determine the usage state
-%% across branches.
-
-is_not_used(R, Is, Label, #st{ll=Ll}) ->
- beam_utils:is_not_used(R, Is, Ll) andalso
- beam_utils:is_not_used_at(R, Label, Ll).
-
-%% initialized_regs([Instruction]) -> [Register])
-%% Given a REVERSED instruction sequence, return a list of the registers
-%% that are guaranteed to be initialized (not contain garbage).
-
-initialized_regs(Is) ->
- initialized_regs(Is, ordsets:new()).
-
-initialized_regs([{set,Dst,_Src,{alloc,Live,_}}|_], Regs0) ->
- Regs = add_init_regs(free_vars_regs(Live), Regs0),
- add_init_regs(Dst, Regs);
-initialized_regs([{set,Dst,Src,_}|Is], Regs) ->
- initialized_regs(Is, add_init_regs(Dst, add_init_regs(Src, Regs)));
-initialized_regs([{test,_,_,Src}|Is], Regs) ->
- initialized_regs(Is, add_init_regs(Src, Regs));
-initialized_regs([{block,Bl}|Is], Regs) ->
- initialized_regs(reverse(Bl, Is), Regs);
-initialized_regs([{bs_context_to_binary,Src}|Is], Regs) ->
- initialized_regs(Is, add_init_regs([Src], Regs));
-initialized_regs([{label,_},{func_info,_,_,Arity}|_], Regs) ->
- InitRegs = free_vars_regs(Arity),
- add_init_regs(InitRegs, Regs);
-initialized_regs([_|_], Regs) -> Regs.
-
-add_init_regs([{x,_}=X|T], Regs) ->
- add_init_regs(T, ordsets:add_element(X, Regs));
-add_init_regs([_|T], Regs) ->
- add_init_regs(T, Regs);
-add_init_regs([], Regs) -> Regs.
diff --git a/lib/compiler/src/beam_bs.erl b/lib/compiler/src/beam_bs.erl
new file mode 100644
index 0000000000..beb055b23d
--- /dev/null
+++ b/lib/compiler/src/beam_bs.erl
@@ -0,0 +1,281 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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%
+%%
+%% Purpose : Partitions assembly instructions into basic blocks and
+%% optimizes them.
+
+-module(beam_bs).
+
+-export([module/2]).
+-import(lists, [mapfoldl/3,reverse/1]).
+
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
+module({Mod,Exp,Attr,Fs0,Lc0}, _Opt) ->
+ {Fs,Lc} = mapfoldl(fun function/2, Lc0, Fs0),
+ {ok,{Mod,Exp,Attr,Fs,Lc}}.
+
+function({function,Name,Arity,CLabel,Is0}, Lc0) ->
+ try
+ Is1 = bs_put_opt(Is0),
+ {Is,Lc} = bsm_opt(Is1, Lc0),
+ {{function,Name,Arity,CLabel,Is},Lc}
+ catch
+ Class:Error ->
+ Stack = erlang:get_stacktrace(),
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+%%%
+%%% Evaluation of constant bit fields.
+%%%
+
+bs_put_opt([{bs_put,_,_,_}=I|Is0]) ->
+ {BsPuts0,Is} = collect_bs_puts(Is0, [I]),
+ BsPuts = opt_bs_puts(BsPuts0),
+ BsPuts ++ bs_put_opt(Is);
+bs_put_opt([I|Is]) ->
+ [I|bs_put_opt(Is)];
+bs_put_opt([]) -> [].
+
+collect_bs_puts([{bs_put,_,_,_}=I|Is], Acc) ->
+ collect_bs_puts(Is, [I|Acc]);
+collect_bs_puts([_|_]=Is, Acc) ->
+ {reverse(Acc),Is}.
+
+opt_bs_puts(Is) ->
+ opt_bs_1(Is, []).
+
+opt_bs_1([{bs_put,Fail,
+ {bs_put_float,1,Flags0},[{integer,Sz},Src]}=I0|Is], Acc) ->
+ try eval_put_float(Src, Sz, Flags0) of
+ <<Int:Sz>> ->
+ Flags = force_big(Flags0),
+ I = {bs_put,Fail,{bs_put_integer,1,Flags},
+ [{integer,Sz},{integer,Int}]},
+ opt_bs_1([I|Is], Acc)
+ catch
+ error:_ ->
+ opt_bs_1(Is, [I0|Acc])
+ end;
+opt_bs_1([{bs_put,_,{bs_put_integer,1,_},[{integer,8},{integer,_}]}|_]=IsAll,
+ Acc0) ->
+ {Is,Acc} = bs_collect_string(IsAll, Acc0),
+ opt_bs_1(Is, Acc);
+opt_bs_1([{bs_put,Fail,{bs_put_integer,1,F},[{integer,Sz},{integer,N}]}=I|Is0],
+ Acc) when Sz > 8 ->
+ case field_endian(F) of
+ big ->
+ %% We can do this optimization for any field size without
+ %% risk for code explosion.
+ case bs_split_int(N, Sz, Fail, Is0) of
+ no_split -> opt_bs_1(Is0, [I|Acc]);
+ Is -> opt_bs_1(Is, Acc)
+ end;
+ little when Sz < 128 ->
+ %% We only try to optimize relatively small fields, to
+ %% avoid an explosion in code size.
+ <<Int:Sz>> = <<N:Sz/little>>,
+ Flags = force_big(F),
+ Is = [{bs_put,Fail,{bs_put_integer,1,Flags},
+ [{integer,Sz},{integer,Int}]}|Is0],
+ opt_bs_1(Is, Acc);
+ _ -> %native or too wide little field
+ opt_bs_1(Is0, [I|Acc])
+ end;
+opt_bs_1([{bs_put,Fail,{Op,U,F},[{integer,Sz},Src]}|Is], Acc) when U > 1 ->
+ opt_bs_1([{bs_put,Fail,{Op,1,F},[{integer,U*Sz},Src]}|Is], Acc);
+opt_bs_1([I|Is], Acc) ->
+ opt_bs_1(Is, [I|Acc]);
+opt_bs_1([], Acc) -> reverse(Acc).
+
+eval_put_float(Src, Sz, Flags) when Sz =< 256 ->
+ %%Only evaluate if Sz is reasonable.
+ Val = value(Src),
+ case field_endian(Flags) of
+ little -> <<Val:Sz/little-float-unit:1>>;
+ big -> <<Val:Sz/big-float-unit:1>>
+ %% native intentionally not handled here - we can't optimize
+ %% it.
+ end.
+
+value({integer,I}) -> I;
+value({float,F}) -> F.
+
+bs_collect_string(Is, [{bs_put,_,{bs_put_string,Len,{string,Str}},[]}|Acc]) ->
+ bs_coll_str_1(Is, Len, reverse(Str), Acc);
+bs_collect_string(Is, Acc) ->
+ bs_coll_str_1(Is, 0, [], Acc).
+
+bs_coll_str_1([{bs_put,_,{bs_put_integer,U,_},[{integer,Sz},{integer,V}]}|Is],
+ Len, StrAcc, IsAcc) when U*Sz =:= 8 ->
+ Byte = V band 16#FF,
+ bs_coll_str_1(Is, Len+1, [Byte|StrAcc], IsAcc);
+bs_coll_str_1(Is, Len, StrAcc, IsAcc) ->
+ {Is,[{bs_put,{f,0},{bs_put_string,Len,{string,reverse(StrAcc)}},[]}|IsAcc]}.
+
+field_endian({field_flags,F}) -> field_endian_1(F).
+
+field_endian_1([big=E|_]) -> E;
+field_endian_1([little=E|_]) -> E;
+field_endian_1([native=E|_]) -> E;
+field_endian_1([_|Fs]) -> field_endian_1(Fs).
+
+force_big({field_flags,F}) ->
+ {field_flags,force_big_1(F)}.
+
+force_big_1([big|_]=Fs) -> Fs;
+force_big_1([little|Fs]) -> [big|Fs];
+force_big_1([F|Fs]) -> [F|force_big_1(Fs)].
+
+bs_split_int(0, Sz, _, _) when Sz > 64 ->
+ %% We don't want to split in this case because the
+ %% string will consist of only zeroes.
+ no_split;
+bs_split_int(-1, Sz, _, _) when Sz > 64 ->
+ %% We don't want to split in this case because the
+ %% string will consist of only 255 bytes.
+ no_split;
+bs_split_int(N, Sz, Fail, Acc) ->
+ FirstByteSz = case Sz rem 8 of
+ 0 -> 8;
+ Rem -> Rem
+ end,
+ bs_split_int_1(N, FirstByteSz, Sz, Fail, Acc).
+
+bs_split_int_1(-1, _, Sz, Fail, Acc) when Sz > 64 ->
+ I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
+ [{integer,Sz},{integer,-1}]},
+ [I|Acc];
+bs_split_int_1(0, _, Sz, Fail, Acc) when Sz > 64 ->
+ I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
+ [{integer,Sz},{integer,0}]},
+ [I|Acc];
+bs_split_int_1(N, ByteSz, Sz, Fail, Acc) when Sz > 0 ->
+ Mask = (1 bsl ByteSz) - 1,
+ I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
+ [{integer,ByteSz},{integer,N band Mask}]},
+ bs_split_int_1(N bsr ByteSz, 8, Sz-ByteSz, Fail, [I|Acc]);
+bs_split_int_1(_, _, _, _, Acc) -> Acc.
+
+%%%
+%%% Optimization of bit syntax matching: get rid
+%%% of redundant bs_restore2/2 instructions across select_val
+%%% instructions, as well as a few other simple peep-hole
+%%% optimizations.
+%%%
+
+bsm_opt(Is0, Lc0) ->
+ {Is1,D0,Lc} = bsm_scan(Is0, [], Lc0, []),
+ Is2 = case D0 of
+ [] ->
+ %% No bit syntax matching in this function.
+ Is1;
+ [_|_] ->
+ %% Optimize the bit syntax matching.
+ D = gb_trees:from_orddict(orddict:from_list(D0)),
+ bsm_reroute(Is1, D, none, [])
+ end,
+ Is = beam_clean:bs_clean_saves(Is2),
+ {bsm_opt_2(Is, []),Lc}.
+
+bsm_scan([{label,L}=Lbl,{bs_restore2,_,Save}=R|Is], D0, Lc, Acc0) ->
+ D = [{{L,Save},Lc}|D0],
+ Acc = [{label,Lc},R,Lbl|Acc0],
+ bsm_scan(Is, D, Lc+1, Acc);
+bsm_scan([I|Is], D, Lc, Acc) ->
+ bsm_scan(Is, D, Lc, [I|Acc]);
+bsm_scan([], D, Lc, Acc) ->
+ {reverse(Acc),D,Lc}.
+
+bsm_reroute([{bs_save2,Reg,Save}=I|Is], D, _, Acc) ->
+ bsm_reroute(Is, D, {Reg,Save}, [I|Acc]);
+bsm_reroute([{bs_restore2,Reg,Save}=I|Is], D, _, Acc) ->
+ bsm_reroute(Is, D, {Reg,Save}, [I|Acc]);
+bsm_reroute([{label,_}=I|Is], D, S, Acc) ->
+ bsm_reroute(Is, D, S, [I|Acc]);
+bsm_reroute([{select,select_val,Reg,F0,Lbls0}|Is], D, {_,Save}=S, Acc0) ->
+ [F|Lbls] = bsm_subst_labels([F0|Lbls0], Save, D),
+ Acc = [{select,select_val,Reg,F,Lbls}|Acc0],
+ bsm_reroute(Is, D, S, Acc);
+bsm_reroute([{test,TestOp,F0,TestArgs}=I|Is], D, {_,Save}=S, Acc0) ->
+ F = bsm_subst_label(F0, Save, D),
+ Acc = [{test,TestOp,F,TestArgs}|Acc0],
+ case bsm_not_bs_test(I) of
+ true ->
+ %% The test instruction will not update the bit offset for
+ %% the binary being matched. Therefore the save position
+ %% can be kept.
+ bsm_reroute(Is, D, S, Acc);
+ false ->
+ %% The test instruction might update the bit offset. Kill
+ %% our remembered Save position.
+ bsm_reroute(Is, D, none, Acc)
+ end;
+bsm_reroute([{test,TestOp,F0,Live,TestArgs,Dst}|Is], D, {_,Save}, Acc0) ->
+ F = bsm_subst_label(F0, Save, D),
+ Acc = [{test,TestOp,F,Live,TestArgs,Dst}|Acc0],
+ %% The test instruction will update the bit offset. Kill our
+ %% remembered Save position.
+ bsm_reroute(Is, D, none, Acc);
+bsm_reroute([{block,[{set,[],[],{alloc,_,_}}]}=Bl,
+ {bs_context_to_binary,_}=I|Is], D, S, Acc) ->
+ %% To help further bit syntax optimizations.
+ bsm_reroute([I,Bl|Is], D, S, Acc);
+bsm_reroute([I|Is], D, _, Acc) ->
+ bsm_reroute(Is, D, none, [I|Acc]);
+bsm_reroute([], _, _, Acc) -> reverse(Acc).
+
+bsm_opt_2([{test,bs_test_tail2,F,[Ctx,Bits]}|Is],
+ [{test,bs_skip_bits2,F,[Ctx,{integer,I},Unit,_Flags]}|Acc]) ->
+ bsm_opt_2(Is, [{test,bs_test_tail2,F,[Ctx,Bits+I*Unit]}|Acc]);
+bsm_opt_2([{test,bs_skip_bits2,F,[Ctx,{integer,I1},Unit1,_]}|Is],
+ [{test,bs_skip_bits2,F,[Ctx,{integer,I2},Unit2,Flags]}|Acc]) ->
+ bsm_opt_2(Is, [{test,bs_skip_bits2,F,
+ [Ctx,{integer,I1*Unit1+I2*Unit2},1,Flags]}|Acc]);
+bsm_opt_2([I|Is], Acc) ->
+ bsm_opt_2(Is, [I|Acc]);
+bsm_opt_2([], Acc) -> reverse(Acc).
+
+%% bsm_not_bs_test({test,Name,_,Operands}) -> true|false.
+%% Test whether is the test is a "safe", i.e. does not move the
+%% bit offset for a binary.
+%%
+%% 'true' means that the test is safe, 'false' that we don't know or
+%% that the test moves the offset (e.g. bs_get_integer2).
+
+bsm_not_bs_test({test,bs_test_tail2,_,[_,_]}) -> true;
+bsm_not_bs_test(Test) -> beam_utils:is_pure_test(Test).
+
+bsm_subst_labels(Fs, Save, D) ->
+ bsm_subst_labels_1(Fs, Save, D, []).
+
+bsm_subst_labels_1([F|Fs], Save, D, Acc) ->
+ bsm_subst_labels_1(Fs, Save, D, [bsm_subst_label(F, Save, D)|Acc]);
+bsm_subst_labels_1([], _, _, Acc) ->
+ reverse(Acc).
+
+bsm_subst_label({f,Lbl0}=F, Save, D) ->
+ case gb_trees:lookup({Lbl0,Save}, D) of
+ {value,Lbl} -> {f,Lbl};
+ none -> F
+ end;
+bsm_subst_label(Other, _, _) -> Other.
diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl
index 62356928ae..9a4e7fb133 100644
--- a/lib/compiler/src/beam_bsm.erl
+++ b/lib/compiler/src/beam_bsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
@@ -60,19 +60,26 @@
%%% data structures or passed to BIFs.
%%%
+-type label() :: beam_asm:label().
+-type func_info() :: {beam_asm:reg(),boolean()}.
+
-record(btb,
- {f, %Gbtrees for all functions.
- index, %{Label,Code} index (for liveness).
- ok_br, %Labels that are OK.
- must_not_save, %Must not save position when
- % optimizing (reaches
- % bs_context_to_binary).
- must_save %Must save position when optimizing.
+ {f :: gb_trees:tree(label(), func_info()),
+ index :: beam_utils:code_index(), %{Label,Code} index (for liveness).
+ ok_br=gb_sets:empty() :: gb_sets:set(label()), %Labels that are OK.
+ must_not_save=false :: boolean(), %Must not save position when
+ % optimizing (reaches
+ % bs_context_to_binary).
+ must_save=false :: boolean() %Must save position when optimizing.
}).
+
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
module({Mod,Exp,Attr,Fs0,Lc}, Opts) ->
- D = #btb{f=btb_index(Fs0)},
- Fs = [function(F, D) || F <- Fs0],
+ FIndex = btb_index(Fs0),
+ Fs = [function(F, FIndex) || F <- Fs0],
Code = {Mod,Exp,Attr,Fs,Lc},
case proplists:get_bool(bin_opt_info, Opts) of
true ->
@@ -92,10 +99,10 @@ format_error({no_bin_opt,Reason}) ->
%%% Local functions.
%%%
-function({function,Name,Arity,Entry,Is}, D0) ->
+function({function,Name,Arity,Entry,Is}, FIndex) ->
try
Index = beam_utils:index_labels(Is),
- D = D0#btb{index=Index},
+ D = #btb{f=FIndex,index=Index},
{function,Name,Arity,Entry,btb_opt_1(Is, D, [])}
catch
Class:Error ->
@@ -179,15 +186,14 @@ btb_gen_save(false, _, Acc) -> Acc.
%% a bs_context_to_binary instruction.
%%
-btb_reaches_match(Is, RegList, D0) ->
+btb_reaches_match(Is, RegList, D) ->
try
Regs = btb_regs_from_list(RegList),
- D = D0#btb{ok_br=gb_sets:empty(),must_not_save=false,must_save=false},
#btb{must_not_save=MustNotSave,must_save=MustSave} =
- btb_reaches_match_1(Is, Regs, D),
- case MustNotSave and MustSave of
+ btb_reaches_match_1(Is, Regs, D),
+ case MustNotSave andalso MustSave of
true -> btb_error(must_and_must_not_save);
- _ -> {ok,MustSave}
+ false -> {ok,MustSave}
end
catch
throw:{error,_}=Error -> Error
@@ -205,8 +211,15 @@ btb_reaches_match_1(Is, Regs, D) ->
btb_reaches_match_2([{block,Bl}|Is], Regs0, D) ->
Regs = btb_reaches_match_block(Bl, Regs0),
btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{call,Arity,{f,Lbl}}|Is], Regs, D) ->
- btb_call(Arity, Lbl, Regs, Is, D);
+btb_reaches_match_2([{call,Arity,{f,Lbl}}|Is], Regs0, D) ->
+ case is_tail_call(Is) of
+ true ->
+ Regs1 = btb_kill_not_live(Arity, Regs0),
+ Regs = btb_kill_yregs(Regs1),
+ btb_tail_call(Lbl, Regs, D);
+ false ->
+ btb_call(Arity, Lbl, Regs0, Is, D)
+ end;
btb_reaches_match_2([{apply,Arity}|Is], Regs, D) ->
btb_call(Arity+2, apply, Regs, Is, D);
btb_reaches_match_2([{call_fun,Live}=I|Is], Regs, D) ->
@@ -360,6 +373,10 @@ btb_reaches_match_2([{line,_}|Is], Regs, D) ->
btb_reaches_match_2([I|_], Regs, _) ->
btb_error({btb_context_regs(Regs),I,not_handled}).
+is_tail_call([{deallocate,_}|_]) -> true;
+is_tail_call([return|_]) -> true;
+is_tail_call(_) -> false.
+
btb_call(Arity, Lbl, Regs0, Is, D0) ->
Regs = btb_kill_not_live(Arity, Regs0),
case btb_are_x_registers_empty(Regs) of
@@ -369,15 +386,15 @@ btb_call(Arity, Lbl, Regs0, Is, D0) ->
D = btb_tail_call(Lbl, Regs, D0),
%% No problem so far (the called function can handle a
- %% match context). Now we must make sure that the rest
- %% of this function following the call does not attempt
- %% to use the match context in case there is a copy
- %% tucked away in a y register.
+ %% match context). Now we must make sure that we don't
+ %% have any copies of the match context tucked away in an
+ %% y register.
RegList = btb_context_regs(Regs),
- YRegs = [R || {y,_}=R <- RegList],
- case btb_are_all_unused(YRegs, Is, D) of
- true -> D;
- false -> btb_error({multiple_uses,RegList})
+ case [R || {y,_}=R <- RegList] of
+ [] ->
+ D;
+ [_|_] ->
+ btb_error({multiple_uses,RegList})
end;
true ->
%% No match context in any x register. It could have been
diff --git a/lib/compiler/src/beam_clean.erl b/lib/compiler/src/beam_clean.erl
index 919ee3ee7d..b736d39f9c 100644
--- a/lib/compiler/src/beam_clean.erl
+++ b/lib/compiler/src/beam_clean.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,6 +26,9 @@
-export([clean_labels/1]).
-import(lists, [map/2,foldl/3,reverse/1,filter/2]).
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
module({Mod,Exp,Attr,Fs0,_}, Opts) ->
Order = [Lbl || {function,_,_,Lbl,_} <- Fs0],
All = foldl(fun({function,_,_,Lbl,_}=Func,D) -> dict:store(Lbl, Func, D) end,
@@ -39,6 +42,10 @@ module({Mod,Exp,Attr,Fs0,_}, Opts) ->
{ok,{Mod,Exp,Attr,Fs,Lc}}.
%% Remove all bs_save2/2 instructions not referenced by a bs_restore2/2.
+
+-spec bs_clean_saves([beam_utils:instruction()]) ->
+ [beam_utils:instruction()].
+
bs_clean_saves(Is) ->
Needed = bs_restores(Is, []),
bs_clean_saves_1(Is, gb_sets:from_list(Needed), []).
@@ -98,13 +105,18 @@ add_to_work_list(F, {Fs,Used}=Sets) ->
%%% want to see the expanded code in a .S file.
%%%
--record(st, {lmap, %Translation tables for labels.
- entry, %Number of entry label.
- lc %Label counter
+-type label() :: beam_asm:label().
+
+-record(st, {lmap :: [{label(),label()}], %Translation tables for labels.
+ entry :: beam_asm:label(), %Number of entry label.
+ lc :: non_neg_integer() %Label counter
}).
+-spec clean_labels([beam_utils:instruction()]) ->
+ {[beam_utils:instruction()],pos_integer()}.
+
clean_labels(Fs0) ->
- St0 = #st{lmap=[],lc=1},
+ St0 = #st{lmap=[],entry=1,lc=1},
{Fs1,#st{lmap=Lmap0,lc=Lc}} = function_renumber(Fs0, St0, []),
Lmap = gb_trees:from_orddict(ordsets:from_list(Lmap0)),
Fs = function_replace(Fs1, Lmap, []),
@@ -141,7 +153,7 @@ renumber_labels([{bif,is_record,{f,_},
renumber_labels(Is, Acc, St);
renumber_labels([{test,is_record,{f,_}=Fail,
[Term,{atom,Tag}=TagAtom,{integer,Arity}]}|Is0], Acc, St) ->
- Tmp = {x,1023},
+ Tmp = {x,1022},
Is = case is_record_tuple(Term, Tag, Arity) of
yes ->
Is0;
@@ -190,17 +202,11 @@ replace([{test,Test,{f,Lbl},Ops}|Is], Acc, D) ->
replace([{test,Test,{f,Lbl},Live,Ops,Dst}|Is], Acc, D) ->
replace(Is, [{test,Test,{f,label(Lbl, D)},Live,Ops,Dst}|Acc], D);
replace([{select,I,R,{f,Fail0},Vls0}|Is], Acc, D) ->
- Vls1 = map(fun ({f,L}) -> {f,label(L, D)};
- (Other) -> Other end, Vls0),
+ Vls = map(fun ({f,L}) -> {f,label(L, D)};
+ (Other) -> Other
+ end, Vls0),
Fail = label(Fail0, D),
- case redundant_values(Vls1, Fail, []) of
- [] ->
- %% Oops, no choices left. The loader will not accept that.
- %% Convert to a plain jump.
- replace(Is, [{jump,{f,Fail}}|Acc], D);
- Vls ->
- replace(Is, [{select,I,R,{f,Fail},Vls}|Acc], D)
- end;
+ replace(Is, [{select,I,R,{f,Fail},Vls}|Acc], D);
replace([{'try',R,{f,Lbl}}|Is], Acc, D) ->
replace(Is, [{'try',R,{f,label(Lbl, D)}}|Acc], D);
replace([{'catch',R,{f,Lbl}}|Is], Acc, D) ->
@@ -241,12 +247,6 @@ label(Old, D) ->
{value,Val} -> Val;
none -> throw({error,{undefined_label,Old}})
end.
-
-redundant_values([_,{f,Fail}|Vls], Fail, Acc) ->
- redundant_values(Vls, Fail, Acc);
-redundant_values([Val,Lbl|Vls], Fail, Acc) ->
- redundant_values(Vls, Fail, [Lbl,Val|Acc]);
-redundant_values([], _, Acc) -> reverse(Acc).
%%%
%%% Final fixup of bs_start_match2/5,bs_save2/bs_restore2 instructions for
diff --git a/lib/compiler/src/beam_dead.erl b/lib/compiler/src/beam_dead.erl
index ead88b57e9..d379fdc4eb 100644
--- a/lib/compiler/src/beam_dead.erl
+++ b/lib/compiler/src/beam_dead.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,6 +29,10 @@
-import(lists, [mapfoldl/3,reverse/1]).
+
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
module({Mod,Exp,Attr,Fs0,_}, _Opts) ->
{Fs1,Lc1} = beam_clean:clean_labels(Fs0),
{Fs,Lc} = mapfoldl(fun function/2, Lc1, Fs1),
@@ -239,32 +243,69 @@ backward([{test,is_eq_exact,Fail,[Dst,{integer,Arity}]}=I|
backward([{label,Lbl}=L|Is], D, Acc) ->
backward(Is, beam_utils:index_label(Lbl, Acc, D), [L|Acc]);
backward([{select,select_val,Reg,{f,Fail0},List0}|Is], D, Acc) ->
- List = shortcut_select_list(List0, Reg, D, []),
+ List1 = shortcut_select_list(List0, Reg, D, []),
Fail1 = shortcut_label(Fail0, D),
Fail = shortcut_bs_test(Fail1, Is, D),
- Sel = {select,select_val,Reg,{f,Fail},List},
- backward(Is, D, [Sel|Acc]);
+ List = prune_redundant(List1, Fail),
+ case List of
+ [] ->
+ Jump = {jump,{f,Fail}},
+ backward([Jump|Is], D, Acc);
+ [V,F] ->
+ Test = {test,is_eq_exact,{f,Fail},[Reg,V]},
+ Jump = {jump,F},
+ backward([Jump,Test|Is], D, Acc);
+ [{atom,B1},F,{atom,B2},F] when B1 =:= not B2 ->
+ Test = {test,is_boolean,{f,Fail},[Reg]},
+ Jump = {jump,F},
+ backward([Jump,Test|Is], D, Acc);
+ [_|_] ->
+ Sel = {select,select_val,Reg,{f,Fail},List},
+ backward(Is, D, [Sel|Acc])
+ end;
backward([{jump,{f,To0}},{move,Src,Reg}=Move|Is], D, Acc) ->
To = shortcut_select_label(To0, Reg, Src, D),
Jump = {jump,{f,To}},
- case beam_utils:is_killed_at(Reg, To, D) of
+ case is_killed_at(Reg, To, D) of
false -> backward([Move|Is], D, [Jump|Acc]);
true -> backward([Jump|Is], D, Acc)
end;
-backward([{jump,{f,To}}=J|[{bif,Op,_,Ops,Reg}|Is]=Is0], D, Acc) ->
+backward([{jump,{f,To}}=J|[{bif,Op,{f,BifFail},Ops,Reg}|Is]=Is0], D, Acc) ->
try replace_comp_op(To, Reg, Op, Ops, D) of
I -> backward(Is, D, I++Acc)
catch
- throw:not_possible -> backward(Is0, D, [J|Acc])
+ throw:not_possible ->
+ case To =:= BifFail of
+ true ->
+ %% The bif instruction is redundant. See the comment
+ %% in the next clause for why there is no need to
+ %% test for liveness of Reg at label To.
+ backward([J|Is], D, Acc);
+ false ->
+ backward(Is0, D, [J|Acc])
+ end
end;
-backward([{test,bs_start_match2,F,_,[R,_],Ctxt}=I|Is], D,
+backward([{jump,{f,To}}=J|[{gc_bif,_,{f,To},_,_,_Dst}|Is]], D, Acc) ->
+ %% The gc_bif instruction is redundant, since either the gc_bif
+ %% instruction itself or the jump instruction will transfer control
+ %% to label To. Note that a gc_bif instruction does not assign its
+ %% destination register if the failure branch is taken; therefore,
+ %% the code at label To is not allowed to assume that the destination
+ %% register is initialized, and it is therefore no need to test
+ %% for liveness of the destination register at label To.
+ backward([J|Is], D, Acc);
+backward([{test,bs_start_match2,F,Live,[R,_]=Args,Ctxt}|Is], D,
[{test,bs_match_string,F,[Ctxt,Bs]},
{test,bs_test_tail2,F,[Ctxt,0]}|Acc0]=Acc) ->
+ {f,To0} = F,
case beam_utils:is_killed(Ctxt, Acc0, D) of
true ->
- Eq = {test,is_eq_exact,F,[R,{literal,Bs}]},
+ To = shortcut_bs_context_to_binary(To0, R, D),
+ Eq = {test,is_eq_exact,{f,To},[R,{literal,Bs}]},
backward(Is, D, [Eq|Acc0]);
false ->
+ To = shortcut_bs_start_match(To0, R, D),
+ I = {test,bs_start_match2,{f,To},Live,Args,Ctxt},
backward(Is, D, [I|Acc])
end;
backward([{test,bs_start_match2,{f,To0},Live,[Src|_]=Info,Dst}|Is], D, Acc) ->
@@ -295,7 +336,28 @@ backward([{test,Op,{f,To0},Ops0}|Is], D, Acc) ->
is_eq_exact -> combine_eqs(To, Ops0, D, Acc);
_ -> {test,Op,{f,To},Ops0}
end,
- backward(Is, D, [I|Acc]);
+ case {I,Acc} of
+ {{test,is_atom,Fail,Ops0},[{test,is_boolean,Fail,Ops0}|_]} ->
+ %% An is_atom test before an is_boolean test (with the
+ %% same failure label) is redundant.
+ backward(Is, D, Acc);
+ {{test,is_atom,Fail,[R]},
+ [{test,is_eq_exact,Fail,[R,{atom,_}]}|_]} ->
+ %% An is_atom test before a comparison with an atom (with
+ %% the same failure label) is redundant.
+ backward(Is, D, Acc);
+ {{test,is_integer,Fail,[R]},
+ [{test,is_eq_exact,Fail,[R,{integer,_}]}|_]} ->
+ %% An is_integer test before a comparison with an integer
+ %% (with the same failure label) is redundant.
+ backward(Is, D, Acc);
+ {{test,_,_,_},_} ->
+ %% Still a test instruction. Done.
+ backward(Is, D, [I|Acc]);
+ {_,_} ->
+ %% Rewritten to a select_val. Rescan.
+ backward([I|Is], D, Acc)
+ end;
backward([{test,Op,{f,To0},Live,Ops0,Dst}|Is], D, Acc) ->
To1 = shortcut_bs_test(To0, Is, D),
To2 = shortcut_label(To1, D),
@@ -321,6 +383,14 @@ backward([{kill,_}=I|Is], D, [{line,_},Exit|_]=Acc) ->
false -> backward(Is, D, [I|Acc]);
true -> backward(Is, D, Acc)
end;
+backward([{bif,'or',{f,To0},[Dst,{atom,false}],Dst}=I|Is], D,
+ [{test,is_eq_exact,{f,To},[Dst,{atom,true}]}|_]=Acc) ->
+ case shortcut_label(To0, D) of
+ To ->
+ backward(Is, D, Acc);
+ _ ->
+ backward(Is, D, [I|Acc])
+ end;
backward([I|Is], D, Acc) ->
backward(Is, D, [I|Acc]);
backward([], _D, Acc) -> Acc.
@@ -339,6 +409,8 @@ shortcut_select_list([Lit,{f,To0}|T], Reg, D, Acc) ->
shortcut_select_list(T, Reg, D, [{f,To},Lit|Acc]);
shortcut_select_list([], _, _, Acc) -> reverse(Acc).
+shortcut_label(0, _) ->
+ 0;
shortcut_label(To0, D) ->
case beam_utils:code_at(To0, D) of
[{jump,{f,To}}|_] -> shortcut_label(To, D);
@@ -348,6 +420,12 @@ shortcut_label(To0, D) ->
shortcut_select_label(To, Reg, Lit, D) ->
shortcut_rel_op(To, is_ne_exact, [Reg,Lit], D).
+prune_redundant([_,{f,Fail}|T], Fail) ->
+ prune_redundant(T, Fail);
+prune_redundant([V,F|T], Fail) ->
+ [V,F|prune_redundant(T, Fail)];
+prune_redundant([], _) -> [].
+
%% Replace a comparison operator with a test instruction and a jump.
%% For example, if we have this code:
%%
@@ -375,7 +453,7 @@ comp_op_find_shortcut(To0, Reg, Val, D) ->
To0 ->
not_possible();
To ->
- case beam_utils:is_killed_at(Reg, To, D) of
+ case is_killed_at(Reg, To, D) of
false -> not_possible();
true -> To
end
@@ -509,6 +587,21 @@ shortcut_bs_start_match_1([{test,bs_start_match2,{f,To},_,[Reg|_],_}|_],
shortcut_bs_start_match_1(_, _, To, _) ->
To.
+%% shortcut_bs_context_to_binary(TargetLabel, Reg) -> TargetLabel
+%% If a bs_start_match2 instruction has been eliminated, the
+%% bs_context_to_binary instruction can be eliminated too.
+
+shortcut_bs_context_to_binary(To, Reg, D) ->
+ shortcut_bs_ctb_1(beam_utils:code_at(To, D), Reg, To, D).
+
+shortcut_bs_ctb_1([{bs_context_to_binary,Reg}|Is], Reg, To, D) ->
+ shortcut_bs_ctb_1(Is, Reg, To, D);
+shortcut_bs_ctb_1([{jump,{f,To}}|_], Reg, _, D) ->
+ Code = beam_utils:code_at(To, D),
+ shortcut_bs_ctb_1(Code, Reg, To, D);
+shortcut_bs_ctb_1(_, _, To, _) ->
+ To.
+
%% shortcut_rel_op(FailLabel, Operator, [Operand], D) -> FailLabel'
%% Try to shortcut the given test instruction. Example:
%%
@@ -818,3 +911,17 @@ get_literal(nil) ->
get_literal({literal,_}=Lit) ->
Lit;
get_literal({_,_}) -> error.
+
+
+%%%
+%%% Removing stores to Y registers is not always safe
+%%% if there is an instruction that causes an exception
+%%% within a catch. In practice, there are few or no
+%%% opportunities for removing stores to Y registers anyway
+%%% if sys_core_fold has been run.
+%%%
+
+is_killed_at({x,_}=Reg, Lbl, D) ->
+ beam_utils:is_killed_at(Reg, Lbl, D);
+is_killed_at({y,_}, _, _) ->
+ false.
diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl
index 2b5f8c1b7f..990e86062a 100644
--- a/lib/compiler/src/beam_dict.erl
+++ b/lib/compiler/src/beam_dict.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
@@ -24,11 +24,11 @@
-export([new/0,opcode/2,highest_opcode/1,
atom/2,local/4,export/4,import/4,
string/2,lambda/3,literal/2,line/2,fname/2,
- atom_table/1,local_table/1,export_table/1,import_table/1,
+ atom_table/2,local_table/1,export_table/1,import_table/1,
string_table/1,lambda_table/1,literal_table/1,
line_table/1]).
--type label() :: non_neg_integer().
+-type label() :: beam_asm:label().
-type index() :: non_neg_integer().
@@ -38,13 +38,16 @@
-type line_tab() :: #{{Fname :: index(), Line :: term()} => index()}.
-type literal_tab() :: dict:dict(Literal :: term(), index()).
+-type lambda_info() :: {label(),{index(),label(),non_neg_integer()}}.
+-type lambda_tab() :: {non_neg_integer(),[lambda_info()]}.
+
-record(asm,
{atoms = #{} :: atom_tab(),
exports = [] :: [{label(), arity(), label()}],
locals = [] :: [{label(), arity(), label()}],
imports = gb_trees:empty() :: import_tab(),
strings = <<>> :: binary(), %String pool
- lambdas = [], %[{...}]
+ lambdas = {0,[]} :: lambda_tab(),
literals = dict:new() :: literal_tab(),
fnames = #{} :: fname_tab(),
lines = #{} :: line_tab(),
@@ -145,15 +148,11 @@ string(Str, Dict) when is_list(Str) ->
-spec lambda(label(), non_neg_integer(), bdict()) ->
{non_neg_integer(), bdict()}.
-lambda(Lbl, NumFree, #asm{lambdas=Lambdas0}=Dict) ->
- OldIndex = length(Lambdas0),
+lambda(Lbl, NumFree, #asm{lambdas={OldIndex,Lambdas0}}=Dict) ->
%% Set Index the same as OldIndex.
Index = OldIndex,
- %% Initialize OldUniq to 0. It will be set to an unique value
- %% based on the MD5 checksum of the BEAM code for the module.
- OldUniq = 0,
- Lambdas = [{Lbl,{OldIndex,Lbl,Index,NumFree,OldUniq}}|Lambdas0],
- {OldIndex,Dict#asm{lambdas=Lambdas}}.
+ Lambdas = [{Lbl,{Index,Lbl,NumFree}}|Lambdas0],
+ {OldIndex,Dict#asm{lambdas={OldIndex+1,Lambdas}}}.
%% Returns the index for a literal (adding it to the literal table if necessary).
%% literal(Literal, Dict) -> {Index,Dict'}
@@ -186,6 +185,9 @@ line([{location,Name,Line}], #asm{lines=Lines,num_lines=N}=Dict0) ->
{Index, Dict1#asm{lines=Lines#{Key=>Index},num_lines=N+1}}
end.
+-spec fname(nonempty_string(), bdict()) ->
+ {non_neg_integer(), bdict()}.
+
fname(Name, #asm{fnames=Fnames}=Dict) ->
case Fnames of
#{Name := Index} -> {Index,Dict};
@@ -195,15 +197,15 @@ fname(Name, #asm{fnames=Fnames}=Dict) ->
end.
%% Returns the atom table.
-%% atom_table(Dict) -> {LastIndex,[Length,AtomString...]}
--spec atom_table(bdict()) -> {non_neg_integer(), [[non_neg_integer(),...]]}.
+%% atom_table(Dict, Encoding) -> {LastIndex,[Length,AtomString...]}
+-spec atom_table(bdict(), latin1 | utf8) -> {non_neg_integer(), [[non_neg_integer(),...]]}.
-atom_table(#asm{atoms=Atoms}) ->
+atom_table(#asm{atoms=Atoms}, Encoding) ->
NumAtoms = maps:size(Atoms),
Sorted = lists:keysort(2, maps:to_list(Atoms)),
{NumAtoms,[begin
- L = atom_to_list(A),
- [length(L)|L]
+ L = atom_to_binary(A, Encoding),
+ [byte_size(L),L]
end || {A,_} <- Sorted]}.
%% Returns the table of local functions.
@@ -236,13 +238,16 @@ string_table(#asm{strings=Strings,string_offset=Size}) ->
-spec lambda_table(bdict()) -> {non_neg_integer(), [<<_:192>>]}.
-lambda_table(#asm{locals=Loc0,lambdas=Lambdas0}) ->
+lambda_table(#asm{locals=Loc0,lambdas={NumLambdas,Lambdas0}}) ->
Lambdas1 = sofs:relation(Lambdas0),
Loc = sofs:relation([{Lbl,{F,A}} || {F,A,Lbl} <- Loc0]),
Lambdas2 = sofs:relative_product1(Lambdas1, Loc),
+ %% Initialize OldUniq to 0. It will be set to an unique value
+ %% based on the MD5 checksum of the BEAM code for the module.
+ OldUniq = 0,
Lambdas = [<<F:32,A:32,Lbl:32,Index:32,NumFree:32,OldUniq:32>> ||
- {{_,Lbl,Index,NumFree,OldUniq},{F,A}} <- sofs:to_external(Lambdas2)],
- {length(Lambdas),Lambdas}.
+ {{Index,Lbl,NumFree},{F,A}} <- sofs:to_external(Lambdas2)],
+ {NumLambdas,Lambdas}.
%% Returns the literal table.
%% literal_table(Dict) -> {NumLiterals, [<<TermSize>>,TermInExternalFormat]}
diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl
index 84a94f09e3..8fd0b36d05 100644
--- a/lib/compiler/src/beam_disasm.erl
+++ b/lib/compiler/src/beam_disasm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -314,10 +314,7 @@ get_funs({LsR0,[{func_info,[{atom,M}=AtomM,{atom,F}=AtomF,ArityArg]}|Code0]})
when is_atom(M), is_atom(F) ->
Arity = resolve_arg_unsigned(ArityArg),
{LsR,Code,RestCode} = get_fun(Code0, []),
- Entry = case Code of
- [{label,[{u,E}]}|_] -> E;
- _ -> undefined
- end,
+ [{label,[{u,Entry}]}|_] = Code,
[#function{name=F,
arity=Arity,
entry=Entry,
@@ -818,6 +815,9 @@ resolve_inst({is_tuple=I,Args0},_,_,_) ->
resolve_inst({test_arity=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
+resolve_inst({is_tagged_tuple=I,Args0},_,_,_) ->
+ [F|Args] = resolve_args(Args0),
+ {test,I,F,Args};
resolve_inst({select_val,Args},_,_,_) ->
[Reg,FLbl,{{z,1},{u,_Len},List0}] = Args,
List = resolve_args(List0),
diff --git a/lib/compiler/src/beam_disasm.hrl b/lib/compiler/src/beam_disasm.hrl
index 30e3f22665..d968cd9587 100644
--- a/lib/compiler/src/beam_disasm.hrl
+++ b/lib/compiler/src/beam_disasm.hrl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
@@ -22,7 +22,9 @@
%% the system (e.g. in the translation from Beam to Icode).
%%
-%% XXX: THE FOLLOWING TYPE DECLARATION DOES NOT BELONG HERE...
+%% XXX: THE FOLLOWING TYPE DECLARATION DOES NOT BELONG HERE.
+%% IT SHOULD BE MOVED TO A FILE THAT DEFINES (AND EXPORTS)
+%% PROPER TYPES FOR THE SET OF BEAM INSTRUCTIONS.
%%
-type beam_instr() :: 'bs_init_writable' | 'fclearerror' | 'if_end'
| 'remove_message' | 'return' | 'send' | 'timeout'
@@ -34,7 +36,7 @@
-record(function, {name :: atom(),
arity :: byte(),
- entry, %% unused ??
+ entry :: beam_lib:label(), %% unnecessary ?
code = [] :: [beam_instr()]}).
-record(beam_file, {module :: module(),
diff --git a/lib/compiler/src/beam_except.erl b/lib/compiler/src/beam_except.erl
index e33655281f..9801c68ee2 100644
--- a/lib/compiler/src/beam_except.erl
+++ b/lib/compiler/src/beam_except.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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.
@@ -33,6 +33,9 @@
-import(lists, [reverse/1]).
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
Fs = [function(F) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
@@ -49,9 +52,9 @@ function({function,Name,Arity,CLabel,Is0}) ->
end.
-record(st,
- {lbl, %func_info label
- loc, %location for func_info
- arity %arity for function
+ {lbl :: beam_asm:label(), %func_info label
+ loc :: [_], %location for func_info
+ arity :: arity() %arity for function
}).
function_1(Is0) ->
@@ -133,10 +136,12 @@ translate_exception(_, _, _, _) -> no.
fix_block(Is, 0) ->
reverse(Is);
fix_block(Is, Words) ->
- fix_block_1(reverse(Is), Words).
+ reverse(fix_block_1(Is, Words)).
-fix_block_1([{set,[],[],{alloc,Live,{F1,F2,Needed,F3}}}|Is], Words) ->
- [{set,[],[],{alloc,Live,{F1,F2,Needed-Words,F3}}}|Is];
+fix_block_1([{set,[],[],{alloc,Live,{F1,F2,Needed0,F3}}}|Is], Words) ->
+ Needed = Needed0 - Words,
+ true = Needed >= 0, %Assertion.
+ [{set,[],[],{alloc,Live,{F1,F2,Needed,F3}}}|Is];
fix_block_1([I|Is], Words) ->
[I|fix_block_1(Is, Words)].
diff --git a/lib/compiler/src/beam_flatten.erl b/lib/compiler/src/beam_flatten.erl
index 13c243b155..a4d45a4ca6 100644
--- a/lib/compiler/src/beam_flatten.erl
+++ b/lib/compiler/src/beam_flatten.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,9 @@
-import(lists, [reverse/1,reverse/2]).
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
module({Mod,Exp,Attr,Fs,Lc}, _Opt) ->
{ok,{Mod,Exp,Attr,[function(F) || F <- Fs],Lc}}.
@@ -64,7 +67,6 @@ norm({set,[],[S,D],{set_tuple_element,I}}) -> {set_tuple_element,S,D,I};
norm({set,[D1,D2],[S],get_list}) -> {get_list,S,D1,D2};
norm({set,[D],[S|Puts],{alloc,R,{put_map,Op,F}}}) ->
{put_map,F,Op,S,D,R,{list,Puts}};
-%% get_map_elements is always handled in beam_split (moved out of block)
norm({set,[],[],remove_message}) -> remove_message;
norm({set,[],[],fclearerror}) -> fclearerror;
norm({set,[],[],fcheckerror}) -> {fcheckerror,{f,0}}.
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index 5e58e0f6ac..4365451356 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
-export([module/2,
is_unreachable_after/1,is_exit_instruction/1,
- remove_unused_labels/1,is_label_used_in/2]).
+ remove_unused_labels/1]).
%%% The following optimisations are done:
%%%
@@ -130,6 +130,11 @@
-import(lists, [reverse/1,reverse/2,foldl/3]).
+-type instruction() :: beam_utils:instruction().
+
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
Fs = [function(F) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
@@ -155,9 +160,7 @@ share(Is0) ->
Is = eliminate_fallthroughs(Is0, []),
share_1(Is, #{}, [], []).
-share_1([{label,_}=Lbl|Is], Dict, [], Acc) ->
- share_1(Is, Dict, [], [Lbl|Acc]);
-share_1([{label,L}=Lbl|Is], Dict0, Seq, Acc) ->
+share_1([{label,L}=Lbl|Is], Dict0, [_|_]=Seq, Acc) ->
case maps:find(Seq, Dict0) of
error ->
Dict = maps:put(Seq, L, Dict0),
@@ -167,12 +170,18 @@ share_1([{label,L}=Lbl|Is], Dict0, Seq, Acc) ->
end;
share_1([{func_info,_,_,_}=I|Is], _, [], Acc) ->
reverse(Is, [I|Acc]);
+share_1([{'catch',_,_}=I|Is], Dict0, Seq, Acc) ->
+ Dict = clean_non_sharable(Dict0),
+ share_1(Is, Dict, [I|Seq], Acc);
share_1([{'try',_,_}=I|Is], Dict0, Seq, Acc) ->
Dict = clean_non_sharable(Dict0),
share_1(Is, Dict, [I|Seq], Acc);
share_1([{try_case,_}=I|Is], Dict0, Seq, Acc) ->
Dict = clean_non_sharable(Dict0),
share_1(Is, Dict, [I|Seq], Acc);
+share_1([{catch_end,_}=I|Is], Dict0, Seq, Acc) ->
+ Dict = clean_non_sharable(Dict0),
+ share_1(Is, Dict, [I|Seq], Acc);
share_1([I|Is], Dict, Seq, Acc) ->
case is_unreachable_after(I) of
false ->
@@ -182,18 +191,18 @@ share_1([I|Is], Dict, Seq, Acc) ->
end.
clean_non_sharable(Dict) ->
- %% We are passing in or out of a 'try' block. Remove
- %% sequences that should not shared over the boundaries
- %% of a 'try' block. Since the end of the sequence must match,
- %% the only possible match between a sequence outside and
- %% a sequence inside the 'try' block is a sequence that ends
- %% with an instruction that causes an exception. Any sequence
- %% that causes an exception must contain a line/1 instruction.
+ %% We are passing in or out of a 'catch' or 'try' block. Remove
+ %% sequences that should not be shared over the boundaries of the
+ %% block. Since the end of the sequence must match, the only
+ %% possible match between a sequence outside and a sequence inside
+ %% the 'catch'/'try' block is a sequence that ends with an
+ %% instruction that causes an exception. Any sequence that causes
+ %% an exception must contain a line/1 instruction.
maps:filter(fun(K, _V) -> sharable_with_try(K) end, Dict).
sharable_with_try([{line,_}|_]) ->
%% This sequence may cause an exception and may potentially
- %% match a sequence on the other side of the 'try' block
+ %% match a sequence on the other side of the 'catch'/'try' block
%% boundary.
false;
sharable_with_try([_|Is]) ->
@@ -202,21 +211,18 @@ sharable_with_try([]) -> true.
%% Eliminate all fallthroughs. Return the result reversed.
-eliminate_fallthroughs([I,{label,L}=Lbl|Is], Acc) ->
- case is_unreachable_after(I) orelse is_label(I) of
+eliminate_fallthroughs([{label,L}=Lbl|Is], [I|_]=Acc) ->
+ case is_unreachable_after(I) of
false ->
%% Eliminate fallthrough.
- eliminate_fallthroughs(Is, [Lbl,{jump,{f,L}},I|Acc]);
+ eliminate_fallthroughs(Is, [Lbl,{jump,{f,L}}|Acc]);
true ->
- eliminate_fallthroughs(Is, [Lbl,I|Acc])
+ eliminate_fallthroughs(Is, [Lbl|Acc])
end;
eliminate_fallthroughs([I|Is], Acc) ->
eliminate_fallthroughs(Is, [I|Acc]);
eliminate_fallthroughs([], Acc) -> Acc.
-is_label({label,_}) -> true;
-is_label(_) -> false.
-
%%%
%%% (2) Move short code sequences ending in an instruction that causes an exit
%%% to the end of the function.
@@ -266,17 +272,17 @@ extract_seq_1(_, _) -> no.
%%% (3) (4) (5) (6) Jump and unreachable code optimizations.
%%%
--record(st, {fc, %Label for function class errors.
- entry, %Entry label (must not be moved).
- mlbl, %Moved labels.
- labels :: cerl_sets:set() %Set of referenced labels.
- }).
+-record(st,
+ {
+ entry :: beam_asm:label(), %Entry label (must not be moved).
+ mlbl :: #{beam_asm:label() := [beam_asm:label()]}, %Moved labels.
+ labels :: cerl_sets:set() %Set of referenced labels.
+ }).
-opt([{label,Fc}|_]=Is0, CLabel) ->
- Lbls = initial_labels(Is0),
+opt(Is0, CLabel) ->
find_fixpoint(fun(Is) ->
- St = #st{fc=Fc,entry=CLabel,mlbl=#{},
- labels=Lbls},
+ Lbls = initial_labels(Is),
+ St = #st{entry=CLabel,mlbl=#{},labels=Lbls},
opt(Is, [], St)
end, Is0).
@@ -327,7 +333,8 @@ opt([{label,Lbl}=I|Is], Acc, #st{mlbl=Mlbl}=St0) ->
%% since we will rescan the inserted labels. We MUST rescan.
St = St0#st{mlbl=maps:remove(Lbl, Mlbl)},
insert_labels([Lbl|Lbls], Is, Acc, St);
- error -> opt(Is, [I|Acc], St0)
+ error ->
+ opt(Is, [I|Acc], St0)
end;
opt([{jump,{f,_}=X}|[{label,_},{jump,X}|_]=Is], Acc, St) ->
opt(Is, Acc, St);
@@ -362,12 +369,19 @@ opt([I|Is], Acc, #st{labels=Used0}=St0) ->
true -> skip_unreachable(Is, [I|Acc], St);
false -> opt(Is, [I|Acc], St)
end;
-opt([], Acc, #st{fc=Fc,mlbl=Mlbl}) ->
+opt([], Acc, #st{mlbl=Mlbl}) ->
Code = reverse(Acc),
- case maps:find(Fc, Mlbl) of
- {ok,Lbls} -> insert_fc_labels(Lbls, Mlbl, Code);
- error -> Code
- end.
+ insert_fc_labels(Code, Mlbl).
+
+insert_fc_labels([{label,L}=I|Is0], Mlbl) ->
+ case maps:find(L, Mlbl) of
+ error ->
+ [I|insert_fc_labels(Is0, Mlbl)];
+ {ok,Lbls} ->
+ Is = [{label,Lb} || Lb <- Lbls] ++ Is0,
+ [I|insert_fc_labels(Is, maps:remove(L, Mlbl))]
+ end;
+insert_fc_labels([_|_]=Is, _) -> Is.
maps_append_list(K,Vs,M) ->
case M of
@@ -375,16 +389,6 @@ maps_append_list(K,Vs,M) ->
_ -> M#{K => Vs}
end.
-insert_fc_labels([L|Ls], Mlbl, Acc0) ->
- Acc = [{label,L}|Acc0],
- case maps:find(L, Mlbl) of
- error ->
- insert_fc_labels(Ls, Mlbl, Acc);
- {ok,Lbls} ->
- insert_fc_labels(Lbls++Ls, Mlbl, Acc)
- end;
-insert_fc_labels([], _, Acc) -> Acc.
-
collect_labels(Is, #st{entry=Entry}) ->
collect_labels_1(Is, Entry, []).
@@ -454,6 +458,8 @@ is_label_used(L, St) ->
%% is_unreachable_after(Instruction) -> boolean()
%% Test whether the code after Instruction is unreachable.
+-spec is_unreachable_after(instruction()) -> boolean().
+
is_unreachable_after({func_info,_M,_F,_A}) -> true;
is_unreachable_after(return) -> true;
is_unreachable_after({jump,_Lbl}) -> true;
@@ -466,6 +472,8 @@ is_unreachable_after(I) -> is_exit_instruction(I).
%% Test whether the instruction Instruction always
%% causes an exit/failure.
+-spec is_exit_instruction(instruction()) -> boolean().
+
is_exit_instruction({call_ext,_,{extfunc,M,F,A}}) ->
erl_bifs:is_exit_bif(M, F, A);
is_exit_instruction(if_end) -> true;
@@ -474,40 +482,12 @@ is_exit_instruction({try_case_end,_}) -> true;
is_exit_instruction({badmatch,_}) -> true;
is_exit_instruction(_) -> false.
-%% is_label_used_in(LabelNumber, [Instruction]) -> boolean()
-%% Check whether the label is used in the instruction sequence
-%% (including inside blocks).
-
-is_label_used_in(Lbl, Is) ->
- is_label_used_in_1(Is, Lbl, cerl_sets:new()).
-
-is_label_used_in_1([{block,Block}|Is], Lbl, Empty) ->
- lists:any(fun(I) -> is_label_used_in_block(I, Lbl) end, Block)
- orelse is_label_used_in_1(Is, Lbl, Empty);
-is_label_used_in_1([I|Is], Lbl, Empty) ->
- Used = ulbl(I, Empty),
- cerl_sets:is_element(Lbl, Used) orelse is_label_used_in_1(Is, Lbl, Empty);
-is_label_used_in_1([], _, _) -> false.
-
-is_label_used_in_block({set,_,_,Info}, Lbl) ->
- case Info of
- {bif,_,{f,F}} -> F =:= Lbl;
- {alloc,_,{gc_bif,_,{f,F}}} -> F =:= Lbl;
- {alloc,_,{put_map,_,{f,F}}} -> F =:= Lbl;
- {get_map_elements,{f,F}} -> F =:= Lbl;
- {'catch',{f,F}} -> F =:= Lbl;
- {alloc,_,_} -> false;
- {put_tuple,_} -> false;
- {get_tuple_element,_} -> false;
- {set_tuple_element,_} -> false;
- {line,_} -> false;
- _ when is_atom(Info) -> false
- end.
-
%% remove_unused_labels(Instructions0) -> Instructions
%% Remove all unused labels. Also remove unreachable
%% instructions following labels that are removed.
+-spec remove_unused_labels([instruction()]) -> [instruction()].
+
remove_unused_labels(Is) ->
Used0 = initial_labels(Is),
Used = foldl(fun ulbl/2, Used0, Is),
diff --git a/lib/compiler/src/beam_listing.erl b/lib/compiler/src/beam_listing.erl
index fd5c0a042b..94b47cf568 100644
--- a/lib/compiler/src/beam_listing.erl
+++ b/lib/compiler/src/beam_listing.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
@@ -21,14 +21,24 @@
-export([module/2]).
+-include("core_parse.hrl").
+-include("v3_kernel.hrl").
-include("v3_life.hrl").
-import(lists, [foreach/2]).
-module(File, Core) when element(1, Core) == c_module ->
+-type code() :: cerl:c_module()
+ | beam_utils:module_code()
+ | #k_mdef{}
+ | {module(),_,_,_} %v3_life
+ | [_]. %form-based format
+
+-spec module(file:io_device(), code()) -> 'ok'.
+
+module(File, #c_module{}=Core) ->
%% This is a core module.
io:put_chars(File, core_pp:format(Core));
-module(File, Kern) when element(1, Kern) == k_mdef ->
+module(File, #k_mdef{}=Kern) ->
%% This is a kernel module.
io:put_chars(File, v3_kernel_pp:format(Kern));
%%io:put_chars(File, io_lib:format("~p~n", [Kern]));
@@ -49,10 +59,6 @@ module(Stream, {Mod,Exp,Attr,Code,NumLabels}) ->
[Name, Arity, Entry]),
io:put_chars(Stream, format_asm(Asm))
end, Code);
-module(Stream, {Mod,Exp,Inter}) ->
- %% Other kinds of intermediate formats.
- io:fwrite(Stream, "~w.~n~p.~n", [Mod,Exp]),
- foreach(fun (F) -> io:format(Stream, "~p.\n", [F]) end, Inter);
module(Stream, [_|_]=Fs) ->
%% Form-based abstract format.
foreach(fun (F) -> io:format(Stream, "~p.\n", [F]) end, Fs).
diff --git a/lib/compiler/src/beam_peep.erl b/lib/compiler/src/beam_peep.erl
index 17fd2e502a..6df5c02334 100644
--- a/lib/compiler/src/beam_peep.erl
+++ b/lib/compiler/src/beam_peep.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,6 +24,9 @@
-import(lists, [reverse/1,member/2]).
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
module({Mod,Exp,Attr,Fs0,_}, _Opts) ->
%% First coalesce adjacent labels.
{Fs1,Lc} = beam_clean:clean_labels(Fs0),
@@ -65,18 +68,6 @@ function({function,Name,Arity,CLabel,Is0}) ->
%% InEncoding =:= latin1, OutEncoding =:= unicode;
%% InEncoding =:= latin1, OutEncoding =:= utf8 ->
%%
-%% (2) A select_val/4 instruction that only verifies that
-%% its argument is either 'true' or 'false' can be
-%% be replaced with an is_boolean/2 instruction. That is:
-%%
-%% select_val Reg Fail [ true Next false Next ]
-%% Next: ...
-%%
-%% can be rewritten to
-%%
-%% is_boolean Fail Reg
-%% Next: ...
-%%
peep(Is) ->
peep(Is, gb_sets:empty(), []).
@@ -95,12 +86,19 @@ peep([{gc_bif,_,_,_,_,Dst}=I|Is], SeenTests0, Acc) ->
%% Kill all remembered tests that depend on the destination register.
SeenTests = kill_seen(Dst, SeenTests0),
peep(Is, SeenTests, [I|Acc]);
-peep([{test,is_boolean,{f,Fail},Ops}|_]=Is, SeenTests,
- [{test,is_atom,{f,Fail},Ops}|Acc]) ->
- %% The previous is_atom/2 test (with the same failure label) is redundant.
- %% (If is_boolean(Src) is true, is_atom(Src) is also true, so it is
- %% OK to still remember that we have seen is_atom/1.)
- peep(Is, SeenTests, Acc);
+peep([{jump,{f,L}},{label,L}=I|Is], _, Acc) ->
+ %% Sometimes beam_jump has missed this optimization.
+ peep(Is, gb_sets:empty(), [I|Acc]);
+peep([{select,Op,R,F,Vls0}|Is], _, Acc) ->
+ case prune_redundant_values(Vls0, F) of
+ [] ->
+ %% No values left. Must convert to plain jump.
+ I = {jump,F},
+ peep(Is, gb_sets:empty(), [I|Acc]);
+ [_|_]=Vls ->
+ I = {select,Op,R,F,Vls},
+ peep(Is, gb_sets:empty(), [I|Acc])
+ end;
peep([{test,Op,_,Ops}=I|Is], SeenTests0, Acc) ->
case beam_utils:is_pure_test(I) of
false ->
@@ -121,16 +119,6 @@ peep([{test,Op,_,Ops}=I|Is], SeenTests0, Acc) ->
peep(Is, SeenTests, [I|Acc])
end
end;
-peep([{select,select_val,Src,Fail,
- [{atom,false},{f,L},{atom,true},{f,L}]}|
- [{label,L}|_]=Is], SeenTests, Acc) ->
- I = {test,is_boolean,Fail,[Src]},
- peep([I|Is], SeenTests, Acc);
-peep([{select,select_val,Src,Fail,
- [{atom,true},{f,L},{atom,false},{f,L}]}|
- [{label,L}|_]=Is], SeenTests, Acc) ->
- I = {test,is_boolean,Fail,[Src]},
- peep([I|Is], SeenTests, Acc);
peep([I|Is], _, Acc) ->
%% An unknown instruction. Throw away all information we
%% have collected about test instructions.
@@ -155,3 +143,9 @@ kill_seen_1([{_,Ops}=Test|T], Dst) ->
false -> [Test|kill_seen_1(T, Dst)]
end;
kill_seen_1([], _) -> [].
+
+prune_redundant_values([_Val,F|Vls], F) ->
+ prune_redundant_values(Vls, F);
+prune_redundant_values([Val,Lbl|Vls], F) ->
+ [Val,Lbl|prune_redundant_values(Vls, F)];
+prune_redundant_values([], _) -> [].
diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl
index 7276537949..1403e1e05e 100644
--- a/lib/compiler/src/beam_receive.erl
+++ b/lib/compiler/src/beam_receive.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-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.
@@ -65,6 +65,9 @@
%%% as the SomeUniqInteger.
%%%
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
Fs = [function(F) || F <- Fs0],
Code = {Mod,Exp,Attr,Fs,Lc},
@@ -177,7 +180,8 @@ opt_recv([I|Is], D, R0, L0, Acc) ->
no;
false ->
opt_recv(Is, D, R, L, [I|Acc])
- end.
+ end;
+opt_recv([], _, _, _, _) -> no.
opt_update_regs({block,Bl}, R, L) ->
{opt_update_regs_bl(Bl, R),L};
diff --git a/lib/compiler/src/beam_record.erl b/lib/compiler/src/beam_record.erl
new file mode 100644
index 0000000000..419089b1bc
--- /dev/null
+++ b/lib/compiler/src/beam_record.erl
@@ -0,0 +1,106 @@
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2014-2017. 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%
+%%
+%% File: beam_record.erl
+%% Author: Björn-Egil Dahlberg
+%% Created: 2014-09-03
+%%
+
+-module(beam_record).
+-export([module/2]).
+
+%% Rewrite the instruction stream on tagged tuple tests.
+%% Tagged tuples means a tuple of any arity with an atom as its first element.
+%% Typically records, ok-tuples and error-tuples.
+%%
+%% from:
+%% ...
+%% {test,is_tuple,Fail,[Src]}.
+%% {test,test_arity,Fail,[Src,Sz]}.
+%% ...
+%% {get_tuple_element,Src,0,Dst}.
+%% ...
+%% {test,is_eq_exact,Fail,[Dst,Atom]}.
+%% ...
+%% to:
+%% ...
+%% {test,is_tagged_tuple,Fail,[Src,Sz,Atom]}.
+%% ...
+
+
+-import(lists, [reverse/1]).
+
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
+module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
+ Fs = [function(F) || F <- Fs0],
+ {ok,{Mod,Exp,Attr,Fs,Lc}}.
+
+function({function,Name,Arity,CLabel,Is}) ->
+ try
+ Idx = beam_utils:index_labels(Is),
+ {function,Name,Arity,CLabel,rewrite(Is,Idx)}
+ catch
+ Class:Error ->
+ Stack = erlang:get_stacktrace(),
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+rewrite(Is,Idx) ->
+ rewrite(Is,Idx,[]).
+
+rewrite([{test,is_tuple,Fail,[Src]}=I1,
+ {test,test_arity,Fail,[Src,N]}=I2|Is],Idx,Acc) ->
+ case is_tagged_tuple(Is,Fail,Src,Idx) of
+ no ->
+ rewrite(Is,Idx,[I2,I1|Acc]);
+ {Atom,[{block,[]}|Is1]} ->
+ rewrite(Is1,Idx,[{test,is_tagged_tuple,Fail,[Src,N,Atom]}|Acc]);
+ {Atom,Is1} ->
+ rewrite(Is1,Idx,[{test,is_tagged_tuple,Fail,[Src,N,Atom]}|Acc])
+ end;
+rewrite([I|Is],Idx,Acc) ->
+ rewrite(Is,Idx,[I|Acc]);
+rewrite([],_,Acc) -> reverse(Acc).
+
+is_tagged_tuple([{block,[{set,[Dst],[Src],{get_tuple_element,0}}=B|Bs]},
+ {test,is_eq_exact,Fail,[Dst,{atom,_}=Atom]}|Is],Fail,Src,Idx) ->
+
+ %% if Dst is killed in the instruction stream and at fail label,
+ %% we can safely remove get_tuple_element.
+ %%
+ %% if Dst is not killed in the stream, we cannot remove get_tuple_element
+ %% since it is referenced.
+
+ case is_killed(Dst,Is,Fail,Idx) of
+ true -> {Atom,[{block,Bs}|Is]};
+ false -> {Atom,[{block,[B|Bs]}|Is]}
+ end;
+is_tagged_tuple([{block,[{set,_,_,_}=B|Bs]},
+ {test,is_eq_exact,_,_}=I|Is],Fail,Src,Idx) ->
+ case is_tagged_tuple([{block,Bs},I|Is],Fail,Src,Idx) of
+ {Atom,[{block,Bsr}|Isr]} -> {Atom,[{block,[B|Bsr]}|Isr]};
+ no -> no
+ end;
+is_tagged_tuple(_Is,_Fail,_Src,_Idx) ->
+ no.
+
+is_killed(Dst,Is,{_,Lbl},Idx) ->
+ beam_utils:is_killed(Dst,Is,Idx) andalso
+ beam_utils:is_killed_at(Dst,Lbl,Idx).
diff --git a/lib/compiler/src/beam_reorder.erl b/lib/compiler/src/beam_reorder.erl
new file mode 100644
index 0000000000..910b7f6b0a
--- /dev/null
+++ b/lib/compiler/src/beam_reorder.erl
@@ -0,0 +1,151 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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(beam_reorder).
+
+-export([module/2]).
+-import(lists, [member/2,reverse/1]).
+
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
+module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
+ Fs = [function(F) || F <- Fs0],
+ {ok,{Mod,Exp,Attr,Fs,Lc}}.
+
+function({function,Name,Arity,CLabel,Is0}) ->
+ try
+ Is = reorder(Is0),
+ {function,Name,Arity,CLabel,Is}
+ catch
+ Class:Error ->
+ Stack = erlang:get_stacktrace(),
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+%% reorder(Instructions0) -> Instructions
+%% Reorder instructions before the beam_block pass, because reordering
+%% will be more cumbersome when the blocks are in place.
+%%
+%% Execution of get_tuple_element instructions can be delayed until
+%% they are actually needed. Consider the sequence:
+%%
+%% get_tuple_element Tuple Pos Dst
+%% test Test Fail Operands
+%%
+%% If Dst is killed at label Fail (and not referenced in Operands),
+%% we can can swap the instructions:
+%%
+%% test Test Fail Operands
+%% get_tuple_element Tuple Pos Dst
+%%
+%% That can be beneficial in two ways: Firstly, if the branch is taken
+%% we have avoided execution of the get_tuple_element instruction.
+%% Secondly, even if the branch is not taken, subsequent optimization
+%% (opt_blocks/1) may be able to change Dst to the final destination
+%% register and eliminate a 'move' instruction.
+
+reorder(Is) ->
+ D = beam_utils:index_labels(Is),
+ reorder_1(Is, D, []).
+
+reorder_1([{Op,_,_}=TryCatch|[I|Is]=Is0], D, Acc)
+ when Op =:= 'catch'; Op =:= 'try' ->
+ %% Don't allow 'try' or 'catch' instructions to split blocks if
+ %% it can be avoided.
+ case is_safe(I) of
+ false ->
+ reorder_1(Is0, D, [TryCatch|Acc]);
+ true ->
+ reorder_1([TryCatch|Is], D, [I|Acc])
+ end;
+reorder_1([{label,L}=I|_], D, Acc) ->
+ Is = beam_utils:code_at(L, D),
+ reorder_1(Is, D, [I|Acc]);
+reorder_1([{test,is_nonempty_list,_,_}=I|Is], D, Acc) ->
+ %% The run-time system may combine the is_nonempty_list test with
+ %% the following get_list instruction.
+ reorder_1(Is, D, [I|Acc]);
+reorder_1([{test,_,_,_}=I,
+ {select,_,_,_,_}=S|Is], D, Acc) ->
+ %% There is nothing to gain by inserting a get_tuple_element
+ %% instruction between the test instruction and the select
+ %% instruction.
+ reorder_1(Is, D, [S,I|Acc]);
+reorder_1([{test,_,{f,_},[Src|_]}=I|Is], D,
+ [{get_tuple_element,Src,_,_}|_]=Acc) ->
+ %% We want to avoid code that can confuse beam_validator such as:
+ %% is_tuple Fail Src
+ %% test_arity Fail Src Arity
+ %% is_map Fail Src
+ %% get_tuple_element Src Pos Dst
+ %% Therefore, don't reorder the instructions in such cases.
+ reorder_1(Is, D, [I|Acc]);
+reorder_1([{test,_,{f,L},Ss}=I|Is0], D0,
+ [{get_tuple_element,_,_,El}=G|Acc0]=Acc) ->
+ case member(El, Ss) of
+ true ->
+ reorder_1(Is0, D0, [I|Acc]);
+ false ->
+ case beam_utils:is_killed_at(El, L, D0) of
+ true ->
+ Is = [I,G|Is0],
+ reorder_1(Is, D0, Acc0);
+ false ->
+ case beam_utils:is_killed(El, Is0, D0) of
+ true ->
+ Code0 = beam_utils:code_at(L, D0),
+ Code = [G|Code0],
+ D = beam_utils:index_label(L, Code, D0),
+ Is = [I|Is0],
+ reorder_1(Is, D, Acc0);
+ false ->
+ reorder_1(Is0, D0, [I|Acc])
+ end
+ end
+ end;
+reorder_1([{allocate_zero,N,Live}=I0|Is], D,
+ [{get_tuple_element,{x,Tup},_,{x,Dst}}=G|Acc]=Acc0) ->
+ case Tup < Dst andalso Dst+1 =:= Live of
+ true ->
+ %% Move allocation instruction upwards past
+ %% get_tuple_element instructions to create more
+ %% opportunities for moving get_tuple_element
+ %% instructions.
+ I = {allocate_zero,N,Dst},
+ reorder_1([I,G|Is], D, Acc);
+ false ->
+ reorder_1(Is, D, [I0|Acc0])
+ end;
+reorder_1([I|Is], D, Acc) ->
+ reorder_1(Is, D, [I|Acc]);
+reorder_1([], _, Acc) -> reverse(Acc).
+
+%% is_safe(Instruction) -> true|false
+%% Test whether an instruction is safe (cannot cause an exception).
+
+is_safe({kill,_}) -> true;
+is_safe({move,_,_}) -> true;
+is_safe({put,_}) -> true;
+is_safe({put_list,_,_,_}) -> true;
+is_safe({put_tuple,_,_}) -> true;
+is_safe({test_heap,_,_}) -> true;
+is_safe(_) -> false.
diff --git a/lib/compiler/src/beam_split.erl b/lib/compiler/src/beam_split.erl
index 3be9311080..d041f18806 100644
--- a/lib/compiler/src/beam_split.erl
+++ b/lib/compiler/src/beam_split.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,6 +23,9 @@
-import(lists, [reverse/1]).
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
Fs = [split_blocks(F) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
@@ -47,6 +50,8 @@ split_block([{set,[R],[_,_,_]=As,{bif,is_record,{f,Lbl}}}|Is], Bl, Acc) ->
split_block(Is, [], [{bif,is_record,{f,Lbl},As,R}|make_block(Bl, Acc)]);
split_block([{set,[R],As,{bif,N,{f,Lbl}=Fail}}|Is], Bl, Acc) when Lbl =/= 0 ->
split_block(Is, [], [{bif,N,Fail,As,R}|make_block(Bl, Acc)]);
+split_block([{set,[R],As,{bif,raise,{f,_}=Fail}}|Is], Bl, Acc) ->
+ split_block(Is, [], [{bif,raise,Fail,As,R}|make_block(Bl, Acc)]);
split_block([{set,[R],As,{alloc,Live,{gc_bif,N,{f,Lbl}=Fail}}}|Is], Bl, Acc)
when Lbl =/= 0 ->
split_block(Is, [], [{gc_bif,N,Fail,Live,As,R}|make_block(Bl, Acc)]);
@@ -54,11 +59,8 @@ split_block([{set,[D],[S|Puts],{alloc,R,{put_map,Op,{f,Lbl}=Fail}}}|Is],
Bl, Acc) when Lbl =/= 0 ->
split_block(Is, [], [{put_map,Fail,Op,S,D,R,{list,Puts}}|
make_block(Bl, Acc)]);
-split_block([{set,Ds,[S|Ss],{get_map_elements,Fail}}|Is], Bl, Acc) ->
- Gets = beam_utils:join_even(Ss,Ds),
- split_block(Is, [], [{get_map_elements,Fail,S,{list,Gets}}|make_block(Bl, Acc)]);
-split_block([{set,[R],[],{'catch',L}}|Is], Bl, Acc) ->
- split_block(Is, [], [{'catch',R,L}|make_block(Bl, Acc)]);
+split_block([{set,[R],[],{try_catch,Op,L}}|Is], Bl, Acc) ->
+ split_block(Is, [], [{Op,R,L}|make_block(Bl, Acc)]);
split_block([{set,[],[],{line,_}=Line}|Is], Bl, Acc) ->
split_block(Is, [], [Line|make_block(Bl, Acc)]);
split_block([I|Is], Bl, Acc) ->
diff --git a/lib/compiler/src/beam_trim.erl b/lib/compiler/src/beam_trim.erl
index 509e013b62..4da0985085 100644
--- a/lib/compiler/src/beam_trim.erl
+++ b/lib/compiler/src/beam_trim.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
@@ -24,10 +24,13 @@
-import(lists, [reverse/1,reverse/2,splitwith/2,sort/1]).
-record(st,
- {safe, %Safe labels.
- lbl %Code at each label.
+ {safe :: gb_sets:set(beam_asm:label()), %Safe labels.
+ lbl :: beam_utils:code_index() %Code at each label.
}).
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
+
module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
Fs = [function(F) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
@@ -230,7 +233,7 @@ safe_labels([], Acc) -> gb_sets:from_list(Acc).
frame_layout(Is, Kills, #st{safe=Safe,lbl=D}) ->
N = frame_size(Is, Safe),
- IsKilled = fun(R) -> beam_utils:is_killed(R, Is, D) end,
+ IsKilled = fun(R) -> beam_utils:is_not_used(R, Is, D) end,
{N,frame_layout_1(Kills, 0, N, IsKilled, [])}.
frame_layout_1([{kill,{y,Y}}=I|Ks], Y, N, IsKilled, Acc) ->
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl
index 5298589f83..3d842a6fd3 100644
--- a/lib/compiler/src/beam_type.erl
+++ b/lib/compiler/src/beam_type.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,7 +23,13 @@
-export([module/2]).
--import(lists, [foldl/3,reverse/1,filter/2]).
+-import(lists, [filter/2,foldl/3,keyfind/3,member/2,
+ reverse/1,reverse/2,sort/1]).
+
+-define(UNICODE_INT, {integer,{0,16#10FFFF}}).
+
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
Fs = [function(F) || F <- Fs0],
@@ -33,7 +39,8 @@ function({function,Name,Arity,CLabel,Asm0}) ->
try
Asm1 = beam_utils:live_opt(Asm0),
Asm2 = opt(Asm1, [], tdb_new()),
- Asm = beam_utils:delete_live_annos(Asm2),
+ Asm3 = beam_utils:live_opt(Asm2),
+ Asm = beam_utils:delete_live_annos(Asm3),
{function,Name,Arity,CLabel,Asm}
catch
Class:Error ->
@@ -92,8 +99,19 @@ simplify_basic_1([{set,[D],[TupleReg],{get_tuple_element,0}}=I|Is0], Ts0, Acc) -
Ts = update(I, Ts0),
simplify_basic_1(Is0, Ts, [I|Acc])
end;
-simplify_basic_1([{set,_,_,{'catch',_}}=I|Is], _Ts, Acc) ->
+simplify_basic_1([{set,_,_,{try_catch,_,_}}=I|Is], _Ts, Acc) ->
simplify_basic_1(Is, tdb_new(), [I|Acc]);
+simplify_basic_1([{test,is_atom,_,[R]}=I|Is], Ts, Acc) ->
+ case tdb_find(R, Ts) of
+ boolean -> simplify_basic_1(Is, Ts, Acc);
+ _ -> simplify_basic_1(Is, Ts, [I|Acc])
+ end;
+simplify_basic_1([{test,is_integer,_,[R]}=I|Is], Ts, Acc) ->
+ case tdb_find(R, Ts) of
+ integer -> simplify_basic_1(Is, Ts, Acc);
+ {integer,_} -> simplify_basic_1(Is, Ts, Acc);
+ _ -> simplify_basic_1(Is, Ts, [I|Acc])
+ end;
simplify_basic_1([{test,is_tuple,_,[R]}=I|Is], Ts, Acc) ->
case tdb_find(R, Ts) of
{tuple,_,_} -> simplify_basic_1(Is, Ts, Acc);
@@ -137,6 +155,16 @@ simplify_basic_1([{test,is_record,_,[R,{atom,_}=Tag,{integer,Arity}]}=I|Is], Ts0
Ts = update(I, Ts0),
simplify_basic_1(Is, Ts, [I|Acc])
end;
+simplify_basic_1([{select,select_val,Reg,_,_}=I0|Is], Ts, Acc) ->
+ I = case tdb_find(Reg, Ts) of
+ {integer,Range} ->
+ simplify_select_val_int(I0, Range);
+ boolean ->
+ simplify_select_val_bool(I0);
+ _ ->
+ I0
+ end,
+ simplify_basic_1(Is, tdb_new(), [I|Acc]);
simplify_basic_1([I|Is], Ts0, Acc) ->
Ts = update(I, Ts0),
simplify_basic_1(Is, Ts, [I|Acc]);
@@ -144,6 +172,32 @@ simplify_basic_1([], Ts, Acc) ->
Is = reverse(Acc),
{Is,Ts}.
+simplify_select_val_int({select,select_val,R,_,L0}=I, {Min,Max}) ->
+ Vs = sort([V || {integer,V} <- L0]),
+ case eq_ranges(Vs, Min, Max) of
+ false -> I;
+ true -> simplify_select_val_1(L0, {integer,Max}, R, [])
+ end.
+
+simplify_select_val_bool({select,select_val,R,_,L}=I) ->
+ Vs = sort([V || {atom,V} <- L]),
+ case Vs of
+ [false,true] ->
+ simplify_select_val_1(L, {atom,false}, R, []);
+ _ ->
+ I
+ end.
+
+simplify_select_val_1([Val,F|T], Val, R, Acc) ->
+ L = reverse(Acc, T),
+ {select,select_val,R,F,L};
+simplify_select_val_1([V,F|T], Val, R, Acc) ->
+ simplify_select_val_1(T, Val, R, [F,V|Acc]).
+
+eq_ranges([H], H, H) -> true;
+eq_ranges([H|T], H, Max) -> eq_ranges(T, H+1, Max);
+eq_ranges(_, _, _) -> false.
+
%% simplify_float([Instruction], TypeDatabase) ->
%% {[Instruction],TypeDatabase'} | not_possible
%% Simplify floating point operations in blocks.
@@ -199,7 +253,7 @@ simplify_float_1([{set,[D0],[A0,B0],{alloc,_,{gc_bif,Op0,{f,0}}}}=I|Is]=Is0,
Ts = tdb_update([{D0,float}], Ts0),
simplify_float_1(Is, Ts, Rs, Acc)
end;
-simplify_float_1([{set,_,_,{'catch',_}}=I|Is]=Is0, _Ts, Rs0, Acc0) ->
+simplify_float_1([{set,_,_,{try_catch,_,_}}=I|Is]=Is0, _Ts, Rs0, Acc0) ->
Acc = flush_all(Rs0, Is0, Acc0),
simplify_float_1(Is, tdb_new(), Rs0, [I|Acc]);
simplify_float_1([{set,_,_,{line,_}}=I|Is], Ts, Rs, Acc) ->
@@ -311,7 +365,7 @@ flt_need_heap_2({set,_,_,{get_tuple_element,_}}, H, Fl) ->
{[],H,Fl};
flt_need_heap_2({set,_,_,get_list}, H, Fl) ->
{[],H,Fl};
-flt_need_heap_2({set,_,_,{'catch',_}}, H, Fl) ->
+flt_need_heap_2({set,_,_,{try_catch,_,_}}, H, Fl) ->
{[],H,Fl};
%% All other instructions should cause the insertion of an allocation
%% instruction if needed.
@@ -382,6 +436,17 @@ update({set,[D],[{integer,I},Reg],{bif,element,_}}, Ts0) ->
tdb_update([{Reg,{tuple,I,[]}},{D,kill}], Ts0);
update({set,[D],[_Index,Reg],{bif,element,_}}, Ts0) ->
tdb_update([{Reg,{tuple,0,[]}},{D,kill}], Ts0);
+update({set,[D],Args,{bif,N,_}}, Ts0) ->
+ Ar = length(Args),
+ BoolOp = erl_internal:new_type_test(N, Ar) orelse
+ erl_internal:comp_op(N, Ar) orelse
+ erl_internal:bool_op(N, Ar),
+ case BoolOp of
+ true ->
+ tdb_update([{D,boolean}], Ts0);
+ false ->
+ tdb_update([{D,kill}], Ts0)
+ end;
update({set,[D],[S],{get_tuple_element,0}}, Ts) ->
tdb_update([{D,{tuple_element,S,0}}], Ts);
update({set,[D],[S],{alloc,_,{gc_bif,float,{f,0}}}}, Ts0) ->
@@ -390,6 +455,13 @@ update({set,[D],[S],{alloc,_,{gc_bif,float,{f,0}}}}, Ts0) ->
true -> tdb_update([{D,float}], Ts0);
false -> Ts0
end;
+update({set,[D],[S1,S2],{alloc,_,{gc_bif,'band',{f,0}}}}, Ts) ->
+ case keyfind(integer, 1, [S1,S2]) of
+ {integer,N} ->
+ update_band(N, D, Ts);
+ false ->
+ tdb_update([{D,integer}], Ts)
+ end;
update({set,[D],[S1,S2],{alloc,_,{gc_bif,'/',{f,0}}}}, Ts0) ->
%% Make sure we reject non-numeric literals.
case possibly_numeric(S1) andalso possibly_numeric(S2) of
@@ -397,15 +469,17 @@ update({set,[D],[S1,S2],{alloc,_,{gc_bif,'/',{f,0}}}}, Ts0) ->
false -> Ts0
end;
update({set,[D],[S1,S2],{alloc,_,{gc_bif,Op,{f,0}}}}, Ts0) ->
- case arith_op(Op) of
- no ->
- tdb_update([{D,kill}], Ts0);
- {yes,_} ->
+ case op_type(Op) of
+ integer ->
+ tdb_update([{D,integer}], Ts0);
+ {float,_} ->
case {tdb_find(S1, Ts0),tdb_find(S2, Ts0)} of
{float,_} -> tdb_update([{D,float}], Ts0);
{_,float} -> tdb_update([{D,float}], Ts0);
{_,_} -> tdb_update([{D,kill}], Ts0)
- end
+ end;
+ unknown ->
+ tdb_update([{D,kill}], Ts0)
end;
update({set,[],_Src,_Op}, Ts0) -> Ts0;
update({set,[D],_Src,_Op}, Ts0) ->
@@ -422,6 +496,10 @@ update({test,test_arity,_Fail,[Src,Arity]}, Ts0) ->
tdb_update([{Src,{tuple,Arity,[]}}], Ts0);
update({test,is_map,_Fail,[Src]}, Ts0) ->
tdb_update([{Src,map}], Ts0);
+update({get_map_elements,_,Src,{list,Elems0}}, Ts0) ->
+ {_Ss,Ds} = beam_utils:split_even(Elems0),
+ Elems = [{Dst,kill} || Dst <- Ds],
+ tdb_update([{Src,map}|Elems], Ts0);
update({test,is_nonempty_list,_Fail,[Src]}, Ts0) ->
tdb_update([{Src,nonempty_list}], Ts0);
update({test,is_eq_exact,_,[Reg,{atom,_}=Atom]}, Ts) ->
@@ -435,28 +513,104 @@ update({test,is_eq_exact,_,[Reg,{atom,_}=Atom]}, Ts) ->
end;
update({test,is_record,_Fail,[Src,Tag,{integer,Arity}]}, Ts) ->
tdb_update([{Src,{tuple,Arity,[Tag]}}], Ts);
+
+%% Binary matching
+
+update({test,bs_get_integer2,_,_,Args,Dst}, Ts) ->
+ tdb_update([{Dst,get_bs_integer_type(Args)}], Ts);
+update({test,bs_get_utf8,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,?UNICODE_INT}], Ts);
+update({test,bs_get_utf16,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,?UNICODE_INT}], Ts);
+update({test,bs_get_utf32,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,?UNICODE_INT}], Ts);
+update({bs_init,_,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,kill}], Ts);
+update({bs_put,_,_,_}, Ts) ->
+ Ts;
+update({bs_save2,_,_}, Ts) ->
+ Ts;
+update({bs_restore2,_,_}, Ts) ->
+ Ts;
+update({bs_context_to_binary,Dst}, Ts) ->
+ tdb_update([{Dst,kill}], Ts);
+update({test,bs_start_match2,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,kill}], Ts);
+update({test,bs_get_binary2,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,kill}], Ts);
+update({test,bs_get_float2,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,float}], Ts);
+
update({test,_Test,_Fail,_Other}, Ts) ->
Ts;
+
+%% Calls
+
update({call_ext,Ar,{extfunc,math,Math,Ar}}, Ts) ->
case is_math_bif(Math, Ar) of
true -> tdb_update([{{x,0},float}], Ts);
false -> tdb_kill_xregs(Ts)
end;
update({call_ext,3,{extfunc,erlang,setelement,3}}, Ts0) ->
- Op = case tdb_find({x,1}, Ts0) of
- error -> kill;
- Info -> Info
- end,
- Ts1 = tdb_kill_xregs(Ts0),
- tdb_update([{{x,0},Op}], Ts1);
+ Ts = tdb_kill_xregs(Ts0),
+ case tdb_find({x,1}, Ts0) of
+ {tuple,Sz,_}=T0 ->
+ T = case tdb_find({x,0}, Ts0) of
+ {integer,{I,I}} when I > 1 ->
+ %% First element is not changed. The result
+ %% will have the same type.
+ T0;
+ _ ->
+ %% Position is 1 or unknown. May change the
+ %% first element of the tuple.
+ {tuple,Sz,[]}
+ end,
+ tdb_update([{{x,0},T}], Ts);
+ _ ->
+ Ts
+ end;
update({call,_Arity,_Func}, Ts) -> tdb_kill_xregs(Ts);
update({call_ext,_Arity,_Func}, Ts) -> tdb_kill_xregs(Ts);
update({make_fun2,_,_,_,_}, Ts) -> tdb_kill_xregs(Ts);
+update({call_fun, _}, Ts) -> tdb_kill_xregs(Ts);
+update({apply, _}, Ts) -> tdb_kill_xregs(Ts);
+
update({line,_}, Ts) -> Ts;
%% The instruction is unknown. Kill all information.
update(_I, _Ts) -> tdb_new().
+update_band(N, Reg, Ts) ->
+ Type = update_band_1(N, 0),
+ tdb_update([{Reg,Type}], Ts).
+
+update_band_1(N, Bits) when Bits < 64 ->
+ case 1 bsl Bits of
+ P when P =:= N + 1 ->
+ {integer,{0,N}};
+ P when P > N + 1 ->
+ integer;
+ _ ->
+ update_band_1(N, Bits+1)
+ end;
+update_band_1(_, _) ->
+ %% Negative or large positive number. Give up.
+ integer.
+
+get_bs_integer_type([_,{integer,N},U,{field_flags,Fl}])
+ when N*U < 64 ->
+ NumBits = N*U,
+ case member(unsigned, Fl) of
+ true ->
+ {integer,{0,(1 bsl NumBits)-1}};
+ false ->
+ %% Signed integer. Don't bother.
+ integer
+ end;
+get_bs_integer_type(_) ->
+ %% Avoid creating ranges with a huge upper limit.
+ integer.
+
is_math_bif(cos, 1) -> true;
is_math_bif(cosh, 1) -> true;
is_math_bif(sin, 1) -> true;
@@ -478,6 +632,9 @@ is_math_bif(log10, 1) -> true;
is_math_bif(sqrt, 1) -> true;
is_math_bif(atan2, 2) -> true;
is_math_bif(pow, 2) -> true;
+is_math_bif(ceil, 1) -> true;
+is_math_bif(floor, 1) -> true;
+is_math_bif(fmod, 2) -> true;
is_math_bif(pi, 0) -> true;
is_math_bif(_, _) -> false.
@@ -545,12 +702,26 @@ load_reg(V, Ts, Rs0, Is0) ->
{Rs,Is}
end.
-arith_op('+') -> {yes,fadd};
-arith_op('-') -> {yes,fsub};
-arith_op('*') -> {yes,fmul};
-arith_op('/') -> {yes,fdiv};
-arith_op(_) -> no.
+arith_op(Op) ->
+ case op_type(Op) of
+ {float,Instr} -> {yes,Instr};
+ _ -> no
+ end.
+op_type('+') -> {float,fadd};
+op_type('-') -> {float,fsub};
+op_type('*') -> {float,fmul};
+%% '/' and 'band' are specially handled.
+op_type('bor') -> integer;
+op_type('bxor') -> integer;
+op_type('bsl') -> integer;
+op_type('bsr') -> integer;
+op_type('div') -> integer;
+op_type(_) -> unknown.
+
+flush(Rs, [{set,[_],[_,_,_],{bif,is_record,_}}|_]=Is0, Acc0) ->
+ Acc = flush_all(Rs, Is0, Acc0),
+ {[],Acc};
flush(Rs, [{set,[_],[],{put_tuple,_}}|_]=Is0, Acc0) ->
Acc = flush_all(Rs, Is0, Acc0),
{[],Acc};
@@ -618,7 +789,6 @@ checkerror(Is) ->
checkerror_1(Is, Is).
checkerror_1([{set,[],[],fcheckerror}|_], OrigIs) -> OrigIs;
-checkerror_1([{set,[],[],fclearerror}|_], OrigIs) -> OrigIs;
checkerror_1([{set,_,_,{bif,fadd,_}}|_], OrigIs) -> checkerror_2(OrigIs);
checkerror_1([{set,_,_,{bif,fsub,_}}|_], OrigIs) -> checkerror_2(OrigIs);
checkerror_1([{set,_,_,{bif,fmul,_}}|_], OrigIs) -> checkerror_2(OrigIs);
@@ -635,11 +805,14 @@ checkerror_2(OrigIs) -> [{set,[],[],fcheckerror}|OrigIs].
%%%
%%% {tuple,Size,First} means that the corresponding register contains a
%%% tuple with *at least* Size elements. An tuple with unknown
-%%% size is represented as {tuple,0}. First is either [] (meaning that
+%%% size is represented as {tuple,0,[]}. First is either [] (meaning that
%%% the tuple's first element is unknown) or [FirstElement] (the contents
%%% of the first element).
%%%
%%% 'float' means that the register contains a float.
+%%%
+%%% 'integer' or {integer,{Min,Max}} that the register contains an
+%%% integer.
%% tdb_new() -> EmptyDataBase
%% Creates a new, empty type database.
@@ -669,21 +842,45 @@ tdb_copy({Tag,_}=S, D, Ts) when Tag =:= x; Tag =:= y ->
error -> orddict:erase(D, Ts);
Type -> orddict:store(D, Type, Ts)
end;
-tdb_copy(Literal, D, Ts) -> orddict:store(D, Literal, Ts).
+tdb_copy(Literal, D, Ts) ->
+ Type = case Literal of
+ {atom,_} -> Literal;
+ {float,_} -> float;
+ {integer,Int} -> {integer,{Int,Int}};
+ {literal,[_|_]} -> nonempty_list;
+ {literal,#{}} -> map;
+ {literal,Tuple} when tuple_size(Tuple) >= 1 ->
+ Lit = tag_literal(element(1, Tuple)),
+ {tuple,tuple_size(Tuple),[Lit]};
+ _ -> term
+ end,
+ if
+ Type =:= term ->
+ orddict:erase(D, Ts);
+ true ->
+ verify_type(Type),
+ orddict:store(D, Type, Ts)
+ end.
+
+tag_literal(A) when is_atom(A) -> {atom,A};
+tag_literal(F) when is_float(F) -> {float,F};
+tag_literal(I) when is_integer(I) -> {integer,I};
+tag_literal([]) -> nil;
+tag_literal(Lit) -> {literal,Lit}.
%% tdb_update([UpdateOp], Db) -> NewDb
%% UpdateOp = {Register,kill}|{Register,NewInfo}
%% Updates a type database. If a 'kill' operation is given, the type
%% information for that register will be removed from the database.
%% A kill operation takes precedence over other operations for the same
-%% register (i.e. [{{x,0},kill},{{x,0},{tuple,5}}] means that the
+%% register (i.e. [{{x,0},kill},{{x,0},{tuple,5,[]}}] means that the
%% the existing type information, if any, will be discarded, and the
-%% the '{tuple,5}' information ignored.
+%% the '{tuple,5,[]}' information ignored.
%%
%% If NewInfo information is given and there exists information about
%% the register, the old and new type information will be merged.
-%% For instance, {tuple,5} and {tuple,10} will be merged to produce
-%% {tuple,10}.
+%% For instance, {tuple,5,_} and {tuple,10,_} will be merged to produce
+%% {tuple,10,_}.
tdb_update(Uis0, Ts0) ->
Uis1 = filter(fun ({{x,_},_Op}) -> true;
@@ -694,7 +891,8 @@ tdb_update(Uis0, Ts0) ->
tdb_update1([{Key,kill}|Ops], [{K,_Old}|_]=Db) when Key < K ->
tdb_update1(remove_key(Key, Ops), Db);
-tdb_update1([{Key,_New}=New|Ops], [{K,_Old}|_]=Db) when Key < K ->
+tdb_update1([{Key,Type}=New|Ops], [{K,_Old}|_]=Db) when Key < K ->
+ verify_type(Type),
[New|tdb_update1(Ops, Db)];
tdb_update1([{Key,kill}|Ops], [{Key,_}|Db]) ->
tdb_update1(remove_key(Key, Ops), Db);
@@ -704,7 +902,8 @@ tdb_update1([{_,_}|_]=Ops, [Old|Db]) ->
[Old|tdb_update1(Ops, Db)];
tdb_update1([{Key,kill}|Ops], []) ->
tdb_update1(remove_key(Key, Ops), []);
-tdb_update1([{_,_}=New|Ops], []) ->
+tdb_update1([{_,Type}=New|Ops], []) ->
+ verify_type(Type),
[New|tdb_update1(Ops, [])];
tdb_update1([], Db) -> Db.
@@ -729,10 +928,21 @@ merge_type_info({tuple,Sz1,[]}, {tuple,_Sz2,First}=Tuple2) ->
merge_type_info({tuple,Sz1,First}, Tuple2);
merge_type_info({tuple,_Sz1,First}=Tuple1, {tuple,Sz2,_}) ->
merge_type_info(Tuple1, {tuple,Sz2,First});
+merge_type_info(integer, {integer,_}=Int) ->
+ Int;
+merge_type_info({integer,_}=Int, integer) ->
+ Int;
+merge_type_info({integer,{Min1,Max1}}, {integer,{Min2,Max2}}) ->
+ {integer,{max(Min1, Min2),min(Max1, Max2)}};
merge_type_info(NewType, _) ->
verify_type(NewType),
NewType.
+verify_type({atom,_}) -> ok;
+verify_type(boolean) -> ok;
+verify_type(integer) -> ok;
+verify_type({integer,{Min,Max}})
+ when is_integer(Min), is_integer(Max) -> ok;
verify_type(map) -> ok;
verify_type(nonempty_list) -> ok;
verify_type({tuple,Sz,[]}) when is_integer(Sz) -> ok;
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index 1945fadfd3..e39fbdc3b7 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
@@ -22,19 +22,37 @@
-module(beam_utils).
-export([is_killed_block/2,is_killed/3,is_killed_at/3,
- is_not_used/3,is_not_used_at/3,
+ is_not_used/3,
empty_label_index/0,index_label/3,index_labels/1,
code_at/2,bif_to_test/3,is_pure_test/1,
- live_opt/1,delete_live_annos/1,combine_heap_needs/2]).
+ live_opt/1,delete_live_annos/1,combine_heap_needs/2,
+ split_even/1]).
--export([join_even/2,split_even/1]).
+-export_type([code_index/0,module_code/0,instruction/0]).
-import(lists, [member/2,sort/1,reverse/1,splitwith/2]).
+%% instruction() describes all instructions that are used during optimzation
+%% (from beam_a to beam_z).
+-type instruction() :: atom() | tuple().
+
+-type code_index() :: gb_trees:tree(beam_asm:label(), [instruction()]).
+
+-type int_function() :: {'function',beam_asm:function_name(),arity(),
+ beam_asm:label(),[instruction()]}.
+
+-type module_code() ::
+ {module(),[_],[_],[int_function()],pos_integer()}.
+
+%% Internal types.
+-type fail() :: beam_asm:fail() | 'fail'.
+-type test() :: {'test',atom(),fail(),[beam_asm:src()]} |
+ {'test',atom(),fail(),integer(),list(),beam_asm:reg()}.
+-type result_cache() :: gb_trees:tree(beam_asm:label(), 'killed' | 'used').
+
-record(live,
- {bl, %Block check fun.
- lbl, %Label to code index.
- res}). %Result cache for each label.
+ {lbl :: code_index(), %Label to code index.
+ res :: result_cache()}). %Result cache for each label.
%% is_killed_block(Register, [Instruction]) -> true|false
@@ -46,12 +64,18 @@
%% i.e. it is OK to enter the instruction sequence with Register
%% containing garbage.
-is_killed_block(R, Is) ->
- case check_killed_block(R, Is) of
- killed -> true;
- used -> false;
- transparent -> false
- end.
+-spec is_killed_block(beam_asm:reg(), [instruction()]) -> boolean().
+
+is_killed_block({x,X}, [{set,_,_,{alloc,Live,_}}|_]) ->
+ X >= Live;
+is_killed_block(R, [{set,Ds,Ss,_Op}|Is]) ->
+ not member(R, Ss) andalso (member(R, Ds) orelse is_killed_block(R, Is));
+is_killed_block(R, [{'%live',_,Regs}|Is]) ->
+ case R of
+ {x,X} when (Regs bsr X) band 1 =:= 0 -> true;
+ _ -> is_killed_block(R, Is)
+ end;
+is_killed_block(_, []) -> false.
%% is_killed(Register, [Instruction], State) -> true|false
%% Determine whether a register is killed by the instruction sequence.
@@ -63,23 +87,25 @@ is_killed_block(R, Is) ->
%% The state (constructed by index_instructions/1) is used to allow us
%% to determine the kill state across branches.
+-spec is_killed(beam_asm:reg(), [instruction()], code_index()) -> boolean().
+
is_killed(R, Is, D) ->
- St = #live{bl=check_killed_block_fun(),lbl=D,res=gb_trees:empty()},
+ St = #live{lbl=D,res=gb_trees:empty()},
case check_liveness(R, Is, St) of
{killed,_} -> true;
- {used,_} -> false;
- {unknown,_} -> false
+ {_,_} -> false
end.
%% is_killed_at(Reg, Lbl, State) -> true|false
%% Determine whether Reg is killed at label Lbl.
+-spec is_killed_at(beam_asm:reg(), beam_asm:label(), code_index()) -> boolean().
+
is_killed_at(R, Lbl, D) when is_integer(Lbl) ->
- St0 = #live{bl=check_killed_block_fun(),lbl=D,res=gb_trees:empty()},
+ St0 = #live{lbl=D,res=gb_trees:empty()},
case check_liveness_at(R, Lbl, St0) of
{killed,_} -> true;
- {used,_} -> false;
- {unknown,_} -> false
+ {_,_} -> false
end.
%% is_not_used(Register, [Instruction], State) -> true|false
@@ -89,45 +115,38 @@ is_killed_at(R, Lbl, D) when is_integer(Lbl) ->
%% The state is used to allow us to determine the usage state
%% across branches.
+-spec is_not_used(beam_asm:reg(), [instruction()], code_index()) -> boolean().
+
is_not_used(R, Is, D) ->
- St = #live{bl=fun check_used_block/3,lbl=D,res=gb_trees:empty()},
+ St = #live{lbl=D,res=gb_trees:empty()},
case check_liveness(R, Is, St) of
- {killed,_} -> true;
{used,_} -> false;
- {unknown,_} -> false
- end.
-
-%% is_not_used(Register, [Instruction], State) -> true|false
-%% Determine whether a register is never used in the instruction sequence
-%% (it could still be referenced by an allocate instruction, meaning that
-%% it MUST be initialized, but that its value does not matter).
-%% The state is used to allow us to determine the usage state
-%% across branches.
-
-is_not_used_at(R, Lbl, D) ->
- St = #live{bl=fun check_used_block/3,lbl=D,res=gb_trees:empty()},
- case check_liveness_at(R, Lbl, St) of
- {killed,_} -> true;
- {used,_} -> false;
- {unknown,_} -> false
+ {_,_} -> true
end.
%% index_labels(FunctionIs) -> State
%% Index the instruction sequence so that we can quickly
%% look up the instruction following a specific label.
+-spec index_labels([instruction()]) -> code_index().
+
index_labels(Is) ->
index_labels_1(Is, []).
%% empty_label_index() -> State
%% Create an empty label index.
+-spec empty_label_index() -> code_index().
+
empty_label_index() ->
gb_trees:empty().
%% index_label(Label, [Instruction], State) -> State
%% Add an index for a label.
+-spec index_label(beam_asm:label(), [instruction()], code_index()) ->
+ code_index().
+
index_label(Lbl, Is0, Acc) ->
Is = drop_labels(Is0),
gb_trees:enter(Lbl, Is, Acc).
@@ -136,15 +155,16 @@ index_label(Lbl, Is0, Acc) ->
%% code_at(Label, State) -> [I].
%% Retrieve the code at the given label.
+-spec code_at(beam_asm:label(), code_index()) -> [instruction()].
+
code_at(L, Ll) ->
- case gb_trees:lookup(L, Ll) of
- {value,Code} -> Code;
- none -> none
- end.
+ gb_trees:get(L, Ll).
%% bif_to_test(Bif, [Op], Fail) -> {test,Test,Fail,[Op]}
%% Convert a BIF to a test. Fail if not possible.
+-spec bif_to_test(atom(), list(), fail()) -> test().
+
bif_to_test(is_atom, [_]=Ops, Fail) -> {test,is_atom,Fail,Ops};
bif_to_test(is_boolean, [_]=Ops, Fail) -> {test,is_boolean,Fail,Ops};
bif_to_test(is_binary, [_]=Ops, Fail) -> {test,is_binary,Fail,Ops};
@@ -164,10 +184,10 @@ bif_to_test('=<', [A,B], Fail) -> {test,is_ge,Fail,[B,A]};
bif_to_test('>', [A,B], Fail) -> {test,is_lt,Fail,[B,A]};
bif_to_test('<', [_,_]=Ops, Fail) -> {test,is_lt,Fail,Ops};
bif_to_test('>=', [_,_]=Ops, Fail) -> {test,is_ge,Fail,Ops};
-bif_to_test('==', [A,[]], Fail) -> {test,is_nil,Fail,[A]};
+bif_to_test('==', [A,nil], Fail) -> {test,is_nil,Fail,[A]};
bif_to_test('==', [_,_]=Ops, Fail) -> {test,is_eq,Fail,Ops};
bif_to_test('/=', [_,_]=Ops, Fail) -> {test,is_ne,Fail,Ops};
-bif_to_test('=:=', [A,[]], Fail) -> {test,is_nil,Fail,[A]};
+bif_to_test('=:=', [A,nil], Fail) -> {test,is_nil,Fail,[A]};
bif_to_test('=:=', [_,_]=Ops, Fail) -> {test,is_eq_exact,Fail,Ops};
bif_to_test('=/=', [_,_]=Ops, Fail) -> {test,is_ne_exact,Fail,Ops};
bif_to_test(is_record, [_,_,_]=Ops, Fail) -> {test,is_record,Fail,Ops}.
@@ -175,9 +195,11 @@ bif_to_test(is_record, [_,_,_]=Ops, Fail) -> {test,is_record,Fail,Ops}.
%% is_pure_test({test,Op,Fail,Ops}) -> true|false.
%% Return 'true' if the test instruction does not modify any
-%% registers and/or bit syntax matching state, nor modifies
-%% any bit syntax matching state.
+%% registers and/or bit syntax matching state.
%%
+
+-spec is_pure_test(test()) -> boolean().
+
is_pure_test({test,is_eq,_,[_,_]}) -> true;
is_pure_test({test,is_ne,_,[_,_]}) -> true;
is_pure_test({test,is_eq_exact,_,[_,_]}) -> true;
@@ -188,6 +210,8 @@ is_pure_test({test,is_nil,_,[_]}) -> true;
is_pure_test({test,is_nonempty_list,_,[_]}) -> true;
is_pure_test({test,test_arity,_,[_,_]}) -> true;
is_pure_test({test,has_map_fields,_,[_|_]}) -> true;
+is_pure_test({test,is_bitstr,_,[_]}) -> true;
+is_pure_test({test,is_function2,_,[_,_]}) -> true;
is_pure_test({test,Op,_,Ops}) ->
erl_internal:new_type_test(Op, length(Ops)).
@@ -198,7 +222,9 @@ is_pure_test({test,Op,_,Ops}) ->
%% whose destination is a register that will not be used.
%% Also insert {'%live',Live,Regs} annotations at the beginning
%% and end of each block.
-%%
+
+-spec live_opt([instruction()]) -> [instruction()].
+
live_opt(Is0) ->
{[{label,Fail}|_]=Bef,[Fi|Is]} =
splitwith(fun({func_info,_,_,_}) -> false;
@@ -211,7 +237,9 @@ live_opt(Is0) ->
%% delete_live_annos([Instruction]) -> [Instruction].
%% Delete all live annotations.
-%%
+
+-spec delete_live_annos([instruction()]) -> [instruction()].
+
delete_live_annos([{block,Bl0}|Is]) ->
case delete_live_annos(Bl0) of
[] -> delete_live_annos(Is);
@@ -226,6 +254,8 @@ delete_live_annos([]) -> [].
%% combine_heap_needs(HeapNeed1, HeapNeed2) -> HeapNeed
%% Combine the heap need for two allocation instructions.
+-spec combine_heap_needs(term(), term()) -> term().
+
combine_heap_needs({alloc,Alloc1}, {alloc,Alloc2}) ->
{alloc,combine_alloc_lists(Alloc1, Alloc2)};
combine_heap_needs({alloc,Alloc}, Words) when is_integer(Words) ->
@@ -235,25 +265,33 @@ combine_heap_needs(Words, {alloc,Alloc}) when is_integer(Words) ->
combine_heap_needs(H1, H2) when is_integer(H1), is_integer(H2) ->
H1+H2.
+%% split_even/1
+%% [1,2,3,4,5,6] -> {[1,3,5],[2,4,6]}
+
+-spec split_even(list()) -> {list(),list()}.
+
+split_even(Rs) -> split_even(Rs, [], []).
+
+
%%%
%%% Local functions.
%%%
-%% check_liveness(Reg, [Instruction], {State,BlockCheckFun}) ->
-%% {killed | used | unknown,UpdateState}
-%% Finds out how Reg is used in the instruction sequence. Returns one of:
-%% killed - Reg is assigned a new value or killed by an allocation instruction
-%% used - Reg is used (or possibly referenced by an allocation instruction)
-%% unknown - not possible to determine (perhaps because of an instruction
-%% that we don't recognize)
-
-check_liveness(R, [{set,_,_,_}=I|_], St) ->
- erlang:error(only_allowed_in_blocks, [R,I,St]);
-check_liveness(R, [{block,Blk}|Is], #live{bl=BlockCheck}=St0) ->
- case BlockCheck(R, Blk, St0) of
- {transparent,St} -> check_liveness(R, Is, St);
- {Other,_}=Res when is_atom(Other) -> Res
+%% check_liveness(Reg, [Instruction], #live{}) ->
+%% {killed | not_used | used, #live{}}
+%% Find out whether Reg is used or killed in instruction sequence.
+%%
+%% killed - Reg is assigned or killed by an allocation instruction.
+%% not_used - the value of Reg is not used, but Reg must not be garbage
+%% used - Reg is used
+
+check_liveness(R, [{block,Blk}|Is], St0) ->
+ case check_liveness_block(R, Blk, St0) of
+ {transparent,St1} ->
+ check_liveness(R, Is, St1);
+ {Other,_}=Res when is_atom(Other) ->
+ Res
end;
check_liveness(R, [{label,_}|Is], St) ->
check_liveness(R, Is, St);
@@ -263,8 +301,12 @@ check_liveness(R, [{test,_,{f,Fail},As}|Is], St0) ->
{used,St0};
false ->
case check_liveness_at(R, Fail, St0) of
- {killed,St} -> check_liveness(R, Is, St);
- {_,_}=Other -> Other
+ {killed,St1} ->
+ check_liveness(R, Is, St1);
+ {not_used,St1} ->
+ not_used(check_liveness(R, Is, St1));
+ {used,_}=Used ->
+ Used
end
end;
check_liveness(R, [{test,Op,Fail,Live,Ss,Dst}|Is], St) ->
@@ -325,13 +367,16 @@ check_liveness(R, [{deallocate,_}|Is], St) ->
{y,_} -> {killed,St};
_ -> check_liveness(R, Is, St)
end;
-check_liveness(R, [return|_], St) ->
- check_liveness_live_ret(R, 1, St);
+check_liveness({x,_}=R, [return|_], St) ->
+ case R of
+ {x,0} -> {used,St};
+ {x,_} -> {killed,St}
+ end;
check_liveness(R, [{call,Live,_}|Is], St) ->
case R of
{x,X} when X < Live -> {used,St};
{x,_} -> {killed,St};
- {y,_} -> check_liveness(R, Is, St)
+ {y,_} -> not_used(check_liveness(R, Is, St))
end;
check_liveness(R, [{call_ext,Live,_}=I|Is], St) ->
case R of
@@ -342,7 +387,7 @@ check_liveness(R, [{call_ext,Live,_}=I|Is], St) ->
{y,_} ->
case beam_jump:is_exit_instruction(I) of
false ->
- check_liveness(R, Is, St);
+ not_used(check_liveness(R, Is, St));
true ->
%% We must make sure we don't check beyond this
%% instruction or we will fall through into random
@@ -354,43 +399,20 @@ check_liveness(R, [{call_fun,Live}|Is], St) ->
case R of
{x,X} when X =< Live -> {used,St};
{x,_} -> {killed,St};
- {y,_} -> check_liveness(R, Is, St)
+ {y,_} -> not_used(check_liveness(R, Is, St))
end;
check_liveness(R, [{apply,Args}|Is], St) ->
case R of
{x,X} when X < Args+2 -> {used,St};
{x,_} -> {killed,St};
- {y,_} -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bif,Op,{f,Fail},Ss,D}|Is], St0) ->
- case check_liveness_fail(R, Op, Ss, Fail, St0) of
- {killed,St} = Killed ->
- case member(R, Ss) of
- true -> {used,St};
- false when R =:= D -> Killed;
- false -> check_liveness(R, Is, St)
- end;
- Other ->
- Other
- end;
-check_liveness(R, [{gc_bif,Op,{f,Fail},Live,Ss,D}|Is], St0) ->
- case R of
- {x,X} when X >= Live ->
- {killed,St0};
- {x,_} ->
- {used,St0};
- _ ->
- case check_liveness_fail(R, Op, Ss, Fail, St0) of
- {killed,St}=Killed ->
- case member(R, Ss) of
- true -> {used,St};
- false when R =:= D -> Killed;
- false -> check_liveness(R, Is, St)
- end;
- Other ->
- Other
- end
- end;
+ {y,_} -> not_used(check_liveness(R, Is, St))
+ end;
+check_liveness(R, [{bif,Op,Fail,Ss,D}|Is], St) ->
+ Set = {set,[D],Ss,{bif,Op,Fail}},
+ check_liveness(R, [{block,[Set]}|Is], St);
+check_liveness(R, [{gc_bif,Op,{f,Fail},Live,Ss,D}|Is], St) ->
+ Set = {set,[D],Ss,{alloc,Live,{gc_bif,Op,Fail}}},
+ check_liveness(R, [{block,[Set]}|Is], St);
check_liveness(R, [{bs_put,{f,0},_,Ss}|Is], St) ->
case member(R, Ss) of
true -> {used,St};
@@ -416,7 +438,7 @@ check_liveness(R, [{make_fun2,_,_,_,NumFree}|Is], St) ->
case R of
{x,X} when X < NumFree -> {used,St};
{x,_} -> {killed,St};
- _ -> check_liveness(R, Is, St)
+ {y,_} -> not_used(check_liveness(R, Is, St))
end;
check_liveness({x,_}=R, [{'catch',_,_}|Is], St) ->
%% All x registers will be killed if an exception occurs.
@@ -461,8 +483,9 @@ check_liveness(R, [{loop_rec,{f,_},{x,0}}|_], St) ->
{x,_} ->
{killed,St};
_ ->
- %% y register. Rarely happens. Be very conversative.
- {unknown,St}
+ %% y register. Rarely happens. Be very conversative and
+ %% assume it's used.
+ {used,St}
end;
check_liveness(R, [{loop_rec_end,{f,Fail}}|_], St) ->
check_liveness_at(R, Fail, St);
@@ -484,23 +507,39 @@ check_liveness(R, [{get_map_elements,{f,Fail},S,{list,L}}|Is], St0) ->
Other
end
end;
+check_liveness(R, [{put_map,F,Op,S,D,Live,{list,Puts}}|Is], St) ->
+ Set = {set,[D],[S|Puts],{alloc,Live,{put_map,Op,F}}},
+ check_liveness(R, [{block,[Set]}||Is], St);
+check_liveness(R, [{test_heap,N,Live}|Is], St) ->
+ I = {block,[{set,[],[],{alloc,Live,{nozero,nostack,N,[]}}}]},
+ check_liveness(R, [I|Is], St);
+check_liveness(R, [{allocate_zero,N,Live}|Is], St) ->
+ I = {block,[{set,[],[],{alloc,Live,{zero,N,0,[]}}}]},
+ check_liveness(R, [I|Is], St);
+check_liveness(R, [{get_list,S,D1,D2}|Is], St) ->
+ I = {block,[{set,[D1,D2],[S],get_list}]},
+ check_liveness(R, [I|Is], St);
check_liveness(_R, Is, St) when is_list(Is) ->
-%% case Is of
-%% [I|_] ->
-%% io:format("~p ~p\n", [_R,I]);
-%% _ -> ok
-%% end,
- {unknown,St}.
-
-check_liveness_everywhere(R, [{f,Lbl}|T], St0) ->
- case check_liveness_at(R, Lbl, St0) of
- {killed,St} -> check_liveness_everywhere(R, T, St);
- {_,_}=Other -> Other
- end;
-check_liveness_everywhere(R, [_|T], St) ->
- check_liveness_everywhere(R, T, St);
-check_liveness_everywhere(_, [], St) ->
- {killed,St}.
+ %% Not implemented. Conservatively assume that the register is used.
+ {used,St}.
+
+check_liveness_everywhere(R, Lbls, St0) ->
+ check_liveness_everywhere_1(R, Lbls, killed, St0).
+
+check_liveness_everywhere_1(R, [{f,Lbl}|T], Res0, St0) ->
+ {Res1,St} = check_liveness_at(R, Lbl, St0),
+ Res = case Res1 of
+ killed -> Res0;
+ _ -> Res1
+ end,
+ case Res of
+ used -> {used,St};
+ _ -> check_liveness_everywhere_1(R, T, Res, St)
+ end;
+check_liveness_everywhere_1(R, [_|T], Res, St) ->
+ check_liveness_everywhere_1(R, T, Res, St);
+check_liveness_everywhere_1(_, [], Res, St) ->
+ {Res,St}.
check_liveness_at(R, Lbl, #live{lbl=Ll,res=ResMemorized}=St0) ->
case gb_trees:lookup(Lbl, ResMemorized) of
@@ -509,119 +548,90 @@ check_liveness_at(R, Lbl, #live{lbl=Ll,res=ResMemorized}=St0) ->
none ->
{Res,St} = case gb_trees:lookup(Lbl, Ll) of
{value,Is} -> check_liveness(R, Is, St0);
- none -> {unknown,St0}
+ none -> {used,St0}
end,
{Res,St#live{res=gb_trees:insert(Lbl, Res, St#live.res)}}
end.
+not_used({killed,St}) -> {not_used,St};
+not_used({_,_}=Res) -> Res.
+
check_liveness_ret(R, R, St) -> {used,St};
check_liveness_ret(_, _, St) -> {killed,St}.
-check_liveness_live_ret({x,R}, Live, St) ->
- if
- R < Live -> {used,St};
- true -> {killed,St}
- end;
-check_liveness_live_ret({y,_}, _, St) ->
- {killed,St}.
-
-check_liveness_fail(_, _, _, 0, St) ->
- {killed,St};
-check_liveness_fail(R, Op, Args, Fail, St) ->
- Arity = length(Args),
- case erl_internal:comp_op(Op, Arity) orelse
- erl_internal:new_type_test(Op, Arity) of
- true -> {killed,St};
- false -> check_liveness_at(R, Fail, St)
- end.
-
-%% check_killed_block(Reg, [Instruction], State) -> killed | transparent | used
-%% Finds out how Reg is used in the instruction sequence inside a block.
-%% Returns one of:
-%% killed - Reg is assigned a new value or killed by an allocation instruction
-%% transparent - Reg is neither used nor killed
-%% used - Reg is used or referenced by an allocation instruction.
-%%
-%% (Unknown instructions will cause an exception.)
-
-check_killed_block_fun() ->
- fun(R, Is, St) -> {check_killed_block(R, Is),St} end.
-
-check_killed_block({x,X}, [{set,_,_,{alloc,Live,_}}|_]) ->
- if
- X >= Live -> killed;
- true -> used
- end;
-check_killed_block(R, [{set,Ds,Ss,_Op}|Is]) ->
- case member(R, Ss) of
- true -> used;
- false ->
- case member(R, Ds) of
- true -> killed;
- false -> check_killed_block(R, Is)
- end
- end;
-check_killed_block(R, [{'%live',Live,_}|Is]) ->
- case R of
- {x,X} when X >= Live -> killed;
- _ -> check_killed_block(R, Is)
- end;
-check_killed_block(_, []) -> transparent.
-
-%% check_used_block(Reg, [Instruction], State) -> killed | transparent | used
+%% check_liveness_block(Reg, [Instruction], State) ->
+%% {killed | not_used | used | transparent,State'}
%% Finds out how Reg is used in the instruction sequence inside a block.
%% Returns one of:
-%% killed - Reg is assigned a new value or killed by an allocation instruction
+%% killed - Reg is assigned a new value or killed by an
+%% allocation instruction
+%% not_used - The value is not used, but the register is referenced
+%% e.g. by an allocation instruction
%% transparent - Reg is neither used nor killed
%% used - Reg is explicitly used by an instruction
-%%
-%% (Unknown instructions will cause an exception.)
+%%
+%% '%live' annotations are not allowed.
+%%
+%% (Unknown instructions will cause an exception.)
-check_used_block({x,X}=R, [{set,Ds,Ss,{alloc,Live,Op}}|Is], St) ->
+check_liveness_block({x,X}=R, [{set,Ds,Ss,{alloc,Live,Op}}|Is], St0) ->
if
- X >= Live -> {killed,St};
- true -> check_used_block_1(R, Ss, Ds, Op, Is, St)
- end;
-check_used_block(R, [{set,Ds,Ss,Op}|Is], St) ->
- check_used_block_1(R, Ss, Ds, Op, Is, St);
-check_used_block(R, [{'%live',Live,_}|Is], St) ->
- case R of
- {x,X} when X >= Live -> {killed,St};
- _ -> check_used_block(R, Is, St)
+ X >= Live ->
+ {killed,St0};
+ true ->
+ case check_liveness_block_1(R, Ss, Ds, Op, Is, St0) of
+ {killed,St} -> {not_used,St};
+ {transparent,St} -> {not_used,St};
+ {_,_}=Res -> Res
+ end
end;
-check_used_block(_, [], St) -> {transparent,St}.
+check_liveness_block({y,_}=R, [{set,Ds,Ss,{alloc,_Live,Op}}|Is], St) ->
+ check_liveness_block_1(R, Ss, Ds, Op, Is, St);
+check_liveness_block(R, [{set,Ds,Ss,Op}|Is], St) ->
+ check_liveness_block_1(R, Ss, Ds, Op, Is, St);
+check_liveness_block(_, [], St) -> {transparent,St}.
-check_used_block_1(R, Ss, Ds, Op, Is, St0) ->
+check_liveness_block_1(R, Ss, Ds, Op, Is, St0) ->
case member(R, Ss) of
true ->
{used,St0};
false ->
- case is_reg_used_at(R, Op, St0) of
- {true,St} ->
- {used,St};
- {false,St} ->
+ case check_liveness_block_2(R, Op, Ss, St0) of
+ {killed,St} ->
case member(R, Ds) of
true -> {killed,St};
- false -> check_used_block(R, Is, St)
- end
+ false -> check_liveness_block(R, Is, St)
+ end;
+ {not_used,St} ->
+ not_used(case member(R, Ds) of
+ true -> {killed,St};
+ false -> check_liveness_block(R, Is, St)
+ end);
+ {used,St} ->
+ {used,St}
end
end.
-is_reg_used_at(R, {gc_bif,_,{f,Lbl}}, St) ->
- is_reg_used_at_1(R, Lbl, St);
-is_reg_used_at(R, {bif,_,{f,Lbl}}, St) ->
- is_reg_used_at_1(R, Lbl, St);
-is_reg_used_at(_, _, St) ->
- {false,St}.
+check_liveness_block_2(R, {gc_bif,_Op,{f,Lbl}}, _Ss, St) ->
+ check_liveness_block_3(R, Lbl, St);
+check_liveness_block_2(R, {bif,Op,{f,Lbl}}, Ss, St) ->
+ Arity = length(Ss),
+ case erl_internal:comp_op(Op, Arity) orelse
+ erl_internal:new_type_test(Op, Arity) of
+ true ->
+ {killed,St};
+ false ->
+ check_liveness_block_3(R, Lbl, St)
+ end;
+check_liveness_block_2(R, {put_map,_Op,{f,Lbl}}, _Ss, St) ->
+ check_liveness_block_3(R, Lbl, St);
+check_liveness_block_2(_, _, _, St) ->
+ {killed,St}.
-is_reg_used_at_1(_, 0, St) ->
- {false,St};
-is_reg_used_at_1(R, Lbl, St0) ->
- case check_liveness_at(R, Lbl, St0) of
- {killed,St} -> {false,St};
- {used,St} -> {true,St};
- {unknown,St} -> {true,St}
- end.
+check_liveness_block_3(_, 0, St) ->
+ {killed,St};
+check_liveness_block_3(R, Lbl, St0) ->
+ check_liveness_at(R, Lbl, St0).
index_labels_1([{label,Lbl}|Is0], Acc) ->
Is = drop_labels(Is0),
@@ -736,11 +746,6 @@ live_opt([{select,_,Src,Fail,List}=I|Is], Regs0, D, Acc) ->
Regs1 = x_live([Src], Regs0),
Regs = live_join_labels([Fail|List], D, Regs1),
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{'try',_,_}=I|Is], Regs, D, Acc) ->
- %% If an exeption happens, all x registers will be killed.
- %% Therefore, we should only base liveness of the code inside
- %% the try.
- live_opt(Is, Regs, D, [I|Acc]);
live_opt([{try_case,_}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(1), D, [I|Acc]);
live_opt([{loop_rec,_Fail,_Dst}=I|Is], _, D, Acc) ->
@@ -749,6 +754,11 @@ live_opt([timeout=I|Is], _, D, Acc) ->
live_opt(Is, 0, D, [I|Acc]);
live_opt([{wait,_}=I|Is], _, D, Acc) ->
live_opt(Is, 0, D, [I|Acc]);
+live_opt([{get_map_elements,Fail,Src,{list,List}}=I|Is], Regs0, D, Acc) ->
+ {Ss,Ds} = split_even(List),
+ Regs1 = x_live([Src|Ss], x_dead(Ds, Regs0)),
+ Regs = live_join_label(Fail, D, Regs1),
+ live_opt(Is, Regs, D, [I|Acc]);
%% Transparent instructions - they neither use nor modify x registers.
live_opt([{deallocate,_}=I|Is], Regs, D, Acc) ->
@@ -795,7 +805,8 @@ live_opt_block([{set,Ds,Ss,Op0}|Is], Regs0, D, Acc) ->
_ ->
live_opt_block(Is, Regs, D, [I|Acc])
end;
-
+live_opt_block([{'%live',_,_}|Is], Regs, D, Acc) ->
+ live_opt_block(Is, Regs, D, Acc);
live_opt_block([], Regs, _, Acc) -> {Acc,Regs}.
live_opt_block_op({alloc,Live0,AllocOp}, Regs0, D) ->
@@ -850,14 +861,7 @@ x_live([], Regs) -> Regs.
is_live(X, Regs) -> ((Regs bsr X) band 1) =:= 1.
-%% split_even/1
-%% [1,2,3,4,5,6] -> {[1,3,5],[2,4,6]}
-split_even(Rs) -> split_even(Rs,[],[]).
-split_even([],Ss,Ds) -> {reverse(Ss),reverse(Ds)};
-split_even([S,D|Rs],Ss,Ds) ->
- split_even(Rs,[S|Ss],[D|Ds]).
-
-%% join_even/1
-%% {[1,3,5],[2,4,6]} -> [1,2,3,4,5,6]
-join_even([],[]) -> [];
-join_even([S|Ss],[D|Ds]) -> [S,D|join_even(Ss,Ds)].
+split_even([], Ss, Ds) ->
+ {reverse(Ss),reverse(Ds)};
+split_even([S,D|Rs], Ss, Ds) ->
+ split_even(Rs, [S|Ss], [D|Ds]).
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index b18eb47d0e..be8908dd6b 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. 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.
@@ -31,16 +31,11 @@
-import(lists, [reverse/1,foldl/3,foreach/2,dropwhile/2]).
--define(MAXREG, 1024).
+%% To be called by the compiler.
-%%-define(DEBUG, 1).
--ifdef(DEBUG).
--define(DBG_FORMAT(F, D), (io:format((F), (D)))).
--else.
--define(DBG_FORMAT(F, D), ok).
--endif.
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_utils:module_code()}.
-%% To be called by the compiler.
module({Mod,Exp,Attr,Fs,Lc}=Code, _Opts)
when is_atom(Mod), is_list(Exp), is_list(Attr), is_integer(Lc) ->
case validate(Mod, Fs) of
@@ -170,29 +165,25 @@ validate_0(Module, [{function,Name,Ar,Entry,Code}|Fs], Ft) ->
% in the module (those that start with bs_start_match2).
}).
--ifdef(DEBUG).
-print_st(#st{x=Xs,y=Ys,numy=NumY,h=H,ct=Ct}) ->
- io:format(" #st{x=~p~n"
- " y=~p~n"
- " numy=~p,h=~p,ct=~w~n",
- [gb_trees:to_list(Xs),gb_trees:to_list(Ys),NumY,H,Ct]).
--endif.
+%% Match context type.
+-record(ms,
+ {id=make_ref() :: reference(), %Unique ID.
+ valid=0 :: non_neg_integer(), %Valid slots
+ slots=0 :: non_neg_integer() %Number of slots
+ }).
validate_1(Is, Name, Arity, Entry, Ft) ->
validate_2(labels(Is), Name, Arity, Entry, Ft).
validate_2({Ls1,[{func_info,{atom,Mod},{atom,Name},Arity}=_F|Is]},
Name, Arity, Entry, Ft) ->
- lists:foreach(fun (_L) -> ?DBG_FORMAT(" ~p.~n", [{label,_L}]) end, Ls1),
- ?DBG_FORMAT(" ~p.~n", [_F]),
validate_3(labels(Is), Name, Arity, Entry, Mod, Ls1, Ft);
validate_2({Ls1,Is}, Name, Arity, _Entry, _Ft) ->
error({{'_',Name,Arity},{first(Is),length(Ls1),illegal_instruction}}).
validate_3({Ls2,Is}, Name, Arity, Entry, Mod, Ls1, Ft) ->
- lists:foreach(fun (_L) -> ?DBG_FORMAT(" ~p.~n", [{label,_L}]) end, Ls2),
Offset = 1 + length(Ls1) + 1 + length(Ls2),
- EntryOK = (Entry =:= undefined) orelse lists:member(Entry, Ls2),
+ EntryOK = lists:member(Entry, Ls2),
if
EntryOK ->
St = init_state(Arity),
@@ -260,7 +251,6 @@ valfun([], MFA, _Offset, #vst{branched=Targets0,labels=Labels0}=Vst) ->
error({MFA,Error})
end;
valfun([I|Is], MFA, Offset, Vst0) ->
- ?DBG_FORMAT(" ~p.\n", [I]),
valfun(Is, MFA, Offset+1,
try
Vst = val_dsetel(I, Vst0),
@@ -278,7 +268,6 @@ valfun_1({label,Lbl}, #vst{current=St0,branched=B,labels=Lbls}=Vst) ->
valfun_1(_I, #vst{current=none}=Vst) ->
%% Ignore instructions after erlang:error/1,2, which
%% the original R10B compiler thought would return.
- ?DBG_FORMAT("Ignoring ~p\n", [_I]),
Vst;
valfun_1({badmatch,Src}, Vst) ->
assert_term(Src, Vst),
@@ -296,7 +285,7 @@ valfun_1({bs_context_to_binary,Ctx}, #vst{current=#st{x=Xs}}=Vst) ->
case Ctx of
{Tag,X} when Tag =:= x; Tag =:= y ->
Type = case gb_trees:lookup(X, Xs) of
- {value,{match_context,_,_}} -> term;
+ {value,#ms{}} -> term;
_ -> get_term_type(Ctx, Vst)
end,
set_type_reg(Type, Ctx, Vst);
@@ -531,6 +520,9 @@ valfun_4({bif,element,{f,Fail},[Pos,Tuple],Dst}, Vst0) ->
TupleType = upgrade_tuple_type({tuple,[get_tuple_size(PosType)]}, TupleType0),
Vst = set_type(TupleType, Tuple, Vst1),
set_type_reg(term, Dst, Vst);
+valfun_4({bif,raise,{f,0},Src,_Dst}, Vst) ->
+ validate_src(Src, Vst),
+ kill_state(Vst);
valfun_4({bif,Op,{f,Fail},Src,Dst}, Vst0) ->
validate_src(Src, Vst0),
Vst = branch_state(Fail, Vst0),
@@ -594,7 +586,7 @@ valfun_4({test,bs_start_match2,{f,Fail},Live,[Ctx,NeedSlots],Ctx}, Vst0) ->
verify_live(Live, Vst0),
Vst1 = prune_x_regs(Live, Vst0),
BranchVst = case CtxType of
- {match_context,_,_} ->
+ #ms{} ->
%% The failure branch will never be taken when Ctx
%% is a match context. Therefore, the type for Ctx
%% at the failure label must not be match_context
@@ -631,17 +623,17 @@ valfun_4({test,bs_skip_utf16,{f,Fail},[Ctx,Live,_]}, Vst) ->
valfun_4({test,bs_skip_utf32,{f,Fail},[Ctx,Live,_]}, Vst) ->
validate_bs_skip_utf(Fail, Ctx, Live, Vst);
valfun_4({test,bs_get_integer2,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
- validate_bs_get(Fail, Ctx, Live, Dst, Vst);
+ validate_bs_get(Fail, Ctx, Live, {integer, []}, Dst, Vst);
valfun_4({test,bs_get_float2,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
- validate_bs_get(Fail, Ctx, Live, Dst, Vst);
+ validate_bs_get(Fail, Ctx, Live, {float, []}, Dst, Vst);
valfun_4({test,bs_get_binary2,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
- validate_bs_get(Fail, Ctx, Live, Dst, Vst);
+ validate_bs_get(Fail, Ctx, Live, term, Dst, Vst);
valfun_4({test,bs_get_utf8,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
- validate_bs_get(Fail, Ctx, Live, Dst, Vst);
+ validate_bs_get(Fail, Ctx, Live, {integer, []}, Dst, Vst);
valfun_4({test,bs_get_utf16,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
- validate_bs_get(Fail, Ctx, Live, Dst, Vst);
+ validate_bs_get(Fail, Ctx, Live, {integer, []}, Dst, Vst);
valfun_4({test,bs_get_utf32,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
- validate_bs_get(Fail, Ctx, Live, Dst, Vst);
+ validate_bs_get(Fail, Ctx, Live, {integer, []}, Dst, Vst);
valfun_4({bs_save2,Ctx,SavePoint}, Vst) ->
bsm_save(Ctx, SavePoint, Vst);
valfun_4({bs_restore2,Ctx,SavePoint}, Vst) ->
@@ -661,6 +653,9 @@ valfun_4({test,is_nonempty_list,{f,Lbl},[Cons]}, Vst) ->
valfun_4({test,test_arity,{f,Lbl},[Tuple,Sz]}, Vst) when is_integer(Sz) ->
assert_type(tuple, Tuple, Vst),
set_type_reg({tuple,Sz}, Tuple, branch_state(Lbl, Vst));
+valfun_4({test,is_tagged_tuple,{f,Lbl},[Src,Sz,_Atom]}, Vst) ->
+ validate_src([Src], Vst),
+ set_type_reg({tuple, Sz}, Src, branch_state(Lbl, Vst));
valfun_4({test,has_map_fields,{f,Lbl},Src,{list,List}}, Vst) ->
assert_type(map, Src, Vst),
assert_unique_map_keys(List),
@@ -670,8 +665,10 @@ valfun_4({test,is_map,{f,Lbl},[Src]}, Vst0) ->
case Src of
{Tag,_} when Tag =:= x; Tag =:= y ->
set_type_reg(map, Src, Vst);
+ {literal,Map} when is_map(Map) ->
+ Vst;
_ ->
- Vst
+ kill_state(Vst)
end;
valfun_4({test,_Op,{f,Lbl},Src}, Vst) ->
validate_src(Src, Vst),
@@ -797,12 +794,12 @@ verify_put_map(Fail, Src, Dst, Live, List, Vst0) ->
%%
%% Common code for validating bs_get* instructions.
%%
-validate_bs_get(Fail, Ctx, Live, Dst, Vst0) ->
+validate_bs_get(Fail, Ctx, Live, Type, Dst, Vst0) ->
bsm_validate_context(Ctx, Vst0),
verify_live(Live, Vst0),
Vst1 = prune_x_regs(Live, Vst0),
Vst = branch_state(Fail, Vst1),
- set_type_reg(term, Dst, Vst).
+ set_type_reg(Type, Dst, Vst).
%%
%% Common code for validating bs_skip_utf* instructions.
@@ -818,9 +815,11 @@ validate_bs_skip_utf(Fail, Ctx, Live, Vst0) ->
%% A possibility for garbage collection must not occur between setelement/3 and
%% set_tuple_element/3.
%%
+%% Note that #vst.current will be 'none' if the instruction is unreachable.
+%%
val_dsetel({move,_,_}, Vst) ->
Vst;
-val_dsetel({call_ext,3,{extfunc,erlang,setelement,3}}, #vst{current=St}=Vst) ->
+val_dsetel({call_ext,3,{extfunc,erlang,setelement,3}}, #vst{current=#st{}=St}=Vst) ->
Vst#vst{current=St#st{setelem=true}};
val_dsetel({set_tuple_element,_,_,_}, #vst{current=#st{setelem=false}}) ->
error(illegal_context_for_set_tuple_element);
@@ -847,7 +846,7 @@ kill_state_1(Vst) ->
%% The stackframe must be initialized.
%% The instruction will return to the instruction following the call.
call(Name, Live, #vst{current=St}=Vst) ->
- verify_live(Live, Vst),
+ verify_call_args(Name, Live, Vst),
verify_y_init(Vst),
case return_type(Name, Vst) of
Type when Type =/= exception ->
@@ -859,44 +858,74 @@ call(Name, Live, #vst{current=St}=Vst) ->
%% Tail call.
%% The stackframe must have a known size and be initialized.
%% Does not return to the instruction following the call.
-tail_call(Name, Live, Vst) ->
+tail_call(Name, Live, Vst0) ->
+ verify_y_init(Vst0),
+ Vst = deallocate(Vst0),
verify_call_args(Name, Live, Vst),
- verify_y_init(Vst),
verify_no_ct(Vst),
kill_state(Vst).
verify_call_args(_, 0, #vst{}) ->
ok;
verify_call_args({f,Lbl}, Live, Vst) when is_integer(Live)->
- Verify = fun(R) ->
- case get_move_term_type(R, Vst) of
- {match_context,_,_} ->
- verify_call_match_context(Lbl, Vst);
- _ ->
- ok
- end
- end,
- verify_call_args_1(Live, Verify, Vst);
+ verify_local_call(Lbl, Live, Vst);
verify_call_args(_, Live, Vst) when is_integer(Live)->
- Verify = fun(R) -> get_term_type(R, Vst) end,
- verify_call_args_1(Live, Verify, Vst);
+ verify_call_args_1(Live, Vst);
verify_call_args(_, Live, _) ->
error({bad_number_of_live_regs,Live}).
-verify_call_args_1(0, _, _) -> ok;
-verify_call_args_1(N, Verify, Vst) ->
+verify_call_args_1(0, _) -> ok;
+verify_call_args_1(N, Vst) ->
X = N - 1,
- Verify({x,X}),
- verify_call_args_1(X, Verify, Vst).
+ get_term_type({x,X}, Vst),
+ verify_call_args_1(X, Vst).
+
+verify_local_call(Lbl, Live, Vst) ->
+ case all_ms_in_x_regs(Live, Vst) of
+ [{R,Ctx}] ->
+ %% Verify that there is a suitable bs_start_match2 instruction.
+ verify_call_match_context(Lbl, R, Vst),
+
+ %% Since the callee has consumed the match context,
+ %% there must be no additional copies in Y registers.
+ #ms{id=Id} = Ctx,
+ case ms_in_y_regs(Id, Vst) of
+ [] ->
+ ok;
+ [_|_]=Ys ->
+ error({multiple_match_contexts,[R|Ys]})
+ end;
+ [_,_|_]=Xs0 ->
+ Xs = [R || {R,_} <- Xs0],
+ error({multiple_match_contexts,Xs});
+ [] ->
+ ok
+ end.
+
+all_ms_in_x_regs(0, _Vst) ->
+ [];
+all_ms_in_x_regs(Live0, Vst) ->
+ Live = Live0 - 1,
+ R = {x,Live},
+ case get_move_term_type(R, Vst) of
+ #ms{}=M ->
+ [{R,M}|all_ms_in_x_regs(Live, Vst)];
+ _ ->
+ all_ms_in_x_regs(Live, Vst)
+ end.
+
+ms_in_y_regs(Id, #vst{current=#st{y=Ys0}}) ->
+ Ys = gb_trees:to_list(Ys0),
+ [{y,Y} || {Y,#ms{id=OtherId}} <- Ys, OtherId =:= Id].
-verify_call_match_context(Lbl, #vst{ft=Ft}) ->
+verify_call_match_context(Lbl, Ctx, #vst{ft=Ft}) ->
case gb_trees:lookup(Lbl, Ft) of
none ->
error(no_bs_start_match2);
{value,[{test,bs_start_match2,_,_,[Ctx,_],Ctx}|_]} ->
ok;
- {value,[{test,bs_start_match2,_,_,[Bin,_,_],Ctx}|_]} ->
- error({binary_and_context_regs_different,Bin,Ctx})
+ {value,[{test,bs_start_match2,_,_,_,_}=I|_]} ->
+ error({unsuitable_bs_start_match2,I})
end.
allocate(Zero, Stk, Heap, Live, #vst{current=#st{numy=none}}=Vst0) ->
@@ -980,9 +1009,9 @@ get_fls(#vst{current=#st{fls=Fls}}) when is_atom(Fls) -> Fls.
init_fregs() -> 0.
-set_freg({fr,Fr}, #vst{current=#st{f=Fregs0}=St}=Vst)
+set_freg({fr,Fr}=Freg, #vst{current=#st{f=Fregs0}=St}=Vst)
when is_integer(Fr), 0 =< Fr ->
- limit_check(Fr),
+ check_limit(Freg),
Bit = 1 bsl Fr,
if
Fregs0 band Bit =:= 0 ->
@@ -995,9 +1024,10 @@ set_freg(Fr, _) -> error({bad_target,Fr}).
assert_freg_set({fr,Fr}=Freg, #vst{current=#st{f=Fregs}})
when is_integer(Fr), 0 =< Fr ->
if
- Fregs band (1 bsl Fr) =/= 0 ->
- limit_check(Fr);
- true -> error({uninitialized_reg,Freg})
+ (Fregs bsr Fr) band 1 =:= 0 ->
+ error({uninitialized_reg,Freg});
+ true ->
+ ok
end;
assert_freg_set(Fr, _) -> error({bad_source,Fr}).
@@ -1027,7 +1057,7 @@ assert_unique_map_keys([_,_|_]=Ls) ->
%%%
bsm_match_state(Slots) ->
- {match_context,0,Slots}.
+ #ms{slots=Slots}.
bsm_validate_context(Reg, Vst) ->
_ = bsm_get_context(Reg, Vst),
@@ -1035,7 +1065,7 @@ bsm_validate_context(Reg, Vst) ->
bsm_get_context({x,X}=Reg, #vst{current=#st{x=Xs}}=_Vst) when is_integer(X) ->
case gb_trees:lookup(X, Xs) of
- {value,{match_context,_,_}=Ctx} -> Ctx;
+ {value,#ms{}=Ctx} -> Ctx;
_ -> error({no_bsm_context,Reg})
end;
bsm_get_context(Reg, _) -> error({bad_source,Reg}).
@@ -1047,8 +1077,8 @@ bsm_save(Reg, {atom,start}, Vst) ->
Vst;
bsm_save(Reg, SavePoint, Vst) ->
case bsm_get_context(Reg, Vst) of
- {match_context,Bits,Slots} when SavePoint < Slots ->
- Ctx = {match_context,Bits bor (1 bsl SavePoint),Slots},
+ #ms{valid=Bits,slots=Slots}=Ctxt0 when SavePoint < Slots ->
+ Ctx = Ctxt0#ms{valid=Bits bor (1 bsl SavePoint),slots=Slots},
set_type_reg(Ctx, Reg, Vst);
_ -> error({illegal_save,SavePoint})
end.
@@ -1060,7 +1090,7 @@ bsm_restore(Reg, {atom,start}, Vst) ->
Vst;
bsm_restore(Reg, SavePoint, Vst) ->
case bsm_get_context(Reg, Vst) of
- {match_context,Bits,Slots} when SavePoint < Slots ->
+ #ms{valid=Bits,slots=Slots} when SavePoint < Slots ->
case Bits band (1 bsl SavePoint) of
0 -> error({illegal_restore,SavePoint,not_set});
_ -> Vst
@@ -1076,16 +1106,16 @@ set_type(Type, {x,_}=Reg, Vst) -> set_type_reg(Type, Reg, Vst);
set_type(Type, {y,_}=Reg, Vst) -> set_type_y(Type, Reg, Vst);
set_type(_, _, #vst{}=Vst) -> Vst.
-set_type_reg(Type, {x,X}, #vst{current=#st{x=Xs}=St}=Vst)
+set_type_reg(Type, {x,X}=Reg, #vst{current=#st{x=Xs}=St}=Vst)
when is_integer(X), 0 =< X ->
- limit_check(X),
+ check_limit(Reg),
Vst#vst{current=St#st{x=gb_trees:enter(X, Type, Xs)}};
set_type_reg(Type, Reg, Vst) ->
set_type_y(Type, Reg, Vst).
set_type_y(Type, {y,Y}=Reg, #vst{current=#st{y=Ys0}=St}=Vst)
when is_integer(Y), 0 =< Y ->
- limit_check(Y),
+ check_limit(Reg),
Ys = case gb_trees:lookup(Y, Ys0) of
none ->
error({invalid_store,Reg,Type});
@@ -1141,7 +1171,7 @@ assert_term(Src, Vst) ->
%% Thus 'exception' is never stored as type descriptor
%% for a register.
%%
-%% {match_context,_,_} A matching context for bit syntax matching. We do allow
+%% #ms{} A match context for bit syntax matching. We do allow
%% it to moved/to from stack, but otherwise it must only
%% be accessed by bit syntax matching instructions.
%%
@@ -1183,12 +1213,17 @@ assert_type(WantedType, Term, Vst) ->
assert_type(Correct, Correct) -> ok;
assert_type(float, {float,_}) -> ok;
assert_type(tuple, {tuple,_}) -> ok;
+assert_type(tuple, {literal,Tuple}) when is_tuple(Tuple) -> ok;
assert_type({tuple_element,I}, {tuple,[Sz]})
when 1 =< I, I =< Sz ->
ok;
assert_type({tuple_element,I}, {tuple,Sz})
when is_integer(Sz), 1 =< I, I =< Sz ->
ok;
+assert_type({tuple_element,I}, {literal,Lit}) when I =< tuple_size(Lit) ->
+ ok;
+assert_type(cons, {literal,[_|_]}) ->
+ ok;
assert_type(Needed, Actual) ->
error({bad_type,{needed,Needed},{actual,Actual}}).
@@ -1243,7 +1278,7 @@ get_term_type(Src, Vst) ->
initialized -> error({unassigned,Src});
{catchtag,_} -> error({catchtag,Src});
{trytag,_} -> error({trytag,Src});
- {match_context,_,_} -> error({match_context,Src});
+ #ms{} -> error({match_context,Src});
Type -> Type
end.
@@ -1395,12 +1430,13 @@ merge_types(bool, {atom,A}) ->
merge_bool(A);
merge_types({atom,A}, bool) ->
merge_bool(A);
-merge_types({match_context,B0,Slots},{match_context,B1,Slots}) ->
- {match_context,B0 bor B1,Slots};
-merge_types({match_context,_,_}=M, _) ->
- M;
-merge_types(_, {match_context,_,_}=M) ->
- M;
+merge_types(#ms{id=Id1,valid=B1,slots=Slots1},
+ #ms{id=Id2,valid=B2,slots=Slots2}) ->
+ Id = if
+ Id1 =:= Id2 -> Id1;
+ true -> make_ref()
+ end,
+ #ms{id=Id,valid=B1 band B2,slots=min(Slots1, Slots2)};
merge_types(T1, T2) when T1 =/= T2 ->
%% Too different. All we know is that the type is a 'term'.
term.
@@ -1479,7 +1515,9 @@ bif_type(abs, [Num], Vst) ->
bif_type(float, _, _) -> {float,[]};
bif_type('/', _, _) -> {float,[]};
%% Integer operations.
+bif_type(ceil, [_], _) -> {integer,[]};
bif_type('div', [_,_], _) -> {integer,[]};
+bif_type(floor, [_], _) -> {integer,[]};
bif_type('rem', [_,_], _) -> {integer,[]};
bif_type(length, [_], _) -> {integer,[]};
bif_type(size, [_], _) -> {integer,[]};
@@ -1523,7 +1561,6 @@ bif_type(node, [_], _) -> {atom,[]};
bif_type(hd, [_], _) -> term;
bif_type(tl, [_], _) -> term;
bif_type(get, [_], _) -> term;
-bif_type(raise, [_,_], _) -> exception;
bif_type(Bif, _, _) when is_atom(Bif) -> term.
is_bif_safe('/=', 2) -> true;
@@ -1537,6 +1574,7 @@ is_bif_safe('>=', 2) -> true;
is_bif_safe(is_atom, 1) -> true;
is_bif_safe(is_boolean, 1) -> true;
is_bif_safe(is_binary, 1) -> true;
+is_bif_safe(is_bitstring, 1) -> true;
is_bif_safe(is_float, 1) -> true;
is_bif_safe(is_function, 1) -> true;
is_bif_safe(is_integer, 1) -> true;
@@ -1567,8 +1605,12 @@ return_type_1(erlang, setelement, 3, Vst) ->
Tuple = {x,1},
TupleType =
case get_term_type(Tuple, Vst) of
- {tuple,_}=TT -> TT;
- _ -> {tuple,[0]}
+ {tuple,_}=TT ->
+ TT;
+ {literal,Lit} when is_tuple(Lit) ->
+ {tuple,tuple_size(Lit)};
+ _ ->
+ {tuple,[0]}
end,
case get_term_type({x,0}, Vst) of
{integer,[]} -> TupleType;
@@ -1609,20 +1651,25 @@ return_type_math(log10, 1) -> {float,[]};
return_type_math(sqrt, 1) -> {float,[]};
return_type_math(atan2, 2) -> {float,[]};
return_type_math(pow, 2) -> {float,[]};
+return_type_math(ceil, 1) -> {float,[]};
+return_type_math(floor, 1) -> {float,[]};
+return_type_math(fmod, 2) -> {float,[]};
return_type_math(pi, 0) -> {float,[]};
return_type_math(F, A) when is_atom(F), is_integer(A), A >= 0 -> term.
-limit_check(Num) when is_integer(Num), Num >= ?MAXREG ->
- error(limit);
-limit_check(_) -> ok.
+check_limit({x,X}) when is_integer(X), X < 1023 ->
+ %% Note: x(1023) is reserved for use by the BEAM loader.
+ ok;
+check_limit({y,Y}) when is_integer(Y), Y < 1024 ->
+ ok;
+check_limit({fr,Fr}) when is_integer(Fr), Fr < 1024 ->
+ ok;
+check_limit(_) ->
+ error(limit).
min(A, B) when is_integer(A), is_integer(B), A < B -> A;
min(A, B) when is_integer(A), is_integer(B) -> B.
gb_trees_from_list(L) -> gb_trees:from_orddict(lists:sort(L)).
--ifdef(DEBUG).
-error(Error) -> exit(Error).
--else.
error(Error) -> throw(Error).
--endif.
diff --git a/lib/compiler/src/beam_z.erl b/lib/compiler/src/beam_z.erl
index 8381578b68..787e33c142 100644
--- a/lib/compiler/src/beam_z.erl
+++ b/lib/compiler/src/beam_z.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-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.
@@ -24,6 +24,11 @@
-export([module/2]).
+-import(lists, [dropwhile/2]).
+
+-spec module(beam_utils:module_code(), [compile:option()]) ->
+ {'ok',beam_asm:module_code()}.
+
module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
Fs = [function(F) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
@@ -51,6 +56,16 @@ undo_renames([{call,A,F},return|Is]) ->
[{call_only,A,F}|undo_renames(Is)];
undo_renames([{call_ext,A,F},return|Is]) ->
[{call_ext_only,A,F}|undo_renames(Is)];
+undo_renames([{bif,raise,_,_,_}=I|Is0]) ->
+ %% A minor optimization. Done here because:
+ %% (1) beam_jump may move or share 'raise' instructions, and that
+ %% may confuse beam_validator.
+ %% (2) beam_trim cannot do its optimization if the 'deallocate'
+ %% instruction after 'raise' has been removed.
+ Is = dropwhile(fun({label,_}) -> false;
+ (_) -> true
+ end, Is0),
+ [I|undo_renames(Is)];
undo_renames([I|Is]) ->
[undo_rename(I)|undo_renames(Is)];
undo_renames([]) -> [].
diff --git a/lib/compiler/src/cerl.erl b/lib/compiler/src/cerl.erl
index e7a2b8177a..6b936a7687 100644
--- a/lib/compiler/src/cerl.erl
+++ b/lib/compiler/src/cerl.erl
@@ -1,8 +1,3 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2010. 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
@@ -15,9 +10,8 @@
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
-%% %CopyrightEnd%
-
-%% =====================================================================
+%% @copyright 1999-2002 Richard Carlsson
+%% @author Richard Carlsson <[email protected]>
%% @doc Core Erlang abstract syntax trees.
%%
%% <p> This module defines an abstract data type for representing Core
@@ -126,6 +120,7 @@
%% keep map exports here for now
c_map_pattern/1,
is_c_map/1,
+ is_c_map_pattern/1,
map_es/1,
map_arg/1,
update_c_map/3,
@@ -134,7 +129,7 @@
ann_c_map_pattern/2,
map_pair_op/1,map_pair_key/1,map_pair_val/1,
update_c_map_pair/4,
- c_map_pair/2,
+ c_map_pair/2, c_map_pair_exact/2,
ann_c_map_pair/4
]).
@@ -1589,6 +1584,8 @@ ann_make_list(_, [], Node) ->
%% @doc Returns <code>true</code> if <code>Node</code> is an abstract
%% map constructor, otherwise <code>false</code>.
+-type map_op() :: #c_literal{val::'assoc'} | #c_literal{val::'exact'}.
+
-spec is_c_map(cerl()) -> boolean().
is_c_map(#c_map{}) ->
@@ -1636,6 +1633,11 @@ is_c_map_empty(#c_map{ es=[] }) -> true;
is_c_map_empty(#c_literal{val=M}) when is_map(M),map_size(M) =:= 0 -> true;
is_c_map_empty(_) -> false.
+-spec is_c_map_pattern(c_map()) -> boolean().
+
+is_c_map_pattern(#c_map{is_pat=IsPat}) ->
+ IsPat.
+
-spec ann_c_map([term()], [c_map_pair()]) -> c_map() | c_literal().
ann_c_map(As, Es) ->
@@ -1679,8 +1681,16 @@ update_c_map(#c_map{is_pat=true}=Old, M, Es) ->
update_c_map(#c_map{is_pat=false}=Old, M, Es) ->
ann_c_map(get_ann(Old), M, Es).
+-spec map_pair_key(c_map_pair()) -> cerl().
+
map_pair_key(#c_map_pair{key=K}) -> K.
+
+-spec map_pair_val(c_map_pair()) -> cerl().
+
map_pair_val(#c_map_pair{val=V}) -> V.
+
+-spec map_pair_op(c_map_pair()) -> map_op().
+
map_pair_op(#c_map_pair{op=Op}) -> Op.
-spec c_map_pair(cerl(), cerl()) -> c_map_pair().
@@ -1688,12 +1698,19 @@ map_pair_op(#c_map_pair{op=Op}) -> Op.
c_map_pair(Key,Val) ->
#c_map_pair{op=#c_literal{val=assoc},key=Key,val=Val}.
+-spec c_map_pair_exact(cerl(), cerl()) -> c_map_pair().
+
+c_map_pair_exact(Key,Val) ->
+ #c_map_pair{op=#c_literal{val=exact},key=Key,val=Val}.
+
-spec ann_c_map_pair([term()], cerl(), cerl(), cerl()) ->
c_map_pair().
ann_c_map_pair(As,Op,K,V) ->
#c_map_pair{op=Op, key = K, val=V, anno = As}.
+-spec update_c_map_pair(c_map_pair(), map_op(), cerl(), cerl()) -> c_map_pair().
+
update_c_map_pair(Old,Op,K,V) ->
#c_map_pair{op=Op, key=K, val=V, anno = get_ann(Old)}.
@@ -1944,7 +1961,7 @@ is_c_var(_) ->
false.
-%% @spec c_fname(Name::atom(), Arity::integer()) -> cerl()
+%% @spec c_fname(Name::atom(), Arity::arity()) -> cerl()
%% @equiv c_var({Name, Arity})
%% @see fname_id/1
%% @see fname_arity/1
@@ -1952,18 +1969,18 @@ is_c_var(_) ->
%% @see ann_c_fname/3
%% @see update_c_fname/3
--spec c_fname(atom(), non_neg_integer()) -> c_var().
+-spec c_fname(atom(), arity()) -> c_var().
c_fname(Atom, Arity) ->
c_var({Atom, Arity}).
-%% @spec ann_c_fname(As::[term()], Name::atom(), Arity::integer()) ->
+%% @spec ann_c_fname(As::[term()], Name::atom(), Arity::arity()) ->
%% cerl()
%% @equiv ann_c_var(As, {Atom, Arity})
%% @see c_fname/2
--spec ann_c_fname([term()], atom(), non_neg_integer()) -> c_var().
+-spec ann_c_fname([term()], atom(), arity()) -> c_var().
ann_c_fname(As, Atom, Arity) ->
ann_c_var(As, {Atom, Arity}).
@@ -1981,13 +1998,13 @@ update_c_fname(#c_var{name = {_, Arity}, anno = As}, Atom) ->
#c_var{name = {Atom, Arity}, anno = As}.
-%% @spec update_c_fname(Old::cerl(), Name::atom(), Arity::integer()) ->
+%% @spec update_c_fname(Old::cerl(), Name::atom(), Arity::arity()) ->
%% cerl()
%% @equiv update_c_var(Old, {Atom, Arity})
%% @see update_c_fname/2
%% @see c_fname/2
--spec update_c_fname(c_var(), atom(), integer()) -> c_var().
+-spec update_c_fname(c_var(), atom(), arity()) -> c_var().
update_c_fname(Node, Atom, Arity) ->
update_c_var(Node, {Atom, Arity}).
@@ -2036,14 +2053,14 @@ fname_id(#c_var{name={A,_}}) ->
A.
-%% @spec fname_arity(cerl()) -> byte()
+%% @spec fname_arity(cerl()) -> arity()
%%
%% @doc Returns the arity part of an abstract function name variable.
%%
%% @see fname_id/1
%% @see c_fname/2
--spec fname_arity(c_var()) -> byte().
+-spec fname_arity(c_var()) -> arity().
fname_arity(#c_var{name={_,N}}) ->
N.
@@ -2489,7 +2506,7 @@ fun_body(Node) ->
Node#c_fun.body.
-%% @spec fun_arity(Node::cerl()) -> integer()
+%% @spec fun_arity(Node::cerl()) -> arity()
%%
%% @doc Returns the number of parameter subtrees of an abstract
%% fun-expression.
@@ -2500,7 +2517,7 @@ fun_body(Node) ->
%% @see c_fun/2
%% @see fun_vars/1
--spec fun_arity(c_fun()) -> non_neg_integer().
+-spec fun_arity(c_fun()) -> arity().
fun_arity(Node) ->
length(fun_vars(Node)).
@@ -3407,7 +3424,7 @@ apply_args(Node) ->
Node#c_apply.args.
-%% @spec apply_arity(Node::cerl()) -> integer()
+%% @spec apply_arity(Node::cerl()) -> arity()
%%
%% @doc Returns the number of argument subtrees of an abstract
%% function application.
@@ -3419,7 +3436,7 @@ apply_args(Node) ->
%% @see c_apply/2
%% @see apply_args/1
--spec apply_arity(c_apply()) -> non_neg_integer().
+-spec apply_arity(c_apply()) -> arity().
apply_arity(Node) ->
length(apply_args(Node)).
@@ -3525,7 +3542,7 @@ call_args(Node) ->
Node#c_call.args.
-%% @spec call_arity(Node::cerl()) -> integer()
+%% @spec call_arity(Node::cerl()) -> arity()
%%
%% @doc Returns the number of argument subtrees of an abstract
%% inter-module call.
@@ -3537,7 +3554,7 @@ call_args(Node) ->
%% @see c_call/3
%% @see call_args/1
--spec call_arity(c_call()) -> non_neg_integer().
+-spec call_arity(c_call()) -> arity().
call_arity(Node) ->
length(call_args(Node)).
@@ -3629,7 +3646,7 @@ primop_args(Node) ->
Node#c_primop.args.
-%% @spec primop_arity(Node::cerl()) -> integer()
+%% @spec primop_arity(Node::cerl()) -> arity()
%%
%% @doc Returns the number of argument subtrees of an abstract
%% primitive operation call.
@@ -3641,7 +3658,7 @@ primop_args(Node) ->
%% @see c_primop/2
%% @see primop_args/1
--spec primop_arity(c_primop()) -> non_neg_integer().
+-spec primop_arity(c_primop()) -> arity().
primop_arity(Node) ->
length(primop_args(Node)).
diff --git a/lib/compiler/src/cerl_clauses.erl b/lib/compiler/src/cerl_clauses.erl
index 4d2f1ebd1b..7d6518c3c6 100644
--- a/lib/compiler/src/cerl_clauses.erl
+++ b/lib/compiler/src/cerl_clauses.erl
@@ -1,8 +1,3 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2010. 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
@@ -15,8 +10,8 @@
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
-%% %CopyrightEnd%
-
+%% @copyright 1999-2002 Richard Carlsson
+%% @author Richard Carlsson <[email protected]>
%% @doc Utility functions for Core Erlang case/receive clauses.
%%
%% <p>Syntax trees are defined in the module <a
diff --git a/lib/compiler/src/cerl_inline.erl b/lib/compiler/src/cerl_inline.erl
index cbcacf9e8e..f5afa75b16 100644
--- a/lib/compiler/src/cerl_inline.erl
+++ b/lib/compiler/src/cerl_inline.erl
@@ -1,8 +1,3 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2012. 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
@@ -15,9 +10,9 @@
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
-%% %CopyrightEnd%
-%%
-%% Core Erlang inliner.
+%% @copyright 1999-2002 Richard Carlsson
+%% @author Richard Carlsson <[email protected]>
+%% @doc Core Erlang inliner.
%% =====================================================================
%%
diff --git a/lib/compiler/src/cerl_trees.erl b/lib/compiler/src/cerl_trees.erl
index 58bb18e34a..f30a0b33ac 100644
--- a/lib/compiler/src/cerl_trees.erl
+++ b/lib/compiler/src/cerl_trees.erl
@@ -1,8 +1,3 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2010. 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
@@ -15,8 +10,8 @@
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
-%% %CopyrightEnd%
-
+%% @copyright 1999-2002 Richard Carlsson.
+%% @author Richard Carlsson <[email protected]>
%% @doc Basic functions on Core Erlang abstract syntax trees.
%%
%% <p>Syntax trees are defined in the module <a
@@ -27,7 +22,7 @@
-module(cerl_trees).
-export([depth/1, fold/3, free_variables/1, get_label/1, label/1, label/2,
- map/2, mapfold/3, size/1, variables/1]).
+ map/2, mapfold/3, mapfold/4, size/1, variables/1]).
-import(cerl, [alias_pat/1, alias_var/1, ann_c_alias/3, ann_c_apply/3,
ann_c_binary/2, ann_c_bitstr/6, ann_c_call/4,
@@ -61,6 +56,7 @@
map_arg/1, map_es/1,
ann_c_map/3,
update_c_map/3,
+ is_c_map_pattern/1, ann_c_map_pattern/2,
map_pair_key/1,map_pair_val/1,map_pair_op/1,
ann_c_map_pair/4,
update_c_map_pair/4
@@ -340,136 +336,162 @@ fold_pairs(_, S, []) ->
%% starting with the given value <code>Initial</code>, while doing a
%% post-order traversal of the tree, much like <code>fold/3</code>.
%%
+%% This is the same as mapfold/4, with an identity function as the
+%% pre-operation.
+%%
%% @see map/2
%% @see fold/3
+%% @see mapfold/4
-spec mapfold(fun((cerl:cerl(), term()) -> {cerl:cerl(), term()}),
term(), cerl:cerl()) -> {cerl:cerl(), term()}.
mapfold(F, S0, T) ->
+ mapfold(fun(T0, A) -> {T0, A} end, F, S0, T).
+
+
+%% @spec mapfold(Pre, Post, Initial::term(), Tree::cerl()) ->
+%% {cerl(), term()}
+%%
+%% Pre = Post = (cerl(), term()) -> {cerl(), term()}
+%%
+%% @doc Does a combined map/fold operation on the nodes of the
+%% tree. It begins by calling <code>Pre</code> on the tree, using the
+%% <code>Initial</code> value. It then deconstructs the top node of
+%% the returned tree and recurses on the children, using the returned
+%% value as the new initial and carrying the returned values from one
+%% call to the next. Finally it reassembles the top node from the
+%% children, calls <code>Post</code> on it and returns the result.
+
+-spec mapfold(fun((cerl:cerl(), term()) -> {cerl:cerl(), term()}),
+ fun((cerl:cerl(), term()) -> {cerl:cerl(), term()}),
+ term(), cerl:cerl()) -> {cerl:cerl(), term()}.
+
+mapfold(Pre, Post, S00, T0) ->
+ {T, S0} = Pre(T0, S00),
case type(T) of
literal ->
case concrete(T) of
[_ | _] ->
- {T1, S1} = mapfold(F, S0, cons_hd(T)),
- {T2, S2} = mapfold(F, S1, cons_tl(T)),
- F(update_c_cons(T, T1, T2), S2);
+ {T1, S1} = mapfold(Pre, Post, S0, cons_hd(T)),
+ {T2, S2} = mapfold(Pre, Post, S1, cons_tl(T)),
+ Post(update_c_cons(T, T1, T2), S2);
V when tuple_size(V) > 0 ->
- {Ts, S1} = mapfold_list(F, S0, tuple_es(T)),
- F(update_c_tuple(T, Ts), S1);
+ {Ts, S1} = mapfold_list(Pre, Post, S0, tuple_es(T)),
+ Post(update_c_tuple(T, Ts), S1);
_ ->
- F(T, S0)
+ Post(T, S0)
end;
var ->
- F(T, S0);
+ Post(T, S0);
values ->
- {Ts, S1} = mapfold_list(F, S0, values_es(T)),
- F(update_c_values(T, Ts), S1);
+ {Ts, S1} = mapfold_list(Pre, Post, S0, values_es(T)),
+ Post(update_c_values(T, Ts), S1);
cons ->
- {T1, S1} = mapfold(F, S0, cons_hd(T)),
- {T2, S2} = mapfold(F, S1, cons_tl(T)),
- F(update_c_cons_skel(T, T1, T2), S2);
+ {T1, S1} = mapfold(Pre, Post, S0, cons_hd(T)),
+ {T2, S2} = mapfold(Pre, Post, S1, cons_tl(T)),
+ Post(update_c_cons_skel(T, T1, T2), S2);
tuple ->
- {Ts, S1} = mapfold_list(F, S0, tuple_es(T)),
- F(update_c_tuple_skel(T, Ts), S1);
+ {Ts, S1} = mapfold_list(Pre, Post, S0, tuple_es(T)),
+ Post(update_c_tuple_skel(T, Ts), S1);
map ->
- {M , S1} = mapfold(F, S0, map_arg(T)),
- {Ts, S2} = mapfold_list(F, S1, map_es(T)),
- F(update_c_map(T, M, Ts), S2);
+ {M , S1} = mapfold(Pre, Post, S0, map_arg(T)),
+ {Ts, S2} = mapfold_list(Pre, Post, S1, map_es(T)),
+ Post(update_c_map(T, M, Ts), S2);
map_pair ->
- {Op, S1} = mapfold(F, S0, map_pair_op(T)),
- {Key, S2} = mapfold(F, S1, map_pair_key(T)),
- {Val, S3} = mapfold(F, S2, map_pair_val(T)),
- F(update_c_map_pair(T,Op,Key,Val), S3);
+ {Op, S1} = mapfold(Pre, Post, S0, map_pair_op(T)),
+ {Key, S2} = mapfold(Pre, Post, S1, map_pair_key(T)),
+ {Val, S3} = mapfold(Pre, Post, S2, map_pair_val(T)),
+ Post(update_c_map_pair(T,Op,Key,Val), S3);
'let' ->
- {Vs, S1} = mapfold_list(F, S0, let_vars(T)),
- {A, S2} = mapfold(F, S1, let_arg(T)),
- {B, S3} = mapfold(F, S2, let_body(T)),
- F(update_c_let(T, Vs, A, B), S3);
+ {Vs, S1} = mapfold_list(Pre, Post, S0, let_vars(T)),
+ {A, S2} = mapfold(Pre, Post, S1, let_arg(T)),
+ {B, S3} = mapfold(Pre, Post, S2, let_body(T)),
+ Post(update_c_let(T, Vs, A, B), S3);
seq ->
- {A, S1} = mapfold(F, S0, seq_arg(T)),
- {B, S2} = mapfold(F, S1, seq_body(T)),
- F(update_c_seq(T, A, B), S2);
+ {A, S1} = mapfold(Pre, Post, S0, seq_arg(T)),
+ {B, S2} = mapfold(Pre, Post, S1, seq_body(T)),
+ Post(update_c_seq(T, A, B), S2);
apply ->
- {E, S1} = mapfold(F, S0, apply_op(T)),
- {As, S2} = mapfold_list(F, S1, apply_args(T)),
- F(update_c_apply(T, E, As), S2);
+ {E, S1} = mapfold(Pre, Post, S0, apply_op(T)),
+ {As, S2} = mapfold_list(Pre, Post, S1, apply_args(T)),
+ Post(update_c_apply(T, E, As), S2);
call ->
- {M, S1} = mapfold(F, S0, call_module(T)),
- {N, S2} = mapfold(F, S1, call_name(T)),
- {As, S3} = mapfold_list(F, S2, call_args(T)),
- F(update_c_call(T, M, N, As), S3);
+ {M, S1} = mapfold(Pre, Post, S0, call_module(T)),
+ {N, S2} = mapfold(Pre, Post, S1, call_name(T)),
+ {As, S3} = mapfold_list(Pre, Post, S2, call_args(T)),
+ Post(update_c_call(T, M, N, As), S3);
primop ->
- {N, S1} = mapfold(F, S0, primop_name(T)),
- {As, S2} = mapfold_list(F, S1, primop_args(T)),
- F(update_c_primop(T, N, As), S2);
+ {N, S1} = mapfold(Pre, Post, S0, primop_name(T)),
+ {As, S2} = mapfold_list(Pre, Post, S1, primop_args(T)),
+ Post(update_c_primop(T, N, As), S2);
'case' ->
- {A, S1} = mapfold(F, S0, case_arg(T)),
- {Cs, S2} = mapfold_list(F, S1, case_clauses(T)),
- F(update_c_case(T, A, Cs), S2);
+ {A, S1} = mapfold(Pre, Post, S0, case_arg(T)),
+ {Cs, S2} = mapfold_list(Pre, Post, S1, case_clauses(T)),
+ Post(update_c_case(T, A, Cs), S2);
clause ->
- {Ps, S1} = mapfold_list(F, S0, clause_pats(T)),
- {G, S2} = mapfold(F, S1, clause_guard(T)),
- {B, S3} = mapfold(F, S2, clause_body(T)),
- F(update_c_clause(T, Ps, G, B), S3);
+ {Ps, S1} = mapfold_list(Pre, Post, S0, clause_pats(T)),
+ {G, S2} = mapfold(Pre, Post, S1, clause_guard(T)),
+ {B, S3} = mapfold(Pre, Post, S2, clause_body(T)),
+ Post(update_c_clause(T, Ps, G, B), S3);
alias ->
- {V, S1} = mapfold(F, S0, alias_var(T)),
- {P, S2} = mapfold(F, S1, alias_pat(T)),
- F(update_c_alias(T, V, P), S2);
+ {V, S1} = mapfold(Pre, Post, S0, alias_var(T)),
+ {P, S2} = mapfold(Pre, Post, S1, alias_pat(T)),
+ Post(update_c_alias(T, V, P), S2);
'fun' ->
- {Vs, S1} = mapfold_list(F, S0, fun_vars(T)),
- {B, S2} = mapfold(F, S1, fun_body(T)),
- F(update_c_fun(T, Vs, B), S2);
+ {Vs, S1} = mapfold_list(Pre, Post, S0, fun_vars(T)),
+ {B, S2} = mapfold(Pre, Post, S1, fun_body(T)),
+ Post(update_c_fun(T, Vs, B), S2);
'receive' ->
- {Cs, S1} = mapfold_list(F, S0, receive_clauses(T)),
- {E, S2} = mapfold(F, S1, receive_timeout(T)),
- {A, S3} = mapfold(F, S2, receive_action(T)),
- F(update_c_receive(T, Cs, E, A), S3);
+ {Cs, S1} = mapfold_list(Pre, Post, S0, receive_clauses(T)),
+ {E, S2} = mapfold(Pre, Post, S1, receive_timeout(T)),
+ {A, S3} = mapfold(Pre, Post, S2, receive_action(T)),
+ Post(update_c_receive(T, Cs, E, A), S3);
'try' ->
- {E, S1} = mapfold(F, S0, try_arg(T)),
- {Vs, S2} = mapfold_list(F, S1, try_vars(T)),
- {B, S3} = mapfold(F, S2, try_body(T)),
- {Evs, S4} = mapfold_list(F, S3, try_evars(T)),
- {H, S5} = mapfold(F, S4, try_handler(T)),
- F(update_c_try(T, E, Vs, B, Evs, H), S5);
+ {E, S1} = mapfold(Pre, Post, S0, try_arg(T)),
+ {Vs, S2} = mapfold_list(Pre, Post, S1, try_vars(T)),
+ {B, S3} = mapfold(Pre, Post, S2, try_body(T)),
+ {Evs, S4} = mapfold_list(Pre, Post, S3, try_evars(T)),
+ {H, S5} = mapfold(Pre, Post, S4, try_handler(T)),
+ Post(update_c_try(T, E, Vs, B, Evs, H), S5);
'catch' ->
- {B, S1} = mapfold(F, S0, catch_body(T)),
- F(update_c_catch(T, B), S1);
+ {B, S1} = mapfold(Pre, Post, S0, catch_body(T)),
+ Post(update_c_catch(T, B), S1);
binary ->
- {Ds, S1} = mapfold_list(F, S0, binary_segments(T)),
- F(update_c_binary(T, Ds), S1);
+ {Ds, S1} = mapfold_list(Pre, Post, S0, binary_segments(T)),
+ Post(update_c_binary(T, Ds), S1);
bitstr ->
- {Val, S1} = mapfold(F, S0, bitstr_val(T)),
- {Size, S2} = mapfold(F, S1, bitstr_size(T)),
- {Unit, S3} = mapfold(F, S2, bitstr_unit(T)),
- {Type, S4} = mapfold(F, S3, bitstr_type(T)),
- {Flags, S5} = mapfold(F, S4, bitstr_flags(T)),
- F(update_c_bitstr(T, Val, Size, Unit, Type, Flags), S5);
+ {Val, S1} = mapfold(Pre, Post, S0, bitstr_val(T)),
+ {Size, S2} = mapfold(Pre, Post, S1, bitstr_size(T)),
+ {Unit, S3} = mapfold(Pre, Post, S2, bitstr_unit(T)),
+ {Type, S4} = mapfold(Pre, Post, S3, bitstr_type(T)),
+ {Flags, S5} = mapfold(Pre, Post, S4, bitstr_flags(T)),
+ Post(update_c_bitstr(T, Val, Size, Unit, Type, Flags), S5);
letrec ->
- {Ds, S1} = mapfold_pairs(F, S0, letrec_defs(T)),
- {B, S2} = mapfold(F, S1, letrec_body(T)),
- F(update_c_letrec(T, Ds, B), S2);
+ {Ds, S1} = mapfold_pairs(Pre, Post, S0, letrec_defs(T)),
+ {B, S2} = mapfold(Pre, Post, S1, letrec_body(T)),
+ Post(update_c_letrec(T, Ds, B), S2);
module ->
- {N, S1} = mapfold(F, S0, module_name(T)),
- {Es, S2} = mapfold_list(F, S1, module_exports(T)),
- {As, S3} = mapfold_pairs(F, S2, module_attrs(T)),
- {Ds, S4} = mapfold_pairs(F, S3, module_defs(T)),
- F(update_c_module(T, N, Es, As, Ds), S4)
+ {N, S1} = mapfold(Pre, Post, S0, module_name(T)),
+ {Es, S2} = mapfold_list(Pre, Post, S1, module_exports(T)),
+ {As, S3} = mapfold_pairs(Pre, Post, S2, module_attrs(T)),
+ {Ds, S4} = mapfold_pairs(Pre, Post, S3, module_defs(T)),
+ Post(update_c_module(T, N, Es, As, Ds), S4)
end.
-mapfold_list(F, S0, [T | Ts]) ->
- {T1, S1} = mapfold(F, S0, T),
- {Ts1, S2} = mapfold_list(F, S1, Ts),
+mapfold_list(Pre, Post, S0, [T | Ts]) ->
+ {T1, S1} = mapfold(Pre, Post, S0, T),
+ {Ts1, S2} = mapfold_list(Pre, Post, S1, Ts),
{[T1 | Ts1], S2};
-mapfold_list(_, S, []) ->
+mapfold_list(_, _, S, []) ->
{[], S}.
-mapfold_pairs(F, S0, [{T1, T2} | Ps]) ->
- {T3, S1} = mapfold(F, S0, T1),
- {T4, S2} = mapfold(F, S1, T2),
- {Ps1, S3} = mapfold_pairs(F, S2, Ps),
+mapfold_pairs(Pre, Post, S0, [{T1, T2} | Ps]) ->
+ {T3, S1} = mapfold(Pre, Post, S0, T1),
+ {T4, S2} = mapfold(Pre, Post, S1, T2),
+ {Ps1, S3} = mapfold_pairs(Pre, Post, S2, Ps),
{[{T3, T4} | Ps1], S3};
-mapfold_pairs(_, S, []) ->
+mapfold_pairs(_, _, S, []) ->
{[], S}.
@@ -640,8 +662,8 @@ vars_in_list([], _, A) ->
vars_in_defs(Ds, S) ->
vars_in_defs(Ds, S, []).
-vars_in_defs([{_, F} | Ds], S, A) ->
- vars_in_defs(Ds, S, ordsets:union(variables(F, S), A));
+vars_in_defs([{_, Post} | Ds], S, A) ->
+ vars_in_defs(Ds, S, ordsets:union(variables(Post, S), A));
vars_in_defs([], _, A) ->
A.
@@ -703,13 +725,14 @@ label(T, N, Env) ->
%% Constant literals are not labeled.
{T, N};
var ->
- case dict:find(var_name(T), Env) of
- {ok, L} ->
- {As, _} = label_ann(T, L),
- N1 = N;
- error ->
- {As, N1} = label_ann(T, N)
- end,
+ {As, N1} =
+ case dict:find(var_name(T), Env) of
+ {ok, L} ->
+ {A, _} = label_ann(T, L),
+ {A, N};
+ error ->
+ label_ann(T, N)
+ end,
{set_ann(T, As), N1};
values ->
{Ts, N1} = label_list(values_es(T), N, Env),
@@ -725,10 +748,17 @@ label(T, N, Env) ->
{As, N2} = label_ann(T, N1),
{ann_c_tuple_skel(As, Ts), N2};
map ->
- {M, N1} = label(map_arg(T), N, Env),
- {Ts, N2} = label_list(map_es(T), N1, Env),
- {As, N3} = label_ann(T, N2),
- {ann_c_map(As, M, Ts), N3};
+ case is_c_map_pattern(T) of
+ false ->
+ {M, N1} = label(map_arg(T), N, Env),
+ {Ts, N2} = label_list(map_es(T), N1, Env),
+ {As, N3} = label_ann(T, N2),
+ {ann_c_map(As, M, Ts), N3};
+ true ->
+ {Ts, N1} = label_list(map_es(T), N, Env),
+ {As, N2} = label_ann(T, N1),
+ {ann_c_map_pattern(As, Ts), N2}
+ end;
map_pair ->
{Op, N1} = label(map_pair_op(T), N, Env),
{Key, N2} = label(map_pair_key(T), N1, Env),
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index e0a29fe9b1..aa2d224bb4 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. 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.
@@ -26,6 +26,7 @@
-export([forms/1,forms/2,noenv_forms/2]).
-export([output_generated/1,noenv_output_generated/1]).
-export([options/0]).
+-export([env_compiler_options/0]).
%% Erlc interface.
-export([compile/3,compile_beam/3,compile_asm/3,compile_core/3]).
@@ -40,6 +41,12 @@
%%----------------------------------------------------------------------
+-type abstract_code() :: [erl_parse:abstract_form()].
+
+%% Internal representations used for 'from_asm' and 'from_beam' compilation can
+%% also be valid, but have no relevant types defined.
+-type forms() :: abstract_code() | cerl:c_module().
+
-type option() :: atom() | {atom(), term()} | {'d', atom(), term()}.
-type err_info() :: {erl_anno:line() | 'none',
@@ -48,6 +55,9 @@
-type warnings() :: [{file:filename(), [err_info()]}].
-type mod_ret() :: {'ok', module()}
| {'ok', module(), cerl:c_module()} %% with option 'to_core'
+ | {'ok', %% with option 'to_pp'
+ module() | [], %% module() if 'to_exp'
+ abstract_code()}
| {'ok', module(), warnings()}.
-type bin_ret() :: {'ok', module(), binary()}
| {'ok', module(), binary(), warnings()}.
@@ -78,7 +88,11 @@ file(File, Opts) when is_list(Opts) ->
file(File, Opt) ->
file(File, [Opt|?DEFAULT_OPTIONS]).
-forms(File) -> forms(File, ?DEFAULT_OPTIONS).
+-spec forms(abstract_code()) -> comp_ret().
+
+forms(Forms) -> forms(Forms, ?DEFAULT_OPTIONS).
+
+-spec forms(forms(), [option()] | option()) -> comp_ret().
forms(Forms, Opts) when is_list(Opts) ->
do_compile({forms,Forms}, [binary|Opts++env_default_opts()]);
@@ -106,6 +120,8 @@ noenv_file(File, Opts) when is_list(Opts) ->
noenv_file(File, Opt) ->
noenv_file(File, [Opt|?DEFAULT_OPTIONS]).
+-spec noenv_forms(forms(), [option()] | option()) -> comp_ret().
+
noenv_forms(Forms, Opts) when is_list(Opts) ->
do_compile({forms,Forms}, [binary|Opts]);
noenv_forms(Forms, Opt) when is_atom(Opt) ->
@@ -120,11 +136,19 @@ noenv_output_generated(Opts) ->
end, Passes).
%%
+%% Retrieve ERL_COMPILER_OPTIONS as a list of terms
+%%
+
+-spec env_compiler_options() -> [term()].
+
+env_compiler_options() -> env_default_opts().
+
+%%
%% Local functions
%%
--define(pass(P), {P,fun P/1}).
--define(pass(P,T), {P,fun T/1,fun P/1}).
+-define(pass(P), {P,fun P/2}).
+-define(pass(P,T), {P,fun T/1,fun P/2}).
env_default_opts() ->
Key = "ERL_COMPILER_OPTIONS",
@@ -149,26 +173,34 @@ env_default_opts() ->
do_compile(Input, Opts0) ->
Opts = expand_opts(Opts0),
- {Pid,Ref} =
- spawn_monitor(fun() ->
- exit(try
- internal(Input, Opts)
- catch
- error:Reason ->
- {error,Reason}
- end)
- end),
- receive
- {'DOWN',Ref,process,Pid,Rep} -> Rep
+ IntFun = fun() -> try
+ internal(Input, Opts)
+ catch
+ error:Reason ->
+ {error,Reason}
+ end
+ end,
+ %% Dialyzer has already spawned workers.
+ case lists:member(dialyzer, Opts) of
+ true ->
+ IntFun();
+ false ->
+ {Pid,Ref} =
+ spawn_monitor(fun() ->
+ exit(IntFun())
+ end),
+ receive
+ {'DOWN',Ref,process,Pid,Rep} -> Rep
+ end
end.
expand_opts(Opts0) ->
%% {debug_info_key,Key} implies debug_info.
Opts = case {proplists:get_value(debug_info_key, Opts0),
proplists:get_value(encrypt_debug_info, Opts0),
- proplists:get_bool(debug_info, Opts0)} of
+ proplists:get_value(debug_info, Opts0)} of
{undefined,undefined,_} -> Opts0;
- {_,_,false} -> [debug_info|Opts0];
+ {_,_,undefined} -> [debug_info|Opts0];
{_,_,_} -> Opts0
end,
foldr(fun expand_opt/2, [], Opts).
@@ -181,12 +213,14 @@ expand_opt(report, Os) ->
[report_errors,report_warnings|Os];
expand_opt(return, Os) ->
[return_errors,return_warnings|Os];
-expand_opt(r12, Os) ->
- [no_recv_opt,no_line_info|Os];
-expand_opt(r13, Os) ->
- [no_recv_opt,no_line_info|Os];
-expand_opt(r14, Os) ->
- [no_line_info|Os];
+expand_opt(r16, Os) ->
+ [no_record_opt,no_utf8_atoms|Os];
+expand_opt(r17, Os) ->
+ [no_record_opt,no_utf8_atoms|Os];
+expand_opt(r18, Os) ->
+ [no_record_opt,no_utf8_atoms|Os];
+expand_opt(r19, Os) ->
+ [no_record_opt,no_utf8_atoms|Os];
expand_opt({debug_info_key,_}=O, Os) ->
[encrypt_debug_info,O|Os];
expand_opt(no_float_opt, Os) ->
@@ -196,6 +230,8 @@ expand_opt(O, Os) -> [O|Os].
%% format_error(ErrorDescriptor) -> string()
+-spec format_error(term()) -> iolist().
+
format_error(no_native_support) ->
"this system is not configured for native-code compilation.";
format_error(no_crypto) ->
@@ -216,6 +252,8 @@ format_error({epp,E}) ->
epp:format_error(E);
format_error(write_error) ->
"error writing file";
+format_error({write_error, Error}) ->
+ io_lib:format("error writing file: ~ts", [file:format_error(Error)]);
format_error({rename,From,To,Error}) ->
io_lib:format("failed to rename ~ts to ~ts: ~ts",
[From,To,file:format_error(Error)]);
@@ -226,9 +264,9 @@ format_error({delete_temp,File,Error}) ->
io_lib:format("failed to delete temporary file ~ts: ~ts",
[File,file:format_error(Error)]);
format_error({parse_transform,M,R}) ->
- io_lib:format("error in parse transform '~s': ~tp", [M, R]);
+ io_lib:format("error in parse transform '~ts': ~tp", [M, R]);
format_error({undef_parse_transform,M}) ->
- io_lib:format("undefined parse transform '~s'", [M]);
+ io_lib:format("undefined parse transform '~ts'", [M]);
format_error({core_transform,M,R}) ->
io_lib:format("error in core transform '~s': ~tp", [M, R]);
format_error({crash,Pass,Reason}) ->
@@ -254,34 +292,41 @@ format_error_reason({Reason, Stack}) when is_list(Stack) ->
format_error_reason(Reason) ->
io_lib:format("~tp", [Reason]).
+-type err_warn_info() :: tuple().
+
%% The compile state record.
-record(compile, {filename="" :: file:filename(),
dir="" :: file:filename(),
base="" :: file:filename(),
ifile="" :: file:filename(),
ofile="" :: file:filename(),
- module=[],
- code=[],
- core_code=[],
- abstract_code=[], %Abstract code for debugger.
- options=[] :: [option()], %Options for compilation
+ module=[] :: module() | [],
+ core_code=[] :: cerl:c_module() | [],
+ abstract_code=[] :: abstract_code(), %Abstract code for debugger.
+ options=[] :: [option()], %Options for compilation
mod_options=[] :: [option()], %Options for module_info
encoding=none :: none | epp:source_encoding(),
- errors=[],
- warnings=[]}).
+ errors=[] :: [err_warn_info()],
+ warnings=[] :: [err_warn_info()],
+ extra_chunks=[] :: [{binary(), binary()}]}).
internal({forms,Forms}, Opts0) ->
{_,Ps} = passes(forms, Opts0),
Source = proplists:get_value(source, Opts0, ""),
Opts1 = proplists:delete(source, Opts0),
- Compile = #compile{code=Forms,options=Opts1,mod_options=Opts1},
- internal_comp(Ps, Source, "", Compile);
+ Compile = build_compile(Opts1),
+ internal_comp(Ps, Forms, Source, "", Compile);
internal({file,File}, Opts) ->
{Ext,Ps} = passes(file, Opts),
- Compile = #compile{options=Opts,mod_options=Opts},
- internal_comp(Ps, File, Ext, Compile).
+ Compile = build_compile(Opts),
+ internal_comp(Ps, none, File, Ext, Compile).
+
+build_compile(Opts0) ->
+ ExtraChunks = proplists:get_value(extra_chunks, Opts0, []),
+ Opts1 = proplists:delete(extra_chunks, Opts0),
+ #compile{options=Opts1,mod_options=Opts1,extra_chunks=ExtraChunks}.
-internal_comp(Passes, File, Suffix, St0) ->
+internal_comp(Passes, Code0, File, Suffix, St0) ->
Dir = filename:dirname(File),
Base = filename:basename(File, Suffix),
St1 = St0#compile{filename=File, dir=Dir, base=Base,
@@ -291,36 +336,41 @@ internal_comp(Passes, File, Suffix, St0) ->
Run0 = case member(time, Opts) of
true ->
io:format("Compiling ~tp\n", [File]),
- fun run_tc/2;
- false -> fun({_Name,Fun}, St) -> catch Fun(St) end
+ fun run_tc/3;
+ false ->
+ fun({_Name,Fun}, Code, St) ->
+ catch Fun(Code, St)
+ end
end,
Run = case keyfind(eprof, 1, Opts) of
{eprof,EprofPass} ->
- fun(P, St) ->
- run_eprof(P, EprofPass, St)
+ fun(P, Code, St) ->
+ run_eprof(P, Code, EprofPass, St)
end;
false ->
Run0
end,
- case fold_comp(Passes, Run, St1) of
- {ok,St2} -> comp_ret_ok(St2);
+ case fold_comp(Passes, Run, Code0, St1) of
+ {ok,Code,St2} -> comp_ret_ok(Code, St2);
{error,St2} -> comp_ret_err(St2)
end.
-fold_comp([{delay,Ps0}|Passes], Run, #compile{options=Opts}=St) ->
+fold_comp([{delay,Ps0}|Passes], Run, Code, #compile{options=Opts}=St) ->
Ps = select_passes(Ps0, Opts) ++ Passes,
- fold_comp(Ps, Run, St);
-fold_comp([{Name,Test,Pass}|Ps], Run, St) ->
+ fold_comp(Ps, Run, Code, St);
+fold_comp([{Name,Test,Pass}|Ps], Run, Code, St) ->
case Test(St) of
false -> %Pass is not needed.
- fold_comp(Ps, Run, St);
+ fold_comp(Ps, Run, Code, St);
true -> %Run pass in the usual way.
- fold_comp([{Name,Pass}|Ps], Run, St)
+ fold_comp([{Name,Pass}|Ps], Run, Code, St)
end;
-fold_comp([{Name,Pass}|Ps], Run, St0) ->
- case Run({Name,Pass}, St0) of
- {ok,St1} -> fold_comp(Ps, Run, St1);
- {error,_St1} = Error -> Error;
+fold_comp([{Name,Pass}|Ps], Run, Code0, St0) ->
+ case Run({Name,Pass}, Code0, St0) of
+ {ok,Code,St1} ->
+ fold_comp(Ps, Run, Code, St1);
+ {error,_St1}=Error ->
+ Error;
{'EXIT',Reason} ->
Es = [{St0#compile.ifile,[{none,?MODULE,{crash,Name,Reason}}]}],
{error,St0#compile{errors=St0#compile.errors ++ Es}};
@@ -328,30 +378,30 @@ fold_comp([{Name,Pass}|Ps], Run, St0) ->
Es = [{St0#compile.ifile,[{none,?MODULE,{bad_return,Name,Other}}]}],
{error,St0#compile{errors=St0#compile.errors ++ Es}}
end;
-fold_comp([], _Run, St) -> {ok,St}.
+fold_comp([], _Run, Code, St) -> {ok,Code,St}.
-run_tc({Name,Fun}, St) ->
+run_tc({Name,Fun}, Code, St) ->
T1 = erlang:monotonic_time(),
- Val = (catch Fun(St)),
+ Val = (catch Fun(Code, St)),
T2 = erlang:monotonic_time(),
- Elapsed = erlang:convert_time_unit(T2 - T1, native, milli_seconds),
+ Elapsed = erlang:convert_time_unit(T2 - T1, native, millisecond),
Mem0 = erts_debug:flat_size(Val)*erlang:system_info(wordsize),
Mem = lists:flatten(io_lib:format("~.1f kB", [Mem0/1024])),
io:format(" ~-30s: ~10.3f s ~12s\n",
[Name,Elapsed/1000,Mem]),
Val.
-run_eprof({Name,Fun}, Name, St) ->
+run_eprof({Name,Fun}, Code, Name, St) ->
io:format("~p: Running eprof\n", [Name]),
c:appcall(tools, eprof, start_profiling, [[self()]]),
- Val = (catch Fun(St)),
+ Val = (catch Fun(Code, St)),
c:appcall(tools, eprof, stop_profiling, []),
c:appcall(tools, eprof, analyze, []),
Val;
-run_eprof({_,Fun}, _, St) ->
- catch Fun(St).
+run_eprof({_,Fun}, Code, _, St) ->
+ catch Fun(Code, St).
-comp_ret_ok(#compile{code=Code,warnings=Warn0,module=Mod,options=Opts}=St) ->
+comp_ret_ok(Code, #compile{warnings=Warn0,module=Mod,options=Opts}=St) ->
case werror(St) of
true ->
case member(report_warnings, Opts) of
@@ -417,8 +467,10 @@ mpf(Ms) ->
passes(Type, Opts) ->
{Ext,Passes0} = passes_1(Opts),
Passes1 = case Type of
- file -> Passes0;
- forms -> tl(Passes0)
+ file ->
+ Passes0;
+ forms ->
+ fix_first_pass(Passes0)
end,
Passes = select_passes(Passes1, Opts),
@@ -455,6 +507,22 @@ pass(from_beam) ->
{".beam",[?pass(read_beam_file)|binary_passes()]};
pass(_) -> none.
+%% For compilation from forms, replace the first pass with a pass
+%% that retrieves the module name. The module name is needed for
+%% proper diagnostics and for compilation to native code.
+
+fix_first_pass([{parse_core,_}|Passes]) ->
+ [?pass(get_module_name_from_core)|Passes];
+fix_first_pass([{beam_consult_asm,_}|Passes]) ->
+ [?pass(get_module_name_from_asm)|Passes];
+fix_first_pass([{read_beam_file,_}|Passes]) ->
+ [?pass(get_module_name_from_beam)|Passes];
+fix_first_pass([_|Passes]) ->
+ %% When compiling from abstract code, the module name
+ %% will be set after running the v3_core pass.
+ Passes.
+
+
%% select_passes([Command], Opts) -> [{Name,Function}]
%% Interpret the lists of commands to return a pure list of passes.
%%
@@ -506,21 +574,21 @@ pass(_) -> none.
%%
select_passes([{pass,Mod}|Ps], Opts) ->
- F = fun(St) ->
- case catch Mod:module(St#compile.code, St#compile.options) of
+ F = fun(Code0, St) ->
+ case catch Mod:module(Code0, St#compile.options) of
{ok,Code} ->
- {ok,St#compile{code=Code}};
+ {ok,Code,St};
{ok,Code,Ws} ->
- {ok,St#compile{code=Code,warnings=St#compile.warnings++Ws}};
+ {ok,Code,St#compile{warnings=St#compile.warnings++Ws}};
{error,Es} ->
{error,St#compile{errors=St#compile.errors ++ Es}}
end
end,
[{Mod,F}|select_passes(Ps, Opts)];
select_passes([{src_listing,Ext}|_], _Opts) ->
- [{listing,fun (St) -> src_listing(Ext, St) end}];
+ [{listing,fun (Code, St) -> src_listing(Ext, Code, St) end}];
select_passes([{listing,Ext}|_], _Opts) ->
- [{listing,fun (St) -> listing(Ext, St) end}];
+ [{listing,fun (Code, St) -> listing(Ext, Code, St) end}];
select_passes([done|_], _Opts) ->
[];
select_passes([{done,Ext}|_], Opts) ->
@@ -620,13 +688,13 @@ standard_passes() ->
{iff,'dabstr',{listing,"abstr"}},
{iff,debug_info,?pass(save_abstract_code)},
- ?pass(expand_module),
+ ?pass(expand_records),
{iff,'dexp',{listing,"expand"}},
{iff,'E',{src_listing,"E"}},
{iff,'to_exp',{done,"E"}},
%% Conversion to Core Erlang.
- {pass,v3_core},
+ ?pass(core),
{iff,'dcore',{listing,"core"}},
{iff,'to_core0',{done,"core"}}
| core_passes()].
@@ -636,29 +704,31 @@ core_passes() ->
[{iff,clint0,?pass(core_lint_module)},
{delay,
[{unless,no_copt,
- [{core_old_inliner,fun test_old_inliner/1,fun core_old_inliner/1},
+ [{core_old_inliner,fun test_old_inliner/1,fun core_old_inliner/2},
{iff,doldinline,{listing,"oldinline"}},
{pass,sys_core_fold},
{iff,dcorefold,{listing,"corefold"}},
- {core_inline_module,fun test_core_inliner/1,fun core_inline_module/1},
+ {core_inline_module,fun test_core_inliner/1,fun core_inline_module/2},
{iff,dinline,{listing,"inline"}},
{core_fold_after_inlining,fun test_any_inliner/1,
- fun core_fold_module_after_inlining/1},
+ fun core_fold_module_after_inlining/2},
?pass(core_transforms)]},
{iff,dcopt,{listing,"copt"}},
{iff,'to_core',{done,"core"}}]}
| kernel_passes()].
kernel_passes() ->
- %% Destructive setelement/3 optimization and core lint.
- [{pass,sys_core_dsetel},
+ %% Optimizations that must be done after all other optimizations.
+ [{pass,sys_core_bsm},
+ {iff,dcbsm,{listing,"core_bsm"}},
+ {pass,sys_core_dsetel},
{iff,dsetel,{listing,"dsetel"}},
{iff,clint,?pass(core_lint_module)},
{iff,core,?pass(save_core_code)},
%% Kernel Erlang and code generation.
- {pass,v3_kernel},
+ ?pass(v3_kernel),
{iff,dkern,{listing,"kernel"}},
{iff,'to_kernel',{done,"kernel"}},
{pass,v3_life},
@@ -671,13 +741,16 @@ asm_passes() ->
%% Assembly level optimisations.
[{delay,
[{pass,beam_a},
+ {iff,da,{listing,"a"}},
{unless,no_postopt,
- [{pass,beam_block},
+ [{unless,no_reorder,{pass,beam_reorder}},
+ {iff,dre,{listing,"reorder"}},
+ {pass,beam_block},
{iff,dblk,{listing,"block"}},
{unless,no_except,{pass,beam_except}},
{iff,dexcept,{listing,"except"}},
- {unless,no_bopt,{pass,beam_bool}},
- {iff,dbool,{listing,"bool"}},
+ {unless,no_bs_opt,{pass,beam_bs}},
+ {iff,dbs,{listing,"bs"}},
{unless,no_topt,{pass,beam_type}},
{iff,dtype,{listing,"type"}},
{pass,beam_split},
@@ -694,6 +767,8 @@ asm_passes() ->
{iff,dbsm,{listing,"bsm"}},
{unless,no_recv_opt,{pass,beam_receive}},
{iff,drecv,{listing,"recv"}},
+ {unless,no_record_opt,{pass,beam_record}},
+ {iff,drecord,{listing,"record"}},
{unless,no_stack_trimming,{pass,beam_trim}},
{iff,dtrim,{listing,"trim"}},
{pass,beam_flatten}]},
@@ -703,6 +778,7 @@ asm_passes() ->
{iff,no_postopt,[{pass,beam_clean}]},
{pass,beam_z},
+ {iff,dz,{listing,"z"}},
{iff,dopt,{listing,"optimize"}},
{iff,'S',{listing,"S"}},
{iff,'to_asm',{done,"S"}}]},
@@ -711,7 +787,7 @@ asm_passes() ->
| binary_passes()].
binary_passes() ->
- [{native_compile,fun test_native/1,fun native_compile/1},
+ [{native_compile,fun test_native/1,fun native_compile/2},
{unless,binary,?pass(save_binary,not_werror)}].
%%%
@@ -719,9 +795,9 @@ binary_passes() ->
%%%
%% Remove the target file so we don't have an old one if the compilation fail.
-remove_file(St) ->
+remove_file(Code, St) ->
_ = file:delete(St#compile.ofile),
- {ok,St}.
+ {ok,Code,St}.
-record(asm_module, {module,
exports,
@@ -769,34 +845,50 @@ collect_asm([{attributes, Attr} | Rest], R) ->
collect_asm([X | Rest], R) ->
collect_asm(Rest, R#asm_module{code=R#asm_module.code++[X]}).
-beam_consult_asm(St) ->
+beam_consult_asm(_Code, St) ->
case file:consult(St#compile.ifile) of
- {ok, Forms0} ->
+ {ok,Forms0} ->
Encoding = epp:read_encoding(St#compile.ifile),
- {Module, Forms} = preprocess_asm_forms(Forms0),
- {ok,St#compile{module=Module, code=Forms, encoding=Encoding}};
+ {Module,Forms} = preprocess_asm_forms(Forms0),
+ {ok,Forms,St#compile{module=Module,encoding=Encoding}};
{error,E} ->
Es = [{St#compile.ifile,[{none,?MODULE,{open,E}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
-read_beam_file(St) ->
+get_module_name_from_asm({Mod,_,_,_,_}=Asm, St) ->
+ {ok,Asm,St#compile{module=Mod}};
+get_module_name_from_asm(Asm, St) ->
+ %% Invalid Beam assembly code. Let it crash in a later pass.
+ {ok,Asm,St}.
+
+read_beam_file(_Code, St) ->
case file:read_file(St#compile.ifile) of
{ok,Beam} ->
Infile = St#compile.ifile,
case no_native_compilation(Infile, St) of
true ->
- {ok,St#compile{module=none,code=none}};
+ {ok,none,St#compile{module=none}};
false ->
Mod0 = filename:rootname(filename:basename(Infile)),
Mod = list_to_atom(Mod0),
- {ok,St#compile{module=Mod,code=Beam,ofile=Infile}}
+ {ok,Beam,St#compile{module=Mod,ofile=Infile}}
end;
{error,E} ->
Es = [{St#compile.ifile,[{none,?MODULE,{open,E}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
+get_module_name_from_beam(Beam, St) ->
+ case beam_lib:info(Beam) of
+ {error,beam_lib,Error} ->
+ Es = [{"((forms))",[{none,beam_lib,Error}]}],
+ {error,St#compile{errors=St#compile.errors ++ Es}};
+ Info ->
+ {module,Mod} = keyfind(module, 1, Info),
+ {ok,Beam,St#compile{module=Mod}}
+ end.
+
no_native_compilation(BeamFile, #compile{options=Opts0}) ->
case beam_lib:chunks(BeamFile, ["CInf"]) of
{ok,{_,[{"CInf",Term0}]}} ->
@@ -809,17 +901,17 @@ no_native_compilation(BeamFile, #compile{options=Opts0}) ->
_ -> false
end.
-parse_module(St0) ->
+parse_module(_Code, St0) ->
case do_parse_module(utf8, St0) of
- {ok,_}=Ret ->
+ {ok,_,_}=Ret ->
Ret;
{error,_}=Ret ->
Ret;
{invalid_unicode,File,Line} ->
case do_parse_module(latin1, St0) of
- {ok,St} ->
+ {ok,Code,St} ->
Es = [{File,[{Line,?MODULE,reparsing_invalid_unicode}]}],
- {ok,St#compile{warnings=Es++St#compile.warnings}};
+ {ok,Code,St#compile{warnings=Es++St#compile.warnings}};
{error,St} ->
Es = [{File,[{Line,?MODULE,reparsing_invalid_unicode}]}],
{error,St#compile{errors=Es++St#compile.errors}}
@@ -837,13 +929,13 @@ do_parse_module(DefEncoding, #compile{ifile=File,options=Opts,dir=Dir}=St) ->
Encoding = proplists:get_value(encoding, Extra),
case find_invalid_unicode(Forms, File) of
none ->
- {ok,St#compile{code=Forms,encoding=Encoding}};
+ {ok,Forms,St#compile{encoding=Encoding}};
{invalid_unicode,_,_}=Ret ->
case Encoding of
none ->
Ret;
_ ->
- {ok,St#compile{code=Forms,encoding=Encoding}}
+ {ok,Forms,St#compile{encoding=Encoding}}
end
end;
{error,E} ->
@@ -862,7 +954,7 @@ find_invalid_unicode([H|T], File0) ->
end;
find_invalid_unicode([], _) -> none.
-parse_core(St) ->
+parse_core(_Code, St) ->
case file:read_file(St#compile.ifile) of
{ok,Bin} ->
case core_scan:string(binary_to_list(Bin)) of
@@ -870,7 +962,7 @@ parse_core(St) ->
case core_parse:parse(Toks) of
{ok,Mod} ->
Name = (Mod#c_module.name)#c_literal.val,
- {ok,St#compile{module=Name,code=Mod}};
+ {ok,Mod,St#compile{module=Name}};
{error,E} ->
Es = [{St#compile.ifile,[E]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
@@ -884,6 +976,16 @@ parse_core(St) ->
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
+get_module_name_from_core(Core, St) ->
+ try
+ Mod = cerl:concrete(cerl:module_name(Core)),
+ {ok,Core,St#compile{module=Mod}}
+ catch
+ _:_ ->
+ %% Invalid Core Erlang code. Let it crash in a later pass.
+ {ok,Core,St}
+ end.
+
compile_options([{attribute,_L,compile,C}|Fs]) when is_list(C) ->
C ++ compile_options(Fs);
compile_options([{attribute,_L,compile,C}|Fs]) ->
@@ -907,31 +1009,36 @@ clean_parse_transforms_1([], Acc) -> reverse(Acc).
transforms(Os) -> [ M || {parse_transform,M} <- Os ].
-transform_module(#compile{options=Opt,code=Code0}=St0) ->
+transform_module(Code0, #compile{options=Opt}=St) ->
%% Extract compile options from code into options field.
case transforms(Opt ++ compile_options(Code0)) of
- [] -> {ok,St0}; %No parse transforms.
+ [] ->
+ %% No parse transforms.
+ {ok,Code0,St};
Ts ->
%% Remove parse_transform attributes from the abstract code to
%% prevent parse transforms to be run more than once.
Code = clean_parse_transforms(Code0),
- St = St0#compile{code=Code},
- foldl_transform(St, Ts)
+ foldl_transform(Ts, Code, St)
end.
-foldl_transform(St, [T|Ts]) ->
+foldl_transform([T|Ts], Code0, St) ->
Name = "transform " ++ atom_to_list(T),
case code:ensure_loaded(T) =:= {module,T} andalso
- erlang:function_exported(T, parse_transform, 2) of
+ erlang:function_exported(T, parse_transform, 2) of
true ->
- Fun = fun(S) ->
- T:parse_transform(S#compile.code, S#compile.options)
+ Fun = fun(Code, S) ->
+ T:parse_transform(Code, S#compile.options)
end,
Run = case member(time, St#compile.options) of
- true -> fun run_tc/2;
- false -> fun({_Name,F}, S) -> catch F(S) end
+ true ->
+ fun run_tc/3;
+ false ->
+ fun({_Name,F}, Code, S) ->
+ catch F(Code, S)
+ end
end,
- case Run({Name, Fun}, St) of
+ case Run({Name, Fun}, Code0, St) of
{error,Es,Ws} ->
{error,St#compile{warnings=St#compile.warnings ++ Ws,
errors=St#compile.errors ++ Es}};
@@ -940,41 +1047,44 @@ foldl_transform(St, [T|Ts]) ->
{parse_transform,T,R}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}};
{warning, Forms, Ws} ->
- foldl_transform(
- St#compile{code=Forms,
- warnings=St#compile.warnings ++ Ws}, Ts);
+ foldl_transform(Ts, Forms,
+ St#compile{warnings=St#compile.warnings ++ Ws});
Forms ->
- foldl_transform(St#compile{code=Forms}, Ts)
+ foldl_transform(Ts, Forms, St)
end;
false ->
Es = [{St#compile.ifile,[{none,compile,
{undef_parse_transform,T}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end;
-foldl_transform(St, []) -> {ok,St}.
+foldl_transform([], Code, St) -> {ok,Code,St}.
get_core_transforms(Opts) -> [M || {core_transform,M} <- Opts].
-core_transforms(St) ->
+core_transforms(Code, St) ->
%% The options field holds the complete list of options at this
Ts = get_core_transforms(St#compile.options),
- foldl_core_transforms(St, Ts).
+ foldl_core_transforms(Ts, Code, St).
-foldl_core_transforms(St, [T|Ts]) ->
+foldl_core_transforms([T|Ts], Code0, St) ->
Name = "core transform " ++ atom_to_list(T),
- Fun = fun(S) -> T:core_transform(S#compile.code, S#compile.options) end,
+ Fun = fun(Code, S) -> T:core_transform(Code, S#compile.options) end,
Run = case member(time, St#compile.options) of
- true -> fun run_tc/2;
- false -> fun({_Name,F}, S) -> catch F(S) end
+ true ->
+ fun run_tc/3;
+ false ->
+ fun({_Name,F}, Code, S) ->
+ catch F(Code, S)
+ end
end,
- case Run({Name, Fun}, St) of
+ case Run({Name, Fun}, Code0, St) of
{'EXIT',R} ->
Es = [{St#compile.ifile,[{none,compile,{core_transform,T,R}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}};
Forms ->
- foldl_core_transforms(St#compile{code=Forms}, Ts)
+ foldl_core_transforms(Ts, Forms, St)
end;
-foldl_core_transforms(St, []) -> {ok,St}.
+foldl_core_transforms([], Code, St) -> {ok,Code,St}.
%%% Fetches the module name from a list of forms. The module attribute must
%%% be present.
@@ -995,31 +1105,28 @@ add_default_base(St, Forms) ->
St
end.
-lint_module(St) ->
- case erl_lint:module(St#compile.code,
- St#compile.ifile, St#compile.options) of
+lint_module(Code, St) ->
+ case erl_lint:module(Code, St#compile.ifile, St#compile.options) of
{ok,Ws} ->
%% Insert name of module as base name, if needed. This is
%% for compile:forms to work with listing files.
- St1 = add_default_base(St, St#compile.code),
- {ok,St1#compile{warnings=St1#compile.warnings ++ Ws}};
+ St1 = add_default_base(St, Code),
+ {ok,Code,St1#compile{warnings=St1#compile.warnings ++ Ws}};
{error,Es,Ws} ->
{error,St#compile{warnings=St#compile.warnings ++ Ws,
errors=St#compile.errors ++ Es}}
end.
-core_lint_module(St) ->
- case core_lint:module(St#compile.code, St#compile.options) of
+core_lint_module(Code, St) ->
+ case core_lint:module(Code, St#compile.options) of
{ok,Ws} ->
- {ok,St#compile{warnings=St#compile.warnings ++ Ws}};
+ {ok,Code,St#compile{warnings=St#compile.warnings ++ Ws}};
{error,Es,Ws} ->
{error,St#compile{warnings=St#compile.warnings ++ Ws,
errors=St#compile.errors ++ Es}}
end.
-makedep(#compile{code=Code,options=Opts}=St) ->
- Ifile = St#compile.ifile,
- Ofile = St#compile.ofile,
+makedep(Code0, #compile{ifile=Ifile,ofile=Ofile,options=Opts}=St) ->
%% Get the target of the Makefile rule.
Target0 =
@@ -1051,7 +1158,7 @@ makedep(#compile{code=Code,options=Opts}=St) ->
%% List the dependencies (includes) for this target.
{MainRule,PhonyRules} = makedep_add_headers(
Ifile, % The input file name.
- Code, % The parsed source.
+ Code0, % The parsed source.
[], % The list of dependencies already added.
length(Target), % The current line length.
Target, % The target.
@@ -1071,7 +1178,8 @@ makedep(#compile{code=Code,options=Opts}=St) ->
true -> MainRule ++ PhonyRules;
_ -> MainRule
end,
- {ok,St#compile{code=iolist_to_binary([Makefile,"\n"])}}.
+ Code = iolist_to_binary([Makefile,"\n"]),
+ {ok,Code,St}.
makedep_add_headers(Ifile, [{attribute,_,file,{File,_}}|Rest],
Included, LineLen, MainTarget, Phony, Opts) ->
@@ -1136,7 +1244,7 @@ makedep_add_header(Ifile, Included, LineLen, MainTarget, Phony, File) ->
end
end.
-makedep_output(#compile{code=Code,options=Opts,ofile=Ofile}=St) ->
+makedep_output(Code, #compile{options=Opts,ofile=Ofile}=St) ->
%% Write this Makefile (Code) to the selected output.
%% If no output is specified, the default is to write to a file named after
%% the output file.
@@ -1178,9 +1286,9 @@ makedep_output(#compile{code=Code,options=Opts,ofile=Ofile}=St) ->
CloseOutput -> ok = file:close(Output1);
true -> ok
end,
- {ok,St}
+ {ok,Code,St}
catch
- exit:_ ->
+ error:_ ->
%% Couldn't write to output Makefile.
Err = {St#compile.ifile,[{none,?MODULE,write_error}]},
{error,St#compile{errors=St#compile.errors++[Err]}}
@@ -1195,19 +1303,34 @@ makedep_output(#compile{code=Code,options=Opts,ofile=Ofile}=St) ->
{error,St#compile{errors=St#compile.errors++[Err]}}
end.
-%% expand_module(State) -> State'
-%% Do the common preprocessing of the input forms.
+expand_records(Code0, #compile{options=Opts}=St) ->
+ Code = erl_expand_records:module(Code0, Opts),
+ {ok,Code,St}.
-expand_module(#compile{code=Code,options=Opts0}=St0) ->
- {Mod,Exp,Forms,Opts1} = sys_pre_expand:module(Code, Opts0),
+core(Forms, #compile{options=Opts0}=St) ->
+ Opts1 = lists:flatten([C || {attribute,_,compile,C} <- Forms] ++ Opts0),
Opts = expand_opts(Opts1),
- {ok,St0#compile{module=Mod,options=Opts,code={Mod,Exp,Forms}}}.
+ {ok,Core,Ws} = v3_core:module(Forms, Opts),
+ Mod = cerl:concrete(cerl:module_name(Core)),
+ {ok,Core,St#compile{module=Mod,options=Opts,
+ warnings=St#compile.warnings++Ws}}.
-core_fold_module_after_inlining(#compile{code=Code0,options=Opts}=St) ->
+core_fold_module_after_inlining(Code0, #compile{options=Opts}=St) ->
%% Inlining may produce code that generates spurious warnings.
%% Ignore all warnings.
{ok,Code,_Ws} = sys_core_fold:module(Code0, Opts),
- {ok,St#compile{code=Code}}.
+ {ok,Code,St}.
+
+v3_kernel(Code0, #compile{options=Opts,warnings=Ws0}=St) ->
+ {ok,Code,Ws} = v3_kernel:module(Code0, Opts),
+ case Ws =:= [] orelse test_core_inliner(St) of
+ false ->
+ {ok,Code,St#compile{warnings=Ws0++Ws}};
+ true ->
+ %% cerl_inline may produce code that generates spurious
+ %% warnings. Ignore any such warnings.
+ {ok,Code,St}
+ end.
test_old_inliner(#compile{options=Opts}) ->
%% The point of this test is to avoid loading the old inliner
@@ -1230,52 +1353,51 @@ test_core_inliner(#compile{options=Opts}) ->
test_any_inliner(St) ->
test_old_inliner(St) orelse test_core_inliner(St).
-core_old_inliner(#compile{code=Code0,options=Opts}=St) ->
+core_old_inliner(Code0, #compile{options=Opts}=St) ->
{ok,Code} = sys_core_inline:module(Code0, Opts),
- {ok,St#compile{code=Code}}.
+ {ok,Code,St}.
-core_inline_module(#compile{code=Code0,options=Opts}=St) ->
+core_inline_module(Code0, #compile{options=Opts}=St) ->
Code = cerl_inline:core_transform(Code0, Opts),
- {ok,St#compile{code=Code}}.
-
-save_abstract_code(#compile{ifile=File}=St) ->
- case abstract_code(St) of
- {ok,Code} ->
- {ok,St#compile{abstract_code=Code}};
- {error,Es} ->
- {error,St#compile{errors=St#compile.errors ++ [{File,Es}]}}
- end.
+ {ok,Code,St}.
+
+save_abstract_code(Code, St) ->
+ {ok,Code,St#compile{abstract_code=erl_parse:anno_to_term(Code)}}.
+
+debug_info(#compile{module=Module,mod_options=Opts0,ofile=OFile,abstract_code=Abst}) ->
+ AbstOpts = cleanup_compile_options(Opts0),
+ Opts1 = proplists:delete(debug_info, Opts0),
+ {Backend,Metadata,Opts2} =
+ case proplists:get_value(debug_info, Opts0, false) of
+ {OptBackend,OptMetadata} when is_atom(OptBackend) -> {OptBackend,OptMetadata,Opts1};
+ false -> {erl_abstract_code,{none,AbstOpts},Opts1};
+ true -> {erl_abstract_code,{Abst,AbstOpts},[debug_info | Opts1]}
+ end,
+ DebugInfo = erlang:term_to_binary({debug_info_v1,Backend,Metadata}, [compressed]),
-abstract_code(#compile{code=Code0,options=Opts,ofile=OFile}) ->
- Code = erl_parse:anno_to_term(Code0),
- Abstr = erlang:term_to_binary({raw_abstract_v1,Code}, [compressed]),
- case member(encrypt_debug_info, Opts) of
+ case member(encrypt_debug_info, Opts2) of
true ->
- case keyfind(debug_info_key, 1, Opts) of
- {_,Key} ->
- encrypt_abs_code(Abstr, Key);
+ case lists:keytake(debug_info_key, 1, Opts2) of
+ {value,{_, Key},Opts3} ->
+ encrypt_debug_info(DebugInfo, Key, [{debug_info_key,'********'} | Opts3]);
false ->
- %% Note: #compile.module has not been set yet.
- %% Here is an approximation that should work for
- %% all valid cases.
- Module = list_to_atom(filename:rootname(filename:basename(OFile))),
- Mode = proplists:get_value(crypto_mode, Opts, des3_cbc),
+ Mode = proplists:get_value(crypto_mode, Opts2, des3_cbc),
case beam_lib:get_crypto_key({debug_info, Mode, Module, OFile}) of
error ->
{error, [{none,?MODULE,no_crypto_key}]};
Key ->
- encrypt_abs_code(Abstr, {Mode, Key})
+ encrypt_debug_info(DebugInfo, {Mode, Key}, Opts2)
end
end;
false ->
- {ok, Abstr}
+ {ok,DebugInfo,Opts2}
end.
-encrypt_abs_code(Abstr, Key0) ->
+encrypt_debug_info(DebugInfo, Key, Opts) ->
try
- RealKey = generate_key(Key0),
+ RealKey = generate_key(Key),
case start_crypto() of
- ok -> {ok,encrypt(RealKey, Abstr)};
+ ok -> {ok,encrypt(RealKey, DebugInfo),Opts};
{error,_}=E -> E
end
catch
@@ -1283,6 +1405,18 @@ encrypt_abs_code(Abstr, Key0) ->
{error,[{none,?MODULE,bad_crypto_key}]}
end.
+cleanup_compile_options(Opts) ->
+ lists:filter(fun keep_compile_option/1, Opts).
+
+%% We are storing abstract, not asm or core.
+keep_compile_option(from_asm) -> false;
+keep_compile_option(from_core) -> false;
+%% Parse transform and macros have already been applied.
+keep_compile_option({parse_transform, _}) -> false;
+keep_compile_option({d, _, _}) -> false;
+%% Do not affect compilation result on future calls.
+keep_compile_option(Option) -> effects_code_generation(Option).
+
start_crypto() ->
try crypto:start() of
{error,{already_started,crypto}} -> ok;
@@ -1300,33 +1434,35 @@ generate_key(String) when is_list(String) ->
encrypt({des3_cbc=Type,Key,IVec,BlockSize}, Bin0) ->
Bin1 = case byte_size(Bin0) rem BlockSize of
0 -> Bin0;
- N -> list_to_binary([Bin0,random_bytes(BlockSize-N)])
+ N -> list_to_binary([Bin0,crypto:strong_rand_bytes(BlockSize-N)])
end,
Bin = crypto:block_encrypt(Type, Key, IVec, Bin1),
TypeString = atom_to_list(Type),
list_to_binary([0,length(TypeString),TypeString,Bin]).
-random_bytes(N) ->
- _ = random:seed(erlang:time_offset(),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- random_bytes_1(N, []).
-
-random_bytes_1(0, Acc) -> Acc;
-random_bytes_1(N, Acc) -> random_bytes_1(N-1, [random:uniform(255)|Acc]).
-
-save_core_code(St) ->
- {ok,St#compile{core_code=cerl:from_records(St#compile.code)}}.
-
-beam_asm(#compile{ifile=File,code=Code0,
- abstract_code=Abst,mod_options=Opts0}=St) ->
- Source = filename:absname(File),
- Opts1 = lists:map(fun({debug_info_key,_}) -> {debug_info_key,'********'};
- (Other) -> Other
- end, Opts0),
- Opts2 = [O || O <- Opts1, effects_code_generation(O)],
- case beam_asm:module(Code0, Abst, Source, Opts2) of
- {ok,Code} -> {ok,St#compile{code=Code,abstract_code=[]}}
+save_core_code(Code, St) ->
+ {ok,Code,St#compile{core_code=cerl:from_records(Code)}}.
+
+beam_asm(Code0, #compile{ifile=File,extra_chunks=ExtraChunks,options=CompilerOpts}=St) ->
+ case debug_info(St) of
+ {ok,DebugInfo,Opts0} ->
+ Source = paranoid_absname(File),
+ Opts1 = [O || O <- Opts0, effects_code_generation(O)],
+ Chunks = [{<<"Dbgi">>, DebugInfo} | ExtraChunks],
+ {ok,Code} = beam_asm:module(Code0, Chunks, Source, Opts1, CompilerOpts),
+ {ok,Code,St#compile{abstract_code=[]}};
+ {error,Es} ->
+ {error,St#compile{errors=St#compile.errors ++ [{File,Es}]}}
+ end.
+
+paranoid_absname(""=File) ->
+ File;
+paranoid_absname(File) ->
+ case file:get_cwd() of
+ {ok,Cwd} ->
+ filename:absname(File, Cwd);
+ _ ->
+ File
end.
test_native(#compile{options=Opts}) ->
@@ -1340,17 +1476,17 @@ is_native_enabled([no_native|_]) -> false;
is_native_enabled([_|Opts]) -> is_native_enabled(Opts);
is_native_enabled([]) -> false.
-native_compile(#compile{code=none}=St) -> {ok,St};
-native_compile(St) ->
+native_compile(none, St) -> {ok,none,St};
+native_compile(Code, St) ->
case erlang:system_info(hipe_architecture) of
undefined ->
Ws = [{St#compile.ifile,[{none,compile,no_native_support}]}],
- {ok,St#compile{warnings=St#compile.warnings ++ Ws}};
+ {ok,Code,St#compile{warnings=St#compile.warnings ++ Ws}};
_ ->
- native_compile_1(St)
+ native_compile_1(Code, St)
end.
-native_compile_1(St) ->
+native_compile_1(Code, St) ->
Opts0 = St#compile.options,
IgnoreErrors = member(ignore_native_errors, Opts0),
Opts = case keyfind(hipe, 1, Opts0) of
@@ -1360,10 +1496,10 @@ native_compile_1(St) ->
end,
try hipe:compile(St#compile.module,
St#compile.core_code,
- St#compile.code,
+ Code,
Opts) of
{ok,{_Type,Bin}=T} when is_binary(Bin) ->
- {ok,embed_native_code(St, T)};
+ {ok,embed_native_code(Code, T),St};
{error,R} ->
case IgnoreErrors of
true ->
@@ -1386,13 +1522,13 @@ native_compile_1(St) ->
end
end.
-embed_native_code(St, {Architecture,NativeCode}) ->
- {ok, _, Chunks0} = beam_lib:all_chunks(St#compile.code),
+embed_native_code(Code, {Architecture,NativeCode}) ->
+ {ok, _, Chunks0} = beam_lib:all_chunks(Code),
ChunkName = hipe_unified_loader:chunk_name(Architecture),
Chunks1 = lists:keydelete(ChunkName, 1, Chunks0),
Chunks = Chunks1 ++ [{ChunkName,NativeCode}],
- {ok, BeamPlusNative} = beam_lib:build_module(Chunks),
- St#compile{code=BeamPlusNative}.
+ {ok,BeamPlusNative} = beam_lib:build_module(Chunks),
+ BeamPlusNative.
%% effects_code_generation(Option) -> true|false.
%% Determine whether the option could have any effect on the
@@ -1400,30 +1536,31 @@ embed_native_code(St, {Architecture,NativeCode}) ->
%% errors will be reported).
effects_code_generation(Option) ->
- case Option of
+ case Option of
beam -> false;
report_warnings -> false;
report_errors -> false;
return_errors-> false;
return_warnings-> false;
+ warnings_as_errors -> false;
binary -> false;
verbose -> false;
{cwd,_} -> false;
+ {outdir, _} -> false;
_ -> true
end.
-save_binary(#compile{code=none}=St) -> {ok,St};
-save_binary(#compile{module=Mod,ofile=Outfile,
- options=Opts}=St) ->
+save_binary(none, St) -> {ok,none,St};
+save_binary(Code, #compile{module=Mod,ofile=Outfile,options=Opts}=St) ->
%% Test that the module name and output file name match.
case member(no_error_module_mismatch, Opts) of
true ->
- save_binary_1(St);
+ save_binary_1(Code, St);
false ->
Base = filename:rootname(filename:basename(Outfile)),
case atom_to_list(Mod) of
Base ->
- save_binary_1(St);
+ save_binary_1(Code, St);
_ ->
Es = [{St#compile.ofile,
[{none,?MODULE,{module_name,Mod,Base}}]}],
@@ -1431,14 +1568,14 @@ save_binary(#compile{module=Mod,ofile=Outfile,
end
end.
-save_binary_1(St) ->
+save_binary_1(Code, St) ->
Ofile = St#compile.ofile,
Tfile = tmpfile(Ofile), %Temp working file
- case write_binary(Tfile, St#compile.code, St) of
+ case write_binary(Tfile, Code, St) of
ok ->
case file:rename(Tfile, Ofile) of
ok ->
- {ok,St};
+ {ok,none,St};
{error,RenameError} ->
Es0 = [{Ofile,[{none,?MODULE,{rename,Tfile,Ofile,
RenameError}}]}],
@@ -1452,8 +1589,8 @@ save_binary_1(St) ->
end,
{error,St#compile{errors=St#compile.errors ++ Es}}
end;
- {error,_Error} ->
- Es = [{Tfile,[{none,compile,write_error}]}],
+ {error,Error} ->
+ Es = [{Tfile,[{none,compile,{write_error,Error}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
@@ -1538,6 +1675,9 @@ list_errors(_F, []) -> ok.
%% tmpfile(ObjFile) -> TmpFile
%% Work out the correct input and output file names.
+-spec iofile(atom() | file:filename_all()) ->
+ {file:name_all(),file:name_all()}.
+
iofile(File) when is_atom(File) ->
iofile(atom_to_list(File));
iofile(File) ->
@@ -1578,31 +1718,31 @@ pre_defs([]) -> [].
inc_paths(Opts) ->
[ P || {i,P} <- Opts, is_list(P) ].
-src_listing(Ext, St) ->
+src_listing(Ext, Code, St) ->
listing(fun (Lf, {_Mod,_Exp,Fs}) -> do_src_listing(Lf, Fs);
(Lf, Fs) -> do_src_listing(Lf, Fs) end,
- Ext, St).
+ Ext, Code, St).
do_src_listing(Lf, Fs) ->
Opts = [lists:keyfind(encoding, 1, io:getopts(Lf))],
foreach(fun (F) -> io:put_chars(Lf, [erl_pp:form(F, Opts),"\n"]) end,
Fs).
-listing(Ext, St0) ->
+listing(Ext, Code, St0) ->
St = St0#compile{encoding = none},
- listing(fun(Lf, Fs) -> beam_listing:module(Lf, Fs) end, Ext, St).
+ listing(fun(Lf, Fs) -> beam_listing:module(Lf, Fs) end, Ext, Code, St).
-listing(LFun, Ext, St) ->
+listing(LFun, Ext, Code, St) ->
Lfile = outfile(St#compile.base, Ext, St#compile.options),
case file:open(Lfile, [write,delayed_write]) of
{ok,Lf} ->
- Code = restore_expanded_types(Ext, St#compile.code),
+ Code = restore_expanded_types(Ext, Code),
output_encoding(Lf, St),
LFun(Lf, Code),
ok = file:close(Lf),
- {ok,St};
- {error,_Error} ->
- Es = [{Lfile,[{none,compile,write_error}]}],
+ {ok,Code,St};
+ {error,Error} ->
+ Es = [{Lfile,[{none,compile,{write_error,Error}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
@@ -1612,11 +1752,8 @@ output_encoding(F, #compile{encoding = Encoding}) ->
ok = io:setopts(F, [{encoding, Encoding}]),
ok = io:fwrite(F, <<"%% ~s\n">>, [epp:encoding_to_string(Encoding)]).
-restore_expanded_types("P", Fs) ->
- epp:restore_typed_record_fields(Fs);
restore_expanded_types("E", {M,I,Fs0}) ->
- Fs1 = restore_expand_module(Fs0),
- Fs = epp:restore_typed_record_fields(Fs1),
+ Fs = restore_expand_module(Fs0),
{M,I,Fs};
restore_expanded_types(_Ext, Code) -> Code.
@@ -1628,6 +1765,8 @@ restore_expand_module([{attribute,Line,spec,[Arg]}|Fs]) ->
[{attribute,Line,spec,Arg}|restore_expand_module(Fs)];
restore_expand_module([{attribute,Line,callback,[Arg]}|Fs]) ->
[{attribute,Line,callback,Arg}|restore_expand_module(Fs)];
+restore_expand_module([{attribute,Line,record,[R]}|Fs]) ->
+ [{attribute,Line,record,R}|restore_expand_module(Fs)];
restore_expand_module([F|Fs]) ->
[F|restore_expand_module(Fs)];
restore_expand_module([]) -> [].
@@ -1673,13 +1812,18 @@ help(_) ->
%% compile(AbsFileName, Outfilename, Options)
%% Compile entry point for erl_compile.
+-spec compile(file:filename(), _, #options{}) -> 'ok' | 'error'.
+
compile(File0, _OutFile, Options) ->
+ pre_load(),
File = shorten_filename(File0),
case file(File, make_erl_options(Options)) of
{ok,_Mod} -> ok;
Other -> Other
end.
+-spec compile_beam(file:filename(), _, #options{}) -> 'ok' | 'error'.
+
compile_beam(File0, _OutFile, Opts) ->
File = shorten_filename(File0),
case file(File, [from_beam|make_erl_options(Opts)]) of
@@ -1687,6 +1831,8 @@ compile_beam(File0, _OutFile, Opts) ->
Other -> Other
end.
+-spec compile_asm(file:filename(), _, #options{}) -> 'ok' | 'error'.
+
compile_asm(File0, _OutFile, Opts) ->
File = shorten_filename(File0),
case file(File, [from_asm|make_erl_options(Opts)]) of
@@ -1694,6 +1840,8 @@ compile_asm(File0, _OutFile, Opts) ->
Other -> Other
end.
+-spec compile_core(file:filename(), _, #options{}) -> 'ok' | 'error'.
+
compile_core(File0, _OutFile, Opts) ->
File = shorten_filename(File0),
case file(File, [from_core|make_erl_options(Opts)]) of
@@ -1738,3 +1886,47 @@ make_erl_options(Opts) ->
end,
Options ++ [report_errors, {cwd, Cwd}, {outdir, Outdir}|
[{i, Dir} || Dir <- Includes]] ++ Specific.
+
+pre_load() ->
+ L = [beam_a,
+ beam_asm,
+ beam_block,
+ beam_bs,
+ beam_bsm,
+ beam_clean,
+ beam_dead,
+ beam_dict,
+ beam_except,
+ beam_flatten,
+ beam_jump,
+ beam_opcodes,
+ beam_peep,
+ beam_receive,
+ beam_record,
+ beam_reorder,
+ beam_split,
+ beam_trim,
+ beam_type,
+ beam_utils,
+ beam_validator,
+ beam_z,
+ cerl,
+ cerl_clauses,
+ cerl_sets,
+ cerl_trees,
+ core_lib,
+ epp,
+ erl_bifs,
+ erl_expand_records,
+ erl_lint,
+ erl_parse,
+ erl_scan,
+ sys_core_bsm,
+ sys_core_dsetel,
+ sys_core_fold,
+ v3_codegen,
+ v3_core,
+ v3_kernel,
+ v3_life],
+ _ = code:ensure_modules_loaded(L),
+ ok.
diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src
index afb85f4710..3139d68902 100644
--- a/lib/compiler/src/compiler.app.src
+++ b/lib/compiler/src/compiler.app.src
@@ -1,7 +1,7 @@
% This is an -*- erlang -*- file.
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. 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.
@@ -24,7 +24,7 @@
beam_a,
beam_asm,
beam_block,
- beam_bool,
+ beam_bs,
beam_bsm,
beam_clean,
beam_dead,
@@ -37,6 +37,8 @@
beam_opcodes,
beam_peep,
beam_receive,
+ beam_reorder,
+ beam_record,
beam_split,
beam_trim,
beam_type,
@@ -56,12 +58,12 @@
core_lib,
erl_bifs,
rec_env,
+ sys_core_bsm,
sys_core_dsetel,
sys_core_fold,
sys_core_fold_lists,
sys_core_inline,
sys_pre_attributes,
- sys_pre_expand,
v3_codegen,
v3_core,
v3_kernel,
@@ -71,5 +73,5 @@
{registered, []},
{applications, [kernel, stdlib]},
{env, []},
- {runtime_dependencies, ["stdlib-2.5","kernel-4.0","hipe-3.12","erts-7.0",
+ {runtime_dependencies, ["stdlib-2.5","kernel-4.0","hipe-3.12","erts-9.0",
"crypto-3.6"]}]}.
diff --git a/lib/compiler/src/compiler.appup.src b/lib/compiler/src/compiler.appup.src
index 3ada2e933f..e9db37e203 100644
--- a/lib/compiler/src/compiler.appup.src
+++ b/lib/compiler/src/compiler.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014. All Rights Reserved.
+%% Copyright Ericsson AB 2014-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.
diff --git a/lib/compiler/src/core_lib.erl b/lib/compiler/src/core_lib.erl
index 3abb520485..c1806272bd 100644
--- a/lib/compiler/src/core_lib.erl
+++ b/lib/compiler/src/core_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,52 +21,16 @@
-module(core_lib).
--deprecated({get_anno,1,next_major_release}).
--deprecated({set_anno,2,next_major_release}).
--deprecated({is_literal,1,next_major_release}).
--deprecated({is_literal_list,1,next_major_release}).
--deprecated({literal_value,1,next_major_release}).
-
--export([get_anno/1,set_anno/2]).
--export([is_literal/1,is_literal_list/1]).
--export([literal_value/1]).
-export([make_values/1]).
-export([is_var_used/2]).
-include("core_parse.hrl").
-%%
-%% Generic get/set annotation that should be used only with cerl() structures.
-%%
--spec get_anno(cerl:cerl()) -> term().
-
-get_anno(C) -> cerl:get_ann(C).
-
--spec set_anno(cerl:cerl(), term()) -> cerl:cerl().
-
-set_anno(C, A) -> cerl:set_ann(C, A).
-
--spec is_literal(cerl:cerl()) -> boolean().
-
-is_literal(Cerl) ->
- cerl:is_literal(cerl:fold_literal(Cerl)).
-
--spec is_literal_list([cerl:cerl()]) -> boolean().
-
-is_literal_list(Es) -> lists:all(fun is_literal/1, Es).
-
-%% Return the value of LitExpr.
--spec literal_value(cerl:c_literal() | cerl:c_binary() |
- cerl:c_map() | cerl:c_cons() | cerl:c_tuple()) -> term().
-
-literal_value(Cerl) ->
- cerl:concrete(cerl:fold_literal(Cerl)).
-
%% Make a suitable values structure, expr or values, depending on Expr.
-spec make_values([cerl:cerl()] | cerl:cerl()) -> cerl:cerl().
make_values([E]) -> E;
-make_values([H|_]=Es) -> #c_values{anno=get_anno(H),es=Es};
+make_values([H|_]=Es) -> #c_values{anno=cerl:get_ann(H),es=Es};
make_values([]) -> #c_values{es=[]};
make_values(E) -> E.
diff --git a/lib/compiler/src/core_lint.erl b/lib/compiler/src/core_lint.erl
index cc54f6e411..7d3513c0ba 100644
--- a/lib/compiler/src/core_lint.erl
+++ b/lib/compiler/src/core_lint.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2015. 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.
@@ -73,7 +73,7 @@
%% Define the lint state record.
-record(lint, {module :: module(), % Current module
- func :: fa(), % Current function
+ func :: fa() | 'undefined', % Current function
errors = [] :: [error()], % Errors
warnings= [] :: [warning()]}). % Warnings
diff --git a/lib/compiler/src/core_parse.hrl b/lib/compiler/src/core_parse.hrl
index ecf6cc9956..83a6f0179c 100644
--- a/lib/compiler/src/core_parse.hrl
+++ b/lib/compiler/src/core_parse.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/core_parse.yrl b/lib/compiler/src/core_parse.yrl
index 59cfc97ebd..79a7cccd98 100644
--- a/lib/compiler/src/core_parse.yrl
+++ b/lib/compiler/src/core_parse.yrl
@@ -1,7 +1,7 @@
%% -*-Erlang-*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,12 +47,14 @@ receive_expr timeout try_expr
sequence catch_expr
variable clause clause_pattern
-map_expr map_pairs map_pair map_pair_assoc map_pair_exact
+map_expr anno_map_expr map_pairs anno_map_pair map_pair map_pair_assoc map_pair_exact
map_pattern map_pair_patterns map_pair_pattern
-annotation anno_fun anno_expression anno_expressions
+annotation anno_atom anno_fun anno_expression anno_expressions
anno_variable anno_variables anno_pattern anno_patterns
anno_function_name
+anno_literal
+anno_segment anno_segment_pattern
anno_clause anno_clauses.
Terminals
@@ -90,7 +92,7 @@ module_definition ->
module_definition ->
'(' 'module' atom module_export module_attribute module_defs 'end'
'-|' annotation ')' :
- #c_module{anno='$9',name=tok_val('$3'),exports='$4',
+ #c_module{anno='$9',name=#c_literal{val=tok_val('$3')},exports='$4',
attrs='$5',defs='$6'}.
module_export -> '[' ']' : [].
@@ -99,7 +101,7 @@ module_export -> '[' exported_names ']' : '$2'.
exported_names -> exported_name ',' exported_names : ['$1' | '$3'].
exported_names -> exported_name : ['$1'].
-exported_name -> function_name : '$1'.
+exported_name -> anno_function_name : '$1'.
module_attribute -> 'attributes' '[' ']' : [].
module_attribute -> 'attributes' '[' attribute_list ']' : '$3'.
@@ -107,8 +109,16 @@ module_attribute -> 'attributes' '[' attribute_list ']' : '$3'.
attribute_list -> attribute ',' attribute_list : ['$1' | '$3'].
attribute_list -> attribute : ['$1'].
-attribute -> atom '=' literal :
- {#c_literal{val=tok_val('$1')},'$3'}.
+attribute -> anno_atom '=' anno_literal :
+ {'$1','$3'}.
+
+anno_atom -> atom :
+ cerl:c_atom(tok_val('$1')).
+anno_atom -> '(' atom '-|' annotation ')' :
+ cerl:ann_c_atom('$4', tok_val('$2')).
+
+anno_literal -> literal : '$1'.
+anno_literal -> '(' literal '-|' annotation ')' : cerl:set_ann('$2', '$4').
module_defs -> function_definitions : '$1'.
@@ -186,7 +196,9 @@ tuple_pattern -> '{' anno_patterns '}' : c_tuple('$2').
map_pattern -> '~' '{' '}' '~' : c_map_pattern([]).
map_pattern -> '~' '{' map_pair_patterns '}' '~' :
- c_map_pattern(lists:sort('$3')).
+ c_map_pattern('$3').
+map_pattern -> '~' '{' map_pair_patterns '|' anno_map_expr '}' '~' :
+ ann_c_map_pattern('$5', '$3').
map_pair_patterns -> map_pair_pattern : ['$1'].
map_pair_patterns -> map_pair_pattern ',' map_pair_patterns : ['$1' | '$3'].
@@ -194,6 +206,9 @@ map_pair_patterns -> map_pair_pattern ',' map_pair_patterns : ['$1' | '$3'].
map_pair_pattern -> anno_expression ':=' anno_pattern :
#c_map_pair{op=#c_literal{val=exact},
key='$1',val='$3'}.
+map_pair_pattern -> '(' anno_expression ':=' anno_pattern '-|' annotation ')' :
+ #c_map_pair{anno='$6',op=#c_literal{val=exact},
+ key='$2',val='$4'}.
cons_pattern -> '[' anno_pattern tail_pattern :
c_cons('$2', '$3').
@@ -206,8 +221,12 @@ tail_pattern -> ',' anno_pattern tail_pattern :
binary_pattern -> '#' '{' '}' '#' : #c_binary{segments=[]}.
binary_pattern -> '#' '{' segment_patterns '}' '#' : #c_binary{segments='$3'}.
-segment_patterns -> segment_pattern ',' segment_patterns : ['$1' | '$3'].
-segment_patterns -> segment_pattern : ['$1'].
+segment_patterns -> anno_segment_pattern ',' segment_patterns : ['$1' | '$3'].
+segment_patterns -> anno_segment_pattern : ['$1'].
+
+anno_segment_pattern -> segment_pattern : '$1'.
+anno_segment_pattern -> '(' segment_pattern '-|' annotation ')' :
+ cerl:set_ann('$2', '$4').
segment_pattern -> '#' '<' anno_pattern '>' '(' anno_expressions ')':
case '$6' of
@@ -289,11 +308,17 @@ tuple -> '{' anno_expressions '}' : c_tuple('$2').
map_expr -> '~' '{' '}' '~' : c_map([]).
map_expr -> '~' '{' map_pairs '}' '~' : c_map('$3').
-map_expr -> '~' '{' map_pairs '|' variable '}' '~' : ann_c_map([], '$5', '$3').
-map_expr -> '~' '{' map_pairs '|' map_expr '}' '~' : ann_c_map([], '$5', '$3').
+map_expr -> '~' '{' map_pairs '|' anno_variable '}' '~' : ann_c_map([], '$5', '$3').
+map_expr -> '~' '{' map_pairs '|' anno_map_expr '}' '~' : ann_c_map([], '$5', '$3').
-map_pairs -> map_pair : ['$1'].
-map_pairs -> map_pair ',' map_pairs : ['$1' | '$3'].
+anno_map_expr -> map_expr : '$1'.
+anno_map_expr -> '(' map_expr '-|' annotation ')' : cerl:set_ann('$2', '$4').
+
+map_pairs -> anno_map_pair : ['$1'].
+map_pairs -> anno_map_pair ',' map_pairs : ['$1' | '$3'].
+
+anno_map_pair -> map_pair : '$1'.
+anno_map_pair -> '(' map_pair '-|' annotation ')' : cerl:set_ann('$2', '$4').
map_pair -> map_pair_assoc : '$1'.
map_pair -> map_pair_exact : '$1'.
@@ -312,8 +337,11 @@ tail -> ',' anno_expression tail : c_cons('$2', '$3').
binary -> '#' '{' '}' '#' : #c_literal{val = <<>>}.
binary -> '#' '{' segments '}' '#' : make_binary('$3').
-segments -> segment ',' segments : ['$1' | '$3'].
-segments -> segment : ['$1'].
+segments -> anno_segment ',' segments : ['$1' | '$3'].
+segments -> anno_segment : ['$1'].
+
+anno_segment -> segment : '$1'.
+anno_segment -> '(' segment '-|' annotation ')' : cerl:set_ann('$2', '$4').
segment -> '#' '<' anno_expression '>' '(' anno_expressions ')':
case '$6' of
@@ -404,6 +432,21 @@ timeout ->
%% ====================================================================== %%
+Header
+"%% This file was automatically generated from the file \"core_parse.yrl\"."
+"%%"
+"%% Copyright Ericsson AB 1999-2009. 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."
+"".
Erlang code.
@@ -413,7 +456,8 @@ Erlang code.
-include("core_parse.hrl").
--import(cerl, [ann_c_map/3,c_cons/2,c_map/1,c_map_pattern/1,c_tuple/1]).
+-import(cerl, [ann_c_map/3,ann_c_map_pattern/2,c_cons/2,c_map/1,
+ c_map_pattern/1,c_tuple/1]).
tok_val(T) -> element(3, T).
tok_line(T) -> element(2, T).
diff --git a/lib/compiler/src/core_pp.erl b/lib/compiler/src/core_pp.erl
index c2a6a81d5e..cff6c7098b 100644
--- a/lib/compiler/src/core_pp.erl
+++ b/lib/compiler/src/core_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
-module(core_pp).
--export([format/1]).
+-export([format/1,format_all/1]).
-include("core_parse.hrl").
@@ -33,25 +33,35 @@
%% Prettyprint-formats (naively) an abstract Core Erlang syntax
%% tree.
--record(ctxt, {class = term :: 'clause' | 'def' | 'expr' | 'term',
- indent = 0 :: integer(),
+-record(ctxt, {indent = 0 :: integer(),
item_indent = 2 :: integer(),
body_indent = 4 :: integer(),
- tab_width = 8 :: non_neg_integer(),
- line = 0 :: integer()}).
+ line = 0 :: integer(),
+ clean = true :: boolean()}).
+
+-define(TAB_WIDTH, 8).
-spec format(cerl:cerl()) -> iolist().
format(Node) ->
format(Node, #ctxt{}).
-maybe_anno(Node, Fun, Ctxt) ->
+-spec format_all(cerl:cerl()) -> iolist().
+
+format_all(Node) ->
+ format(Node, #ctxt{clean=false}).
+
+maybe_anno(Node, Fun, #ctxt{clean=false}=Ctxt) ->
As = cerl:get_ann(Node),
- case get_line(As) of
+ maybe_anno(Node, Fun, Ctxt, As);
+maybe_anno(Node, Fun, #ctxt{clean=true}=Ctxt) ->
+ As0 = cerl:get_ann(Node),
+ case get_line(As0) of
none ->
- maybe_anno(Node, Fun, Ctxt, As);
+ maybe_anno(Node, Fun, Ctxt, As0);
Line ->
- if Line > Ctxt#ctxt.line ->
+ As = strip_line(As0),
+ if Line > Ctxt#ctxt.line ->
[io_lib:format("%% Line ~w",[Line]),
nl_indent(Ctxt),
maybe_anno(Node, Fun, Ctxt#ctxt{line = Line}, As)
@@ -61,22 +71,22 @@ maybe_anno(Node, Fun, Ctxt) ->
end
end.
-maybe_anno(Node, Fun, Ctxt, As) ->
- case strip_line(As) of
- [] ->
- Fun(Node, Ctxt);
- List ->
- Ctxt1 = add_indent(Ctxt, 2),
- Ctxt2 = add_indent(Ctxt1, 3),
- ["( ",
- Fun(Node, Ctxt1),
- nl_indent(Ctxt1),
- "-| ",format_anno(List, Ctxt2)," )"
- ]
- end.
+maybe_anno(Node, Fun, Ctxt, []) ->
+ Fun(Node, Ctxt);
+maybe_anno(Node, Fun, Ctxt, List) ->
+ Ctxt1 = add_indent(Ctxt, 2),
+ Ctxt2 = add_indent(Ctxt1, 3),
+ ["( ",
+ Fun(Node, Ctxt1),
+ nl_indent(Ctxt1),
+ "-| ",format_anno(List, Ctxt2)," )"
+ ].
format_anno([_|_]=List, Ctxt) ->
[$[,format_anno_list(List, Ctxt),$]];
+format_anno({file,Name}, _Ctxt) ->
+ %% Optimization: Reduces file size considerably.
+ io_lib:format("{'file',~p}", [Name]);
format_anno(Tuple, Ctxt) when is_tuple(Tuple) ->
[${,format_anno_list(tuple_to_list(Tuple), Ctxt),$}];
format_anno(Val, Ctxt) when is_atom(Val) ->
@@ -121,14 +131,11 @@ format_1(#c_literal{anno=A,val=Bitstring}, Ctxt) when is_bitstring(Bitstring) ->
format_1(#c_binary{anno=A,segments=Segs}, Ctxt);
format_1(#c_literal{anno=A,val=M},Ctxt) when is_map(M) ->
Pairs = maps:to_list(M),
- Op = case Ctxt of
- #ctxt{ class = clause } -> exact;
- _ -> assoc
- end,
- Cpairs = [#c_map_pair{op=#c_literal{val=Op},
+ Op = #c_literal{val=assoc},
+ Cpairs = [#c_map_pair{op=Op,
key=#c_literal{val=K},
val=#c_literal{val=V}} || {K,V} <- Pairs],
- format_1(#c_map{anno=A,arg=#c_literal{val=#{}},es=Cpairs},Ctxt);
+ format_1(#c_map{anno=A,arg=#c_literal{val=#{}},es=Cpairs},Ctxt);
format_1(#c_var{name={I,A}}, _) ->
[core_atom(I),$/,integer_to_list(A)];
format_1(#c_var{name=V}, _) ->
@@ -172,7 +179,8 @@ format_1(#c_tuple{es=Es}, Ctxt) ->
format_hseq(Es, ",", add_indent(Ctxt, 1), fun format/2),
$}
];
-format_1(#c_map{arg=#c_literal{val=M},es=Es}, Ctxt) when is_map(M),map_size(M)=:=0 ->
+format_1(#c_map{arg=#c_literal{val=M},es=Es}, Ctxt)
+ when is_map(M), map_size(M) =:= 0 ->
["~{",
format_hseq(Es, ",", add_indent(Ctxt, 1), fun format/2),
"}~"
@@ -195,9 +203,16 @@ format_1(#c_values{es=Es}, Ctxt) ->
format_1(#c_alias{var=V,pat=P}, Ctxt) ->
Txt = [format(V, Ctxt)|" = "],
[Txt|format(P, add_indent(Ctxt, width(Txt, Ctxt)))];
-format_1(#c_let{vars=Vs0,arg=A,body=B}, Ctxt) ->
- Vs = [cerl:set_ann(V, []) || V <- Vs0],
- case is_simple_term(A) of
+format_1(#c_let{anno=Anno0,vars=Vs0,arg=A0,body=B}, #ctxt{clean=Clean}=Ctxt) ->
+ {Vs,A,Anno} = case Clean of
+ false ->
+ {Vs0,A0,Anno0};
+ true ->
+ {[cerl:set_ann(V, []) || V <- Vs0],
+ cerl:set_ann(A0, []),
+ []}
+ end,
+ case is_simple_term(A) andalso Anno =:= [] of
false ->
Ctxt1 = add_indent(Ctxt, Ctxt#ctxt.body_indent),
["let ",
@@ -214,7 +229,7 @@ format_1(#c_let{vars=Vs0,arg=A,body=B}, Ctxt) ->
["let ",
format_values(Vs, add_indent(Ctxt, 4)),
" = ",
- format(cerl:set_ann(A, []), Ctxt1),
+ format(A, Ctxt1),
nl_indent(Ctxt),
"in "
| format(B, add_indent(Ctxt, 4))
@@ -321,35 +336,30 @@ format_1(#c_module{name=N,exports=Es,attrs=As,defs=Ds}, Ctxt) ->
[Mod," [",
format_vseq(Es,
"", ",",
- add_indent(set_class(Ctxt, term), width(Mod, Ctxt)+2),
+ add_indent(Ctxt, width(Mod, Ctxt)+2),
fun format/2),
"]",
nl_indent(Ctxt),
" attributes [",
format_vseq(As,
"", ",",
- add_indent(set_class(Ctxt, def), 16),
+ add_indent(Ctxt, 16),
fun format_def/2),
"]",
nl_indent(Ctxt),
format_funcs(Ds, Ctxt),
nl_indent(Ctxt)
| "end"
- ];
-format_1(Type, _) ->
- ["** Unsupported type: ",
- io_lib:write(Type)
- | " **"
].
format_funcs(Fs, Ctxt) ->
format_vseq(Fs,
"", "",
- set_class(Ctxt, def),
+ Ctxt,
fun format_def/2).
format_def({N,V}, Ctxt0) ->
- Ctxt1 = add_indent(set_class(Ctxt0, expr), Ctxt0#ctxt.body_indent),
+ Ctxt1 = add_indent(Ctxt0, Ctxt0#ctxt.body_indent),
[format(N, Ctxt0),
" =",
nl_indent(Ctxt1)
@@ -362,7 +372,10 @@ format_values(Vs, Ctxt) ->
format_hseq(Vs, ",", add_indent(Ctxt, 1), fun format/2),
$>].
-format_bitstr(#c_bitstr{val=V,size=S,unit=U,type=T,flags=Fs}, Ctxt0) ->
+format_bitstr(Node, Ctxt) ->
+ maybe_anno(Node, fun do_format_bitstr/2, Ctxt).
+
+do_format_bitstr(#c_bitstr{val=V,size=S,unit=U,type=T,flags=Fs}, Ctxt0) ->
Vs = [S, U, T, Fs],
Ctxt1 = add_indent(Ctxt0, 2),
Val = format(V, Ctxt1),
@@ -370,8 +383,7 @@ format_bitstr(#c_bitstr{val=V,size=S,unit=U,type=T,flags=Fs}, Ctxt0) ->
["#<", Val, ">(", format_hseq(Vs,",", Ctxt2, fun format/2), $)].
format_clauses(Cs, Ctxt) ->
- format_vseq(Cs, "", "", set_class(Ctxt, clause),
- fun format_clause/2).
+ format_vseq(Cs, "", "", Ctxt, fun format_clause/2).
format_clause(Node, Ctxt) ->
maybe_anno(Node, fun format_clause_1/2, Ctxt).
@@ -383,15 +395,13 @@ format_clause_1(#c_clause{pats=Ps,guard=G,body=B}, Ctxt) ->
case is_trivial_guard(G) of
true ->
[" when ",
- format_guard(G, add_indent(set_class(Ctxt, expr),
- width(Ptxt, Ctxt) + 6))];
+ format_guard(G, add_indent(Ctxt, width(Ptxt, Ctxt) + 6))];
false ->
[nl_indent(Ctxt2), "when ",
format_guard(G, add_indent(Ctxt2, 2))]
end++
" ->",
- nl_indent(Ctxt2)
- | format(B, set_class(Ctxt2, expr))
+ nl_indent(Ctxt2) | format(B, Ctxt2)
].
is_trivial_guard(#c_literal{val=Val}) when is_atom(Val) -> true;
@@ -445,50 +455,53 @@ format_list_tail(Tail, Ctxt) ->
format_map_pair(Op, K, V, Ctxt0) ->
Ctxt1 = add_indent(Ctxt0, 1),
- Txt = format(K, set_class(Ctxt1, expr)),
+ Txt = format(K, Ctxt1),
Ctxt2 = add_indent(Ctxt0, width(Txt, Ctxt1)),
[Txt,Op,format(V, Ctxt2)].
-indent(Ctxt) -> indent(Ctxt#ctxt.indent, Ctxt).
-
-indent(N, _) when N =< 0 -> "";
-indent(N, Ctxt) ->
- T = Ctxt#ctxt.tab_width,
- string:chars($\t, N div T, string:chars($\s, N rem T)).
+indent(#ctxt{indent=N}) ->
+ if
+ N =< 0 ->
+ "";
+ true ->
+ string:chars($\t, N div ?TAB_WIDTH, spaces(N rem ?TAB_WIDTH))
+ end.
nl_indent(Ctxt) -> [$\n|indent(Ctxt)].
+spaces(0) -> "";
+spaces(1) -> " ";
+spaces(2) -> " ";
+spaces(3) -> " ";
+spaces(4) -> " ";
+spaces(5) -> " ";
+spaces(6) -> " ";
+spaces(7) -> " ".
+%% Undo indentation done by nl_indent/1.
unindent(T, Ctxt) ->
- unindent(T, Ctxt#ctxt.indent, Ctxt, []).
+ unindent(T, Ctxt#ctxt.indent, []).
-unindent(T, N, _, C) when N =< 0 ->
+unindent(T, N, C) when N =< 0 ->
[T|C];
-unindent([$\s|T], N, Ctxt, C) ->
- unindent(T, N - 1, Ctxt, C);
-unindent([$\t|T], N, Ctxt, C) ->
- Tab = Ctxt#ctxt.tab_width,
+unindent([$\s|T], N, C) ->
+ unindent(T, N - 1, C);
+unindent([$\t|T], N, C) ->
+ Tab = ?TAB_WIDTH,
if N >= Tab ->
- unindent(T, N - Tab, Ctxt, C);
+ unindent(T, N - Tab, C);
true ->
- unindent([string:chars($\s, Tab - N)|T], 0, Ctxt, C)
+ unindent([spaces(Tab - N)|T], 0, C)
end;
-unindent([L|T], N, Ctxt, C) when is_list(L) ->
- unindent(L, N, Ctxt, [T|C]);
-unindent([H|T], _, _, C) ->
- [H|[T|C]];
-unindent([], N, Ctxt, [H|T]) ->
- unindent(H, N, Ctxt, T);
-unindent([], _, _, []) -> [].
+unindent([L|T], N, C) when is_list(L) ->
+ unindent(L, N, [T|C]).
width(Txt, Ctxt) ->
- try width(Txt, 0, Ctxt, [])
- catch error:_ -> exit({bad_text,Txt})
- end.
+ width(Txt, 0, Ctxt, []).
width([$\t|T], A, Ctxt, C) ->
- width(T, A + Ctxt#ctxt.tab_width, Ctxt, C);
+ width(T, A + ?TAB_WIDTH, Ctxt, C);
width([$\n|T], _, Ctxt, C) ->
width(unindent([T|C], Ctxt), Ctxt);
width([H|T], A, Ctxt, C) when is_list(H) ->
@@ -502,14 +515,9 @@ width([], A, _, []) -> A.
add_indent(Ctxt, Dx) ->
Ctxt#ctxt{indent = Ctxt#ctxt.indent + Dx}.
-set_class(Ctxt, Class) ->
- Ctxt#ctxt{class = Class}.
-
core_atom(A) -> io_lib:write_string(atom_to_list(A), $').
-is_simple_term(#c_values{es=Es}) ->
- length(Es) < 3 andalso lists:all(fun is_simple_term/1, Es);
is_simple_term(#c_tuple{es=Es}) ->
length(Es) < 4 andalso lists:all(fun is_simple_term/1, Es);
is_simple_term(#c_var{}) -> true;
diff --git a/lib/compiler/src/core_scan.erl b/lib/compiler/src/core_scan.erl
index 5e85bba2bd..9f0676538f 100644
--- a/lib/compiler/src/core_scan.erl
+++ b/lib/compiler/src/core_scan.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2017. 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.
@@ -49,13 +49,37 @@
-import(lists, [reverse/1]).
+-type location() :: integer().
+-type category() :: atom().
+-type symbol() :: atom() | float() | integer() | string().
+-type token() :: {category(), Anno :: location(), symbol()}
+ | {category(), Anno :: location()}.
+-type tokens() :: [token()].
+-type error_description() :: term().
+-type error_info() :: {erl_anno:location(), module(), error_description()}.
+
%% string([Char]) ->
%% string([Char], StartPos) ->
%% {ok, [Tok], EndPos} |
%% {error, {Pos,core_scan,What}, EndPos}
+-spec string(String) -> Return when
+ String :: string(),
+ Return :: {'ok', Tokens :: tokens(), EndLocation}
+ | {'error', ErrorInfo :: error_info(), ErrorLocation},
+ EndLocation :: location(),
+ ErrorLocation :: location().
+
string(Cs) -> string(Cs, 1).
+-spec string(String, StartLocation) -> Return when
+ String :: string(),
+ Return :: {'ok', Tokens :: tokens(), EndLocation}
+ | {'error', ErrorInfo :: error_info(), ErrorLocation},
+ StartLocation :: location(),
+ EndLocation :: location(),
+ ErrorLocation :: location().
+
string(Cs, Sp) ->
%% Add an 'eof' to always get correct handling.
case string_pre_scan(Cs, [], Sp) of
@@ -259,10 +283,12 @@ scan1([$$|Cs0], Toks, Pos) -> %Character constant
scan1(Cs, [{char,Pos,C}|Toks], Pos1);
scan1([$'|Cs0], Toks, Pos) -> %Atom (always quoted)
{S,Cs1,Pos1} = scan_string(Cs0, $', Pos),
- case catch list_to_atom(S) of
+ try binary_to_atom(list_to_binary(S), utf8) of
A when is_atom(A) ->
- scan1(Cs1, [{atom,Pos,A}|Toks], Pos1);
- _Error -> scan_error({illegal,atom}, Pos)
+ scan1(Cs1, [{atom,Pos,A}|Toks], Pos1)
+ catch
+ error:_ ->
+ scan_error({illegal,atom}, Pos)
end;
scan1([$"|Cs0], Toks, Pos) -> %String
{S,Cs1,Pos1} = scan_string(Cs0, $", Pos),
diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl
index c00f5eab70..bafa9d75b7 100644
--- a/lib/compiler/src/erl_bifs.erl
+++ b/lib/compiler/src/erl_bifs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2017. 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.
@@ -75,11 +75,12 @@ is_pure(erlang, binary_to_list, 1) -> true;
is_pure(erlang, binary_to_list, 3) -> true;
is_pure(erlang, bit_size, 1) -> true;
is_pure(erlang, byte_size, 1) -> true;
+is_pure(erlang, ceil, 1) -> true;
is_pure(erlang, element, 2) -> true;
is_pure(erlang, float, 1) -> true;
is_pure(erlang, float_to_list, 1) -> true;
is_pure(erlang, float_to_binary, 1) -> true;
-is_pure(erlang, hash, 2) -> false;
+is_pure(erlang, floor, 1) -> true;
is_pure(erlang, hd, 1) -> true;
is_pure(erlang, integer_to_binary, 1) -> true;
is_pure(erlang, integer_to_list, 1) -> true;
@@ -129,11 +130,14 @@ is_pure(math, asinh, 1) -> true;
is_pure(math, atan, 1) -> true;
is_pure(math, atan2, 2) -> true;
is_pure(math, atanh, 1) -> true;
+is_pure(math, ceil, 1) -> true;
is_pure(math, cos, 1) -> true;
is_pure(math, cosh, 1) -> true;
is_pure(math, erf, 1) -> true;
is_pure(math, erfc, 1) -> true;
is_pure(math, exp, 1) -> true;
+is_pure(math, floor, 1) -> true;
+is_pure(math, fmod, 2) -> true;
is_pure(math, log, 1) -> true;
is_pure(math, log2, 1) -> true;
is_pure(math, log10, 1) -> true;
@@ -203,7 +207,6 @@ is_safe(erlang, registered, 0) -> true;
is_safe(erlang, self, 0) -> true;
is_safe(erlang, term_to_binary, 1) -> true;
is_safe(erlang, time, 0) -> true;
-is_safe(error_logger, warning_map, 0) -> true;
is_safe(_, _, _) -> false.
diff --git a/lib/compiler/src/genop.tab b/lib/compiler/src/genop.tab
index 3a877f2403..b5688de339 100755
--- a/lib/compiler/src/genop.tab
+++ b/lib/compiler/src/genop.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2011. All Rights Reserved.
+# Copyright Ericsson AB 1998-2017. 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.
@@ -537,3 +537,11 @@ BEAM_FORMAT_NUMBER=0
156: is_map/2
157: has_map_fields/3
158: get_map_elements/3
+
+# OTP 20
+
+## @spec is_tagged_tuple Lbl Reg N Atom
+## @doc Test the type of Reg and jumps to Lbl if it is not a tuple.
+## Test the arity of Reg and jumps to Lbl if it is not N.
+## Test the first element of the tuple and jumps to Lbl if it is not Atom.
+159: is_tagged_tuple/4
diff --git a/lib/compiler/src/rec_env.erl b/lib/compiler/src/rec_env.erl
index 0e9e12d1ad..48d39776dc 100644
--- a/lib/compiler/src/rec_env.erl
+++ b/lib/compiler/src/rec_env.erl
@@ -1,8 +1,3 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2014. 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
@@ -15,15 +10,12 @@
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
-%% %CopyrightEnd%
-%%
-%% @author Richard Carlsson <[email protected]>
%% @copyright 1999-2004 Richard Carlsson
+%% @author Richard Carlsson <[email protected]>
%% @doc Abstract environments, supporting self-referential bindings and
%% automatic new-key generation.
-%% The current implementation is based on Erlang standard library
-%% dictionaries.
+%% The current implementation is based on Erlang standard library maps.
%%% -define(DEBUG, true).
@@ -62,7 +54,7 @@ test_0(Type, N) ->
io:fwrite("\ncalls: ~w.\n", [get(new_key_calls)]),
io:fwrite("\nretries: ~w.\n", [get(new_key_retries)]),
io:fwrite("\nmax: ~w.\n", [get(new_key_max)]),
- dict:to_list(element(1,Env)).
+ maps:to_list(element(1,Env)).
test_1(integer = Type, N, Env) when is_integer(N), N > 0 ->
Key = new_key(Env),
@@ -80,14 +72,13 @@ test_1(_,0, Env) ->
%%
%% environment() = [Mapping]
%%
-%% Mapping = {map, Dict} | {rec, Dict, Dict}
-%% Dict = dict:dictionary()
+%% Mapping = {map, map()} | {rec, map(), map()}
%%
-%% An empty environment is a list containing a single `{map, Dict}'
+%% An empty environment is a list containing a single `{map, map()}'
%% element - empty lists are not valid environments. To find a key in an
%% environment, it is searched for in each mapping in the list, in
%% order, until it the key is found in some mapping, or the end of the
-%% list is reached. In a 'rec' mapping, we keep the original dictionary
+%% list is reached. In a 'rec' mapping, we keep the original map
%% together with a version where entries may have been deleted - this
%% makes it possible to garbage collect the entire 'rec' mapping when
%% all its entries are unused (for example, by being shadowed by later
@@ -97,7 +88,7 @@ test_1(_,0, Env) ->
%% =====================================================================
%% @type environment(). An abstract environment.
--type mapping() :: {'map', dict:dict()} | {'rec', dict:dict(), dict:dict()}.
+-type mapping() :: {'map', map()} | {'rec', map(), map()}.
-type environment() :: [mapping(),...].
%% =====================================================================
@@ -108,7 +99,7 @@ test_1(_,0, Env) ->
-spec empty() -> environment().
empty() ->
- [{map, dict:new()}].
+ [{map, #{}}].
%% =====================================================================
@@ -119,14 +110,14 @@ empty() ->
-spec is_empty(environment()) -> boolean().
-is_empty([{map, Dict} | Es]) ->
- N = dict:size(Dict),
+is_empty([{map, Map} | Es]) ->
+ N = map_size(Map),
if N =/= 0 -> false;
Es =:= [] -> true;
true -> is_empty(Es)
end;
-is_empty([{rec, Dict, _} | Es]) ->
- N = dict:size(Dict),
+is_empty([{rec, Map, _} | Es]) ->
+ N = map_size(Map),
if N =/= 0 -> false;
Es =:= [] -> true;
true -> is_empty(Es)
@@ -146,12 +137,12 @@ is_empty([{rec, Dict, _} | Es]) ->
size(Env) ->
env_size(Env).
-env_size([{map, Dict}]) ->
- dict:size(Dict);
-env_size([{map, Dict} | Env]) ->
- dict:size(Dict) + env_size(Env);
-env_size([{rec, Dict, _Dict0} | Env]) ->
- dict:size(Dict) + env_size(Env).
+env_size([{map, Map}]) ->
+ map_size(Map);
+env_size([{map, Map} | Env]) ->
+ map_size(Map) + env_size(Env);
+env_size([{rec, Map, _Map0} | Env]) ->
+ map_size(Map) + env_size(Env).
%% =====================================================================
@@ -165,8 +156,8 @@ env_size([{rec, Dict, _Dict0} | Env]) ->
-spec is_defined(term(), environment()) -> boolean().
-is_defined(Key, [{map, Dict} | Env]) ->
- case dict:is_key(Key, Dict) of
+is_defined(Key, [{map, Map} | Env]) ->
+ case maps:is_key(Key, Map) of
true ->
true;
false when Env =:= [] ->
@@ -174,8 +165,8 @@ is_defined(Key, [{map, Dict} | Env]) ->
false ->
is_defined(Key, Env)
end;
-is_defined(Key, [{rec, Dict, _Dict0} | Env]) ->
- dict:is_key(Key, Dict) orelse is_defined(Key, Env).
+is_defined(Key, [{rec, Map, _Map0} | Env]) ->
+ maps:is_key(Key, Map) orelse is_defined(Key, Env).
%% =====================================================================
@@ -188,12 +179,12 @@ is_defined(Key, [{rec, Dict, _Dict0} | Env]) ->
keys(Env) ->
lists:sort(keys(Env, [])).
-keys([{map, Dict}], S) ->
- dict:fetch_keys(Dict) ++ S;
-keys([{map, Dict} | Env], S) ->
- keys(Env, dict:fetch_keys(Dict) ++ S);
-keys([{rec, Dict, _Dict0} | Env], S) ->
- keys(Env, dict:fetch_keys(Dict) ++ S).
+keys([{map, Map}], S) ->
+ maps:keys(Map) ++ S;
+keys([{map, Map} | Env], S) ->
+ keys(Env, maps:keys(Map) ++ S);
+keys([{rec, Map, _Map0} | Env], S) ->
+ keys(Env, maps:keys(Map) ++ S).
%% =====================================================================
@@ -212,12 +203,12 @@ keys([{rec, Dict, _Dict0} | Env], S) ->
to_list(Env) ->
lists:sort(to_list(Env, [])).
-to_list([{map, Dict}], S) ->
- dict:to_list(Dict) ++ S;
-to_list([{map, Dict} | Env], S) ->
- to_list(Env, dict:to_list(Dict) ++ S);
-to_list([{rec, Dict, _Dict0} | Env], S) ->
- to_list(Env, dict:to_list(Dict) ++ S).
+to_list([{map, Map}], S) ->
+ maps:to_list(Map) ++ S;
+to_list([{map, Map} | Env], S) ->
+ to_list(Env, maps:to_list(Map) ++ S);
+to_list([{rec, Map, _Map0} | Env], S) ->
+ to_list(Env, maps:to_list(Map) ++ S).
%% =====================================================================
@@ -236,12 +227,12 @@ to_list([{rec, Dict, _Dict0} | Env], S) ->
-spec bind(term(), term(), environment()) -> environment().
-bind(Key, Value, [{map, Dict}]) ->
- [{map, dict:store(Key, Value, Dict)}];
-bind(Key, Value, [{map, Dict} | Env]) ->
- [{map, dict:store(Key, Value, Dict)} | delete_any(Key, Env)];
+bind(Key, Value, [{map, Map}]) ->
+ [{map, maps:put(Key, Value, Map)}];
+bind(Key, Value, [{map, Map} | Env]) ->
+ [{map, maps:put(Key, Value, Map)} | delete_any(Key, Env)];
bind(Key, Value, Env) ->
- [{map, dict:store(Key, Value, dict:new())} | delete_any(Key, Env)].
+ [{map, maps:put(Key, Value, #{})} | delete_any(Key, Env)].
%% =====================================================================
@@ -259,17 +250,17 @@ bind(Key, Value, Env) ->
-spec bind_list([term()], [term()], environment()) -> environment().
-bind_list(Ks, Vs, [{map, Dict}]) ->
- [{map, store_list(Ks, Vs, Dict)}];
-bind_list(Ks, Vs, [{map, Dict} | Env]) ->
- [{map, store_list(Ks, Vs, Dict)} | delete_list(Ks, Env)];
+bind_list(Ks, Vs, [{map, Map}]) ->
+ [{map, store_list(Ks, Vs, Map)}];
+bind_list(Ks, Vs, [{map, Map} | Env]) ->
+ [{map, store_list(Ks, Vs, Map)} | delete_list(Ks, Env)];
bind_list(Ks, Vs, Env) ->
- [{map, store_list(Ks, Vs, dict:new())} | delete_list(Ks, Env)].
+ [{map, store_list(Ks, Vs, #{})} | delete_list(Ks, Env)].
-store_list([K | Ks], [V | Vs], Dict) ->
- store_list(Ks, Vs, dict:store(K, V, Dict));
-store_list([], _, Dict) ->
- Dict.
+store_list([K | Ks], [V | Vs], Map) ->
+ store_list(Ks, Vs, maps:put(K, V, Map));
+store_list([], _, Map) ->
+ Map.
delete_list([K | Ks], Env) ->
delete_list(Ks, delete_any(K, Env));
@@ -298,48 +289,40 @@ delete_any(Key, Env) ->
-spec delete(term(), environment()) -> environment().
-delete(Key, [{map, Dict} = E | Env]) ->
- case dict:is_key(Key, Dict) of
- true ->
- [{map, dict:erase(Key, Dict)} | Env];
- false ->
+delete(Key, [{map, Map} = E | Env]) ->
+ case maps:take(Key, Map) of
+ {_, Map1} ->
+ [{map, Map1} | Env];
+ error ->
delete_1(Key, Env, E)
end;
-delete(Key, [{rec, Dict, Dict0} = E | Env]) ->
- case dict:is_key(Key, Dict) of
- true ->
- %% The Dict0 component must be preserved as it is until all
- %% keys in Dict have been deleted.
- Dict1 = dict:erase(Key, Dict),
- case dict:size(Dict1) of
- 0 ->
- Env; % the whole {rec,...} is now garbage
- _ ->
- [{rec, Dict1, Dict0} | Env]
- end;
- false ->
+delete(Key, [{rec, Map, Map0} = E | Env]) ->
+ case maps:take(Key, Map) of
+ {_, Map1} when map_size(Map1) =:= 0 ->
+ Env; % the whole {rec,...} is now garbage
+ %% The Map0 component must be preserved as it is until all
+ %% keys in Map have been deleted.
+ {_, Map1} ->
+ [{rec, Map1, Map0} | Env];
+ error ->
[E | delete(Key, Env)]
end.
%% This is just like above, except we pass on the preceding 'map'
%% mapping in the list to enable merging when removing 'rec' mappings.
-delete_1(Key, [{rec, Dict, Dict0} = E | Env], E1) ->
- case dict:is_key(Key, Dict) of
- true ->
- Dict1 = dict:erase(Key, Dict),
- case dict:size(Dict1) of
- 0 ->
- concat(E1, Env);
- _ ->
- [E1, {rec, Dict1, Dict0} | Env]
- end;
- false ->
+delete_1(Key, [{rec, Map, Map0} = E | Env], E1) ->
+ case maps:take(Key, Map) of
+ {_, Map1} when map_size(Map1) =:= 0 ->
+ concat(E1, Env);
+ {_, Map1} ->
+ [E1, {rec, Map1, Map0} | Env];
+ error ->
[E1, E | delete(Key, Env)]
end.
-concat({map, D1}, [{map, D2} | Env]) ->
- [dict:merge(fun (_K, V1, _V2) -> V1 end, D1, D2) | Env];
+concat({map, M1}, [{map, M2} | Env]) ->
+ [maps:merge(M2, M1) | Env];
concat(E1, Env) ->
[E1 | Env].
@@ -392,15 +375,15 @@ bind_recursive([], [], _, Env) ->
Env;
bind_recursive(Ks, Vs, F, Env) ->
F1 = fun (V) ->
- fun (Dict) -> F(V, [{rec, Dict, Dict} | Env]) end
+ fun (Map) -> F(V, [{rec, Map, Map} | Env]) end
end,
- Dict = bind_recursive_1(Ks, Vs, F1, dict:new()),
- [{rec, Dict, Dict} | Env].
+ Map = bind_recursive_1(Ks, Vs, F1, #{}),
+ [{rec, Map, Map} | Env].
-bind_recursive_1([K | Ks], [V | Vs], F, Dict) ->
- bind_recursive_1(Ks, Vs, F, dict:store(K, F(V), Dict));
-bind_recursive_1([], [], _, Dict) ->
- Dict.
+bind_recursive_1([K | Ks], [V | Vs], F, Map) ->
+ bind_recursive_1(Ks, Vs, F, maps:put(K, F(V), Map));
+bind_recursive_1([], [], _, Map) ->
+ Map.
%% =====================================================================
@@ -416,8 +399,8 @@ bind_recursive_1([], [], _, Dict) ->
-spec lookup(term(), environment()) -> 'error' | {'ok', term()}.
-lookup(Key, [{map, Dict} | Env]) ->
- case dict:find(Key, Dict) of
+lookup(Key, [{map, Map} | Env]) ->
+ case maps:find(Key, Map) of
{ok, _}=Value ->
Value;
error when Env =:= [] ->
@@ -425,10 +408,10 @@ lookup(Key, [{map, Dict} | Env]) ->
error ->
lookup(Key, Env)
end;
-lookup(Key, [{rec, Dict, Dict0} | Env]) ->
- case dict:find(Key, Dict) of
+lookup(Key, [{rec, Map, Map0} | Env]) ->
+ case maps:find(Key, Map) of
{ok, F} ->
- {ok, F(Dict0)};
+ {ok, F(Map0)};
error ->
lookup(Key, Env)
end.
@@ -598,7 +581,17 @@ start_range(Env) ->
%% (pseudo-)randomly distributed over the range.
generate(_N, Range) ->
- random:uniform(Range). % works well
+ %% We must use the same sequence of random variables to ensure
+ %% that two compilations of the same source code generates the
+ %% same BEAM code.
+ case rand:export_seed() of
+ undefined ->
+ _ = rand:seed(exsplus, {1,42,2053}),
+ ok;
+ _ ->
+ ok
+ end,
+ rand:uniform(Range). % works well
%% =====================================================================
diff --git a/lib/compiler/src/sys_core_bsm.erl b/lib/compiler/src/sys_core_bsm.erl
new file mode 100644
index 0000000000..3e04cc33df
--- /dev/null
+++ b/lib/compiler/src/sys_core_bsm.erl
@@ -0,0 +1,355 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. 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%
+%%
+%% Purpose : Optimize bit syntax matching.
+
+
+-module(sys_core_bsm).
+-export([module/2,format_error/1]).
+
+-include("core_parse.hrl").
+-import(lists, [member/2,nth/2,reverse/1,usort/1]).
+
+-spec module(cerl:c_module(), [compile:option()]) -> {'ok', cerl:c_module()}.
+
+module(#c_module{defs=Ds0}=Mod, Opts) ->
+ {Ds,Ws0} = function(Ds0, [], []),
+ case member(bin_opt_info, Opts) of
+ false ->
+ {ok,Mod#c_module{defs=Ds}};
+ true ->
+ Ws1 = [make_warning(Where, What) || {Where,What} <- Ws0],
+ Ws = usort(Ws1),
+ {ok,Mod#c_module{defs=Ds},Ws}
+ end.
+
+function([{#c_var{name={F,Arity}}=Name,B0}|Fs], FsAcc, Ws0) ->
+ try cerl_trees:mapfold(fun bsm_an/2, Ws0, B0) of
+ {B,Ws} ->
+ function(Fs, [{Name,B}|FsAcc], Ws)
+ catch
+ Class:Error ->
+ Stack = erlang:get_stacktrace(),
+ io:fwrite("Function: ~w/~w\n", [F,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end;
+function([], Fs, Ws) ->
+ {reverse(Fs),Ws}.
+
+-type error() :: atom().
+-spec format_error(error()) -> nonempty_string().
+
+format_error(bin_opt_alias) ->
+ "INFO: the '=' operator will prevent delayed sub binary optimization";
+format_error(bin_partition) ->
+ "INFO: matching non-variables after a previous clause matching a variable "
+ "will prevent delayed sub binary optimization";
+format_error(bin_left_var_used_in_guard) ->
+ "INFO: a variable to the left of the binary pattern is used in a guard; "
+ "will prevent delayed sub binary optimization";
+format_error(bin_argument_order) ->
+ "INFO: matching anything else but a plain variable to the left of "
+ "binary pattern will prevent delayed sub binary optimization; "
+ "SUGGEST changing argument order";
+format_error(bin_var_used) ->
+ "INFO: using a matched out sub binary will prevent "
+ "delayed sub binary optimization";
+format_error(orig_bin_var_used_in_guard) ->
+ "INFO: using the original binary variable in a guard will prevent "
+ "delayed sub binary optimization";
+format_error(bin_var_used_in_guard) ->
+ "INFO: using a matched out sub binary in a guard will prevent "
+ "delayed sub binary optimization".
+
+
+%%%
+%%% Annotate bit syntax matching to faciliate optimization in further passes.
+%%%
+
+bsm_an(Core0, Ws0) ->
+ case bsm_an(Core0) of
+ {ok,Core} ->
+ {Core,Ws0};
+ {ok,Core,W} ->
+ {Core,[W|Ws0]}
+ end.
+
+bsm_an(#c_case{arg=#c_var{}=V}=Case) ->
+ bsm_an_1([V], Case);
+bsm_an(#c_case{arg=#c_values{es=Es}}=Case) ->
+ bsm_an_1(Es, Case);
+bsm_an(Other) ->
+ {ok,Other}.
+
+bsm_an_1(Vs, #c_case{clauses=Cs}=Case) ->
+ case bsm_leftmost(Cs) of
+ none -> {ok,Case};
+ Pos -> bsm_an_2(Vs, Cs, Case, Pos)
+ end.
+
+bsm_an_2(Vs, Cs, Case, Pos) ->
+ case bsm_nonempty(Cs, Pos) of
+ true -> bsm_an_3(Vs, Cs, Case, Pos);
+ false -> {ok,Case}
+ end.
+
+bsm_an_3(Vs, Cs, Case, Pos) ->
+ try
+ bsm_ensure_no_partition(Cs, Pos),
+ {ok,bsm_do_an(Vs, Pos, Cs, Case)}
+ catch
+ throw:{problem,Where,What} ->
+ {ok,Case,{Where,What}}
+ end.
+
+bsm_do_an(Vs0, Pos, Cs0, Case) ->
+ case nth(Pos, Vs0) of
+ #c_var{name=Vname}=V0 ->
+ Cs = bsm_do_an_var(Vname, Pos, Cs0, []),
+ V = bsm_annotate_for_reuse(V0),
+ Bef = lists:sublist(Vs0, Pos-1),
+ Aft = lists:nthtail(Pos, Vs0),
+ case Bef ++ [V|Aft] of
+ [_] ->
+ Case#c_case{arg=V,clauses=Cs};
+ Vs ->
+ Case#c_case{arg=#c_values{es=Vs},clauses=Cs}
+ end;
+ _ ->
+ Case
+ end.
+
+bsm_do_an_var(V, S, [#c_clause{pats=Ps,guard=G,body=B0}=C0|Cs], Acc) ->
+ case nth(S, Ps) of
+ #c_var{name=VarName} ->
+ case core_lib:is_var_used(V, G) of
+ true -> bsm_problem(C0, orig_bin_var_used_in_guard);
+ false -> ok
+ end,
+ case core_lib:is_var_used(VarName, G) of
+ true -> bsm_problem(C0, bin_var_used_in_guard);
+ false -> ok
+ end,
+ B1 = bsm_maybe_ctx_to_binary(VarName, B0),
+ B = bsm_maybe_ctx_to_binary(V, B1),
+ C = C0#c_clause{body=B},
+ bsm_do_an_var(V, S, Cs, [C|Acc]);
+ #c_alias{}=P ->
+ case bsm_could_match_binary(P) of
+ false ->
+ bsm_do_an_var(V, S, Cs, [C0|Acc]);
+ true ->
+ bsm_problem(C0, bin_opt_alias)
+ end;
+ P ->
+ case bsm_could_match_binary(P) andalso bsm_is_var_used(V, G, B0) of
+ false ->
+ bsm_do_an_var(V, S, Cs, [C0|Acc]);
+ true ->
+ bsm_problem(C0, bin_var_used)
+ end
+ end;
+bsm_do_an_var(_, _, [], Acc) -> reverse(Acc).
+
+bsm_annotate_for_reuse(#c_var{anno=Anno}=Var) ->
+ Var#c_var{anno=[reuse_for_context|Anno]}.
+
+bsm_is_var_used(V, G, B) ->
+ core_lib:is_var_used(V, G) orelse core_lib:is_var_used(V, B).
+
+bsm_maybe_ctx_to_binary(V, B) ->
+ case core_lib:is_var_used(V, B) andalso not previous_ctx_to_binary(V, B) of
+ false ->
+ B;
+ true ->
+ #c_seq{arg=#c_primop{name=#c_literal{val=bs_context_to_binary},
+ args=[#c_var{name=V}]},
+ body=B}
+ end.
+
+previous_ctx_to_binary(V, Core) ->
+ case Core of
+ #c_seq{arg=#c_primop{name=#c_literal{val=bs_context_to_binary},
+ args=[#c_var{name=V}]}} ->
+ true;
+ _ ->
+ false
+ end.
+
+%% bsm_leftmost(Cs) -> none | ArgumentNumber
+%% Find the leftmost argument that does binary matching. Return
+%% the number of the argument (1-N).
+
+bsm_leftmost(Cs) ->
+ bsm_leftmost_1(Cs, none).
+
+bsm_leftmost_1([#c_clause{pats=Ps}|Cs], Pos) ->
+ bsm_leftmost_2(Ps, Cs, 1, Pos);
+bsm_leftmost_1([], Pos) -> Pos.
+
+bsm_leftmost_2(_, Cs, Pos, Pos) ->
+ bsm_leftmost_1(Cs, Pos);
+bsm_leftmost_2([#c_binary{}|_], Cs, N, _) ->
+ bsm_leftmost_1(Cs, N);
+bsm_leftmost_2([_|Ps], Cs, N, Pos) ->
+ bsm_leftmost_2(Ps, Cs, N+1, Pos);
+bsm_leftmost_2([], Cs, _, Pos) ->
+ bsm_leftmost_1(Cs, Pos).
+
+%% bsm_nonempty(Cs, Pos) -> true|false
+%% Check if at least one of the clauses matches a non-empty
+%% binary in the given argument position.
+%%
+bsm_nonempty([#c_clause{pats=Ps}|Cs], Pos) ->
+ case nth(Pos, Ps) of
+ #c_binary{segments=[_|_]} ->
+ true;
+ _ ->
+ bsm_nonempty(Cs, Pos)
+ end;
+bsm_nonempty([], _ ) -> false.
+
+%% bsm_ensure_no_partition(Cs, Pos) -> ok (exception if problem)
+%% We must make sure that matching is not partitioned between
+%% variables like this:
+%% foo(<<...>>) -> ...
+%% foo(<Variable>) when ... -> ...
+%% foo(<Any non-variable pattern>) ->
+%% If there is such partition, we are not allowed to reuse the binary variable
+%% for the match context.
+%%
+%% Also, arguments to the left of the argument that is matched
+%% against a binary, are only allowed to be simple variables, not
+%% used in guards. The reason is that we must know that the binary is
+%% only matched in one place (i.e. there must be only one bs_start_match2
+%% instruction emitted).
+
+bsm_ensure_no_partition(Cs, Pos) ->
+ bsm_ensure_no_partition_1(Cs, Pos, before).
+
+%% Loop through each clause.
+bsm_ensure_no_partition_1([#c_clause{pats=Ps,guard=G}|Cs], Pos, State0) ->
+ State = bsm_ensure_no_partition_2(Ps, Pos, G, simple_vars, State0),
+ case State of
+ 'after' ->
+ bsm_ensure_no_partition_after(Cs, Pos);
+ _ ->
+ ok
+ end,
+ bsm_ensure_no_partition_1(Cs, Pos, State);
+bsm_ensure_no_partition_1([], _, _) -> ok.
+
+%% Loop through each pattern for this clause.
+bsm_ensure_no_partition_2([#c_binary{}=Where|_], 1, _, Vstate, State) ->
+ case State of
+ before when Vstate =:= simple_vars -> within;
+ before -> bsm_problem(Where, Vstate);
+ within when Vstate =:= simple_vars -> within;
+ within -> bsm_problem(Where, Vstate)
+ end;
+bsm_ensure_no_partition_2([#c_alias{}=Alias|_], 1, N, Vstate, State) ->
+ %% Retrieve the real pattern that the alias refers to and check that.
+ P = bsm_real_pattern(Alias),
+ bsm_ensure_no_partition_2([P], 1, N, Vstate, State);
+bsm_ensure_no_partition_2([_|_], 1, _, _Vstate, before=State) ->
+ %% No binary matching yet - therefore no partition.
+ State;
+bsm_ensure_no_partition_2([P|_], 1, _, Vstate, State) ->
+ case bsm_could_match_binary(P) of
+ false ->
+ %% If clauses can be freely arranged (Vstate =:= simple_vars),
+ %% a clause that cannot match a binary will not partition the clause.
+ %% Example:
+ %%
+ %% a(Var, <<>>) -> ...
+ %% a(Var, []) -> ...
+ %% a(Var, <<B>>) -> ...
+ %%
+ %% But if the clauses can't be freely rearranged, as in
+ %%
+ %% b(Var, <<X>>) -> ...
+ %% b(1, 2) -> ...
+ %%
+ %% we do have a problem.
+ %%
+ case Vstate of
+ simple_vars -> State;
+ _ -> bsm_problem(P, Vstate)
+ end;
+ true ->
+ %% The pattern P *may* match a binary, so we must update the state.
+ %% (P must be a variable.)
+ case State of
+ within -> 'after';
+ 'after' -> 'after'
+ end
+ end;
+bsm_ensure_no_partition_2([#c_var{name=V}|Ps], N, G, Vstate, S) ->
+ case core_lib:is_var_used(V, G) of
+ false ->
+ bsm_ensure_no_partition_2(Ps, N-1, G, Vstate, S);
+ true ->
+ bsm_ensure_no_partition_2(Ps, N-1, G, bin_left_var_used_in_guard, S)
+ end;
+bsm_ensure_no_partition_2([_|Ps], N, G, _, S) ->
+ bsm_ensure_no_partition_2(Ps, N-1, G, bin_argument_order, S).
+
+bsm_ensure_no_partition_after([#c_clause{pats=Ps}=C|Cs], Pos) ->
+ case nth(Pos, Ps) of
+ #c_var{} ->
+ bsm_ensure_no_partition_after(Cs, Pos);
+ _ ->
+ bsm_problem(C, bin_partition)
+ end;
+bsm_ensure_no_partition_after([], _) -> ok.
+
+bsm_could_match_binary(#c_alias{pat=P}) -> bsm_could_match_binary(P);
+bsm_could_match_binary(#c_cons{}) -> false;
+bsm_could_match_binary(#c_tuple{}) -> false;
+bsm_could_match_binary(#c_literal{val=Lit}) -> is_bitstring(Lit);
+bsm_could_match_binary(_) -> true.
+
+bsm_real_pattern(#c_alias{pat=P}) -> bsm_real_pattern(P);
+bsm_real_pattern(P) -> P.
+
+bsm_problem(Where, What) ->
+ throw({problem,Where,What}).
+
+make_warning(Core, Term) ->
+ case should_suppress_warning(Core) of
+ true ->
+ ok;
+ false ->
+ Anno = cerl:get_ann(Core),
+ Line = get_line(Anno),
+ File = get_file(Anno),
+ {File,[{Line,?MODULE,Term}]}
+ end.
+
+should_suppress_warning(Core) ->
+ Ann = cerl:get_ann(Core),
+ member(compiler_generated, Ann).
+
+get_line([Line|_]) when is_integer(Line) -> Line;
+get_line([_|T]) -> get_line(T);
+get_line([]) -> none.
+
+get_file([{file,File}|_]) -> File;
+get_file([_|T]) -> get_file(T);
+get_file([]) -> "no_file". % should not happen
diff --git a/lib/compiler/src/sys_core_dsetel.erl b/lib/compiler/src/sys_core_dsetel.erl
index ac32db10fe..bd3eeae238 100644
--- a/lib/compiler/src/sys_core_dsetel.erl
+++ b/lib/compiler/src/sys_core_dsetel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -72,7 +72,7 @@ module(M0, _Options) ->
{ok,M}.
visit_module(#c_module{defs=Ds0}=R) ->
- Env = dict:new(),
+ Env = #{},
Ds = visit_module_1(Ds0, Env, []),
R#c_module{defs=Ds}.
@@ -95,9 +95,11 @@ visit(Env, #c_var{name={_,_}}=R) ->
{R, Env};
visit(Env0, #c_var{name=X}=R) ->
%% There should not be any free variables. If there are,
- %% the next line will cause an exception.
- {ok, N} = dict:find(X, Env0),
- {R, dict:store(X, N+1, Env0)};
+ %% the case will fail with an exception.
+ case Env0 of
+ #{X:=N} ->
+ {R, Env0#{X:=N+1}}
+ end;
visit(Env, #c_literal{}=R) ->
{R, Env};
visit(Env0, #c_tuple{es=Es0}=R) ->
@@ -203,7 +205,7 @@ bind_vars(Vs, Env) ->
bind_vars(Vs, Env, []).
bind_vars([#c_var{name=X}|Vs], Env0, Xs)->
- bind_vars(Vs, dict:store(X, 0, Env0), [X|Xs]);
+ bind_vars(Vs, Env0#{X=>0}, [X|Xs]);
bind_vars([], Env,Xs) ->
{Xs, Env}.
@@ -217,7 +219,7 @@ visit_pats([], Env, Vs) ->
{Vs, Env}.
visit_pat(Env0, #c_var{name=V}, Vs) ->
- {[V|Vs], dict:store(V, 0, Env0)};
+ {[V|Vs], Env0#{V=>0}};
visit_pat(Env0, #c_tuple{es=Es}, Vs) ->
visit_pats(Es, Env0, Vs);
visit_pat(Env0, #c_map{es=Es}, Vs) ->
@@ -235,23 +237,25 @@ visit_pat(Env0, #c_bitstr{val=Val,size=Sz}, Vs0) ->
case Sz of
#c_var{name=V} ->
%% We don't tolerate free variables.
- {ok, N} = dict:find(V, Env0),
- {Vs0, dict:store(V, N+1, Env0)};
+ case Env0 of
+ #{V:=N} ->
+ {Vs0, Env0#{V:=N+1}}
+ end;
_ ->
visit_pat(Env0, Sz, Vs0)
end,
visit_pat(Env1, Val, Vs1);
visit_pat(Env0, #c_alias{pat=P,var=#c_var{name=V}}, Vs) ->
- visit_pat(dict:store(V, 0, Env0), P, [V|Vs]);
+ visit_pat(Env0#{V=>0}, P, [V|Vs]);
visit_pat(Env, #c_literal{}, Vs) ->
{Vs, Env}.
restore_vars([V|Vs], Env0, Env1) ->
- case dict:find(V, Env0) of
- {ok, N} ->
- restore_vars(Vs, Env0, dict:store(V, N, Env1));
- error ->
- restore_vars(Vs, Env0, dict:erase(V, Env1))
+ case Env0 of
+ #{V:=N} ->
+ restore_vars(Vs, Env0, Env1#{V=>N});
+ _ ->
+ restore_vars(Vs, Env0, maps:remove(V, Env1))
end;
restore_vars([], _, Env1) ->
Env1.
@@ -349,8 +353,8 @@ is_safe(#c_literal{}) -> true;
is_safe(_) -> false.
is_single_use(V, Env) ->
- case dict:find(V, Env) of
- {ok, 1} ->
+ case Env of
+ #{V:=1} ->
true;
_ ->
false
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 65699ccda9..d73060fb7e 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. 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.
@@ -71,7 +71,7 @@
-export([module/2,format_error/1]).
-import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,all/2,any/2,
- reverse/1,reverse/2,member/2,nth/2,flatten/1,
+ reverse/1,reverse/2,member/2,flatten/1,
unzip/1,keyfind/3]).
-import(cerl, [ann_c_cons/3,ann_c_map/3,ann_c_tuple/2]).
@@ -83,10 +83,11 @@
-ifdef(DEBUG).
-define(ASSERT(E),
case E of
- true -> ok;
+ true ->
+ ok;
false ->
io:format("~p, line ~p: assertion failed\n", [?MODULE,?LINE]),
- exit(assertion_failed)
+ error(assertion_failed)
end).
-else.
-define(ASSERT(E), ignore).
@@ -106,7 +107,6 @@
{'ok', cerl:c_module(), [_]}.
module(#c_module{defs=Ds0}=Mod, Opts) ->
- put(bin_opt_info, member(bin_opt_info, Opts)),
put(no_inline_list_funcs, not member(inline_list_funcs, Opts)),
case get(new_var_num) of
undefined -> put(new_var_num, 0);
@@ -115,12 +115,14 @@ module(#c_module{defs=Ds0}=Mod, Opts) ->
init_warnings(),
Ds1 = [function_1(D) || D <- Ds0],
erase(no_inline_list_funcs),
- erase(bin_opt_info),
{ok,Mod#c_module{defs=Ds1},get_warnings()}.
function_1({#c_var{name={F,Arity}}=Name,B0}) ->
try
- B = expr(B0, value, sub_new()), %This must be a fun!
+ B = find_fixpoint(fun(Core) ->
+ %% This must be a fun!
+ expr(Core, value, sub_new())
+ end, B0, 20),
{Name,B}
catch
Class:Error ->
@@ -129,6 +131,14 @@ function_1({#c_var{name={F,Arity}}=Name,B0}) ->
erlang:raise(Class, Error, Stack)
end.
+find_fixpoint(_OptFun, Core, 0) ->
+ Core;
+find_fixpoint(OptFun, Core0, Max) ->
+ case OptFun(Core0) of
+ Core0 -> Core0;
+ Core -> find_fixpoint(OptFun, Core, Max-1)
+ end.
+
%% body(Expr, Sub) -> Expr.
%% body(Expr, Context, Sub) -> Expr.
%% No special handling of anything except values.
@@ -160,13 +170,23 @@ guard(Expr, Sub) ->
%%
opt_guard_try(#c_seq{arg=Arg,body=Body0}=Seq) ->
Body = opt_guard_try(Body0),
- case {Arg,Body} of
- {#c_call{module=#c_literal{val=Mod},
- name=#c_literal{val=Name},
- args=Args},#c_literal{val=false}} ->
+ WillFail = case Body of
+ #c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=error},
+ args=[_]} ->
+ true;
+ #c_literal{val=false} ->
+ true;
+ _ ->
+ false
+ end,
+ case Arg of
+ #c_call{module=#c_literal{val=Mod},
+ name=#c_literal{val=Name},
+ args=Args} when WillFail ->
%% We have sequence consisting of a call (evaluated
%% for a possible exception and/or side effect only),
- %% followed by 'false'.
+ %% followed by 'false' or a call to error/1.
%% Since the sequence is inside a try block that will
%% default to 'false' if any exception occurs, not
%% evalutating the call will not change the behaviour
@@ -181,7 +201,7 @@ opt_guard_try(#c_seq{arg=Arg,body=Body0}=Seq) ->
%% be safely removed.
Body
end;
- {_,_} ->
+ _ ->
Seq#c_seq{body=Body}
end;
opt_guard_try(#c_case{clauses=Cs}=Term) ->
@@ -239,7 +259,7 @@ expr(#c_cons{anno=Anno,hd=H0,tl=T0}=Cons, Ctxt, Sub) ->
case Ctxt of
effect ->
add_warning(Cons, useless_building),
- expr(make_effect_seq([H1,T1], Sub), Ctxt, Sub);
+ make_effect_seq([H1,T1], Sub);
value ->
ann_c_cons(Anno, H1, T1)
end;
@@ -248,7 +268,7 @@ expr(#c_tuple{anno=Anno,es=Es0}=Tuple, Ctxt, Sub) ->
case Ctxt of
effect ->
add_warning(Tuple, useless_building),
- expr(make_effect_seq(Es, Sub), Ctxt, Sub);
+ make_effect_seq(Es, Sub);
value ->
ann_c_tuple(Anno, Es)
end;
@@ -257,7 +277,7 @@ expr(#c_map{anno=Anno,arg=V0,es=Es0}=Map, Ctxt, Sub) ->
case Ctxt of
effect ->
add_warning(Map, useless_building),
- expr(make_effect_seq(Es, Sub), Ctxt, Sub);
+ make_effect_seq(Es, Sub);
value ->
V = expr(V0, Ctxt, Sub),
ann_c_map(Anno,V,Es)
@@ -277,7 +297,7 @@ expr(#c_fun{}=Fun, effect, _) ->
add_warning(Fun, useless_building),
void();
expr(#c_fun{vars=Vs0,body=B0}=Fun, Ctxt0, Sub0) ->
- {Vs1,Sub1} = pattern_list(Vs0, Sub0),
+ {Vs1,Sub1} = var_list(Vs0, Sub0),
Ctxt = case Ctxt0 of
{letrec,Ctxt1} -> Ctxt1;
value -> value
@@ -310,7 +330,7 @@ expr(#c_let{}=Let0, Ctxt, Sub) ->
Expr ->
%% The let body was successfully moved into the let argument.
%% Now recursively re-process the new expression.
- expr(Expr, Ctxt, sub_new_preserve_types(Sub))
+ Expr
end;
expr(#c_letrec{body=#c_var{}}=Letrec, effect, _Sub) ->
%% This is named fun in an 'effect' context. Warn and ignore.
@@ -351,7 +371,7 @@ expr(#c_case{}=Case0, Ctxt, Sub) ->
%% (in addition to any warnings that may have been emitted
%% according to the rules above).
%%
- case opt_bool_case(Case0) of
+ case opt_bool_case(Case0, Sub) of
#c_case{arg=Arg0,clauses=Cs0}=Case1 ->
Arg1 = body(Arg0, value, Sub),
LitExpr = cerl:is_literal(Arg1),
@@ -361,10 +381,8 @@ expr(#c_case{}=Case0, Ctxt, Sub) ->
warn_no_clause_match(Case1, Case),
Expr = eval_case(Case, Sub),
case move_case_into_arg(Case, Sub) of
- impossible ->
- bsm_an(Expr);
- Other ->
- expr(Other, Ctxt, sub_new_preserve_types(Sub))
+ impossible -> Expr;
+ Other -> Other
end;
Other ->
expr(Other, Ctxt, Sub)
@@ -374,10 +392,21 @@ expr(#c_receive{clauses=Cs0,timeout=T0,action=A0}=Recv, Ctxt, Sub) ->
T1 = expr(T0, value, Sub),
A1 = body(A0, Ctxt, Sub),
Recv#c_receive{clauses=Cs1,timeout=T1,action=A1};
-expr(#c_apply{op=Op0,args=As0}=App, _, Sub) ->
+expr(#c_apply{anno=Anno,op=Op0,args=As0}=App, _, Sub) ->
Op1 = expr(Op0, value, Sub),
As1 = expr_list(As0, value, Sub),
- App#c_apply{op=Op1,args=As1};
+ case cerl:is_data(Op1) of
+ false ->
+ App#c_apply{op=Op1,args=As1};
+ true ->
+ add_warning(App, invalid_call),
+ Err = #c_call{anno=Anno,
+ module=#c_literal{val=erlang},
+ name=#c_literal{val=error},
+ args=[#c_tuple{es=[#c_literal{val='badfun'},
+ Op1]}]},
+ make_effect_seq(As1++[Err], Sub)
+ end;
expr(#c_call{module=M0,name=N0}=Call0, Ctxt, Sub) ->
M1 = expr(M0, value, Sub),
N1 = expr(N0, value, Sub),
@@ -420,13 +449,13 @@ expr(#c_try{anno=A,arg=E0,vars=Vs0,body=B0,evars=Evs0,handler=H0}=Try, _, Sub0)
%% Here is the general try/catch construct outside of guards.
%% We can remove try if the value is simple and replace it with a let.
E1 = body(E0, value, Sub0),
- {Vs1,Sub1} = pattern_list(Vs0, Sub0),
+ {Vs1,Sub1} = var_list(Vs0, Sub0),
B1 = body(B0, value, Sub1),
case is_safe_simple(E1, Sub0) of
true ->
expr(#c_let{anno=A,vars=Vs1,arg=E1,body=B1}, value, Sub0);
false ->
- {Evs1,Sub2} = pattern_list(Evs0, Sub0),
+ {Evs1,Sub2} = var_list(Evs0, Sub0),
H1 = body(H0, value, Sub2),
Try#c_try{arg=E1,vars=Vs1,body=B1,evars=Evs1,handler=H1}
end.
@@ -457,7 +486,8 @@ bitstr(#c_bitstr{val=Val,size=Size}=BinSeg, Sub) ->
%% Currently, we don't attempt to check binaries because they
%% are difficult to check.
-is_safe_simple(#c_var{}, _) -> true;
+is_safe_simple(#c_var{}=Var, _) ->
+ not cerl:is_c_fname(Var);
is_safe_simple(#c_cons{hd=H,tl=T}, Sub) ->
is_safe_simple(H, Sub) andalso is_safe_simple(T, Sub);
is_safe_simple(#c_tuple{es=Es}, Sub) -> is_safe_simple_list(Es, Sub);
@@ -722,7 +752,7 @@ call(#c_call{args=As}=Call, #c_literal{val=M}=M0, #c_literal{val=N}=N0, Sub) ->
false ->
case sys_core_fold_lists:call(Call, M, N, As) of
none ->
- call_1(Call, M, N, As, Sub);
+ call_1(Call, M0, N0, As, Sub);
Core ->
expr(Core, Sub)
end
@@ -775,7 +805,7 @@ fold_lit_args(Call, Module, Name, Args0) ->
Val ->
case cerl:is_literal_term(Val) of
true ->
- cerl:abstract(Val);
+ cerl:ann_abstract(cerl:get_ann(Call), Val);
false ->
%% Successful evaluation, but it was not possible
%% to express the computed value as a literal.
@@ -1078,15 +1108,28 @@ is_atom_or_var(_) -> false.
%% clause(Clause, Cepxr, Context, Sub) -> Clause.
-clause(#c_clause{pats=Ps0,guard=G0,body=B0}=Cl, Cexpr, Ctxt, Sub0) ->
- {Ps1,Sub1} = pattern_list(Ps0, Sub0),
+clause(#c_clause{pats=Ps0}=Cl, Cexpr, Ctxt, Sub0) ->
+ try pattern_list(Ps0, Sub0) of
+ {Ps1,Sub1} ->
+ clause_1(Cl, Ps1, Cexpr, Ctxt, Sub1)
+ catch
+ nomatch ->
+ Cl#c_clause{anno=[compiler_generated],
+ guard=#c_literal{val=false}}
+ end.
+
+clause_1(#c_clause{guard=G0,body=B0}=Cl, Ps1, Cexpr, Ctxt, Sub1) ->
Sub2 = update_types(Cexpr, Ps1, Sub1),
- GSub = case {Cexpr,Ps1} of
- {#c_var{name='_'},_} ->
+ GSub = case {Cexpr,Ps1,G0} of
+ {_,_,#c_literal{}} ->
+ %% No need for substitution tricks when the guard
+ %% does not contain any variables.
+ Sub2;
+ {#c_var{name='_'},_,_} ->
%% In a 'receive', Cexpr is the variable '_', which represents the
%% message being matched. We must NOT do any extra substiutions.
Sub2;
- {#c_var{},[#c_var{}=Var]} ->
+ {#c_var{},[#c_var{}=Var],_} ->
%% The idea here is to optimize expressions such as
%%
%% case A of A -> ...
@@ -1105,7 +1148,13 @@ clause(#c_clause{pats=Ps0,guard=G0,body=B0}=Cl, Cexpr, Ctxt, Sub0) ->
%%
%% case A of NewVar when true -> ...
%%
- sub_set_var(Var, Cexpr, Sub2);
+ case cerl:is_c_fname(Cexpr) of
+ false ->
+ sub_set_var(Var, Cexpr, Sub2);
+ true ->
+ %% We must not copy funs, and especially not into guards.
+ Sub2
+ end;
_ ->
Sub2
end,
@@ -1120,7 +1169,7 @@ clause(#c_clause{pats=Ps0,guard=G0,body=B0}=Cl, Cexpr, Ctxt, Sub0) ->
%% the unsubstituted variables and values.
let_substs(Vs0, As0, Sub0) ->
- {Vs1,Sub1} = pattern_list(Vs0, Sub0),
+ {Vs1,Sub1} = var_list(Vs0, Sub0),
{Vs2,As1,Ss} = let_substs_1(Vs1, As0, Sub1),
Sub2 = sub_add_scope([V || #c_var{name=V} <- Vs2], Sub1),
{Vs2,As1,
@@ -1206,20 +1255,132 @@ bin_pattern_list(Ps0, Isub, Osub0) ->
{Ps,{_,Osub}} = mapfoldl(fun bin_pattern/2, {Isub,Osub0}, Ps0),
{Ps,Osub}.
-bin_pattern(#c_bitstr{val=E0,size=Size0}=Pat, {Isub0,Osub0}) ->
+bin_pattern(#c_bitstr{val=E0,size=Size0}=Pat0, {Isub0,Osub0}) ->
Size1 = expr(Size0, Isub0),
{E1,Osub} = pattern(E0, Isub0, Osub0),
Isub = case E0 of
#c_var{} -> sub_set_var(E0, E1, Isub0);
_ -> Isub0
end,
- {Pat#c_bitstr{val=E1,size=Size1},{Isub,Osub}}.
+ Pat = Pat0#c_bitstr{val=E1,size=Size1},
+ bin_pat_warn(Pat),
+ {Pat,{Isub,Osub}}.
pattern_list(Ps, Sub) -> pattern_list(Ps, Sub, Sub).
pattern_list(Ps0, Isub, Osub0) ->
mapfoldl(fun (P, Osub) -> pattern(P, Isub, Osub) end, Osub0, Ps0).
+%% var_list([Var], InSub) -> {Pattern,OutSub}.
+%% Works like pattern_list/2 but only accept variables and is
+%% guaranteed not to throw an exception.
+
+var_list(Vs, Sub0) ->
+ mapfoldl(fun (#c_var{}=V, Sub) ->
+ pattern(V, Sub, Sub)
+ end, Sub0, Vs).
+
+
+%%%
+%%% Generate warnings for binary patterns that will not match.
+%%%
+
+bin_pat_warn(#c_bitstr{type=#c_literal{val=Type},
+ val=Val0,
+ size=#c_literal{val=Sz},
+ unit=#c_literal{val=Unit},
+ flags=Fl}=Pat) ->
+ case {Type,Sz} of
+ {_,_} when is_integer(Sz), Sz >= 0 -> ok;
+ {binary,all} -> ok;
+ {utf8,undefined} -> ok;
+ {utf16,undefined} -> ok;
+ {utf32,undefined} -> ok;
+ {_,_} ->
+ add_warning(Pat, {nomatch_bit_syntax_size,Sz}),
+ throw(nomatch)
+ end,
+ case {Type,Val0} of
+ {integer,#c_literal{val=Val}} when is_integer(Val) ->
+ Signedness = signedness(Fl),
+ TotalSz = Sz * Unit,
+ bit_pat_warn_int(Val, TotalSz, Signedness, Pat);
+ {float,#c_literal{val=Val}} when is_float(Val) ->
+ ok;
+ {utf8,#c_literal{val=Val}} when is_integer(Val) ->
+ bit_pat_warn_unicode(Val, Pat);
+ {utf16,#c_literal{val=Val}} when is_integer(Val) ->
+ bit_pat_warn_unicode(Val, Pat);
+ {utf32,#c_literal{val=Val}} when is_integer(Val) ->
+ bit_pat_warn_unicode(Val, Pat);
+ {_,#c_literal{val=Val}} ->
+ add_warning(Pat, {nomatch_bit_syntax_type,Val,Type}),
+ throw(nomatch);
+ {_,_} ->
+ ok
+ end;
+bin_pat_warn(#c_bitstr{type=#c_literal{val=Type},val=Val0,flags=Fl}=Pat) ->
+ %% Size is variable. Not much that we can check.
+ case {Type,Val0} of
+ {integer,#c_literal{val=Val}} when is_integer(Val) ->
+ case signedness(Fl) of
+ unsigned when Val < 0 ->
+ add_warning(Pat, {nomatch_bit_syntax_unsigned,Val}),
+ throw(nomatch);
+ _ ->
+ ok
+ end;
+ {float,#c_literal{val=Val}} when is_float(Val) ->
+ ok;
+ {_,#c_literal{val=Val}} ->
+ add_warning(Pat, {nomatch_bit_syntax_type,Val,Type}),
+ throw(nomatch);
+ {_,_} ->
+ ok
+ end.
+
+bit_pat_warn_int(Val, 0, signed, Pat) ->
+ if
+ Val =:= 0 ->
+ ok;
+ true ->
+ add_warning(Pat, {nomatch_bit_syntax_truncated,signed,Val,0}),
+ throw(nomatch)
+ end;
+bit_pat_warn_int(Val, Sz, signed, Pat) ->
+ if
+ Val < 0, Val bsr (Sz - 1) =/= -1 ->
+ add_warning(Pat, {nomatch_bit_syntax_truncated,signed,Val,Sz}),
+ throw(nomatch);
+ Val > 0, Val bsr (Sz - 1) =/= 0 ->
+ add_warning(Pat, {nomatch_bit_syntax_truncated,signed,Val,Sz}),
+ throw(nomatch);
+ true ->
+ ok
+ end;
+bit_pat_warn_int(Val, _Sz, unsigned, Pat) when Val < 0 ->
+ add_warning(Pat, {nomatch_bit_syntax_unsigned,Val}),
+ throw(nomatch);
+bit_pat_warn_int(Val, Sz, unsigned, Pat) ->
+ if
+ Val bsr Sz =:= 0 ->
+ ok;
+ true ->
+ add_warning(Pat, {nomatch_bit_syntax_truncated,unsigned,Val,Sz}),
+ throw(nomatch)
+ end.
+
+bit_pat_warn_unicode(U, _Pat) when 0 =< U, U =< 16#10FFFF ->
+ ok;
+bit_pat_warn_unicode(U, Pat) ->
+ add_warning(Pat, {nomatch_bit_syntax_unicode,U}),
+ throw(nomatch).
+
+signedness(#c_literal{val=Flags}) ->
+ [S] = [F || F <- Flags, F =:= signed orelse F =:= unsigned],
+ S.
+
+
%% is_subst(Expr) -> true | false.
%% Test whether an expression is a suitable substitution.
@@ -1260,9 +1421,6 @@ sub_new() -> #sub{v=orddict:new(),s=cerl_sets:new(),t=#{}}.
sub_new(#sub{}=Sub) ->
Sub#sub{v=orddict:new(),t=#{}}.
-sub_new_preserve_types(#sub{}=Sub) ->
- Sub#sub{v=orddict:new()}.
-
sub_get_var(#c_var{name=V}=Var, #sub{v=S}) ->
case orddict:find(V, S) of
{ok,Val} -> Val;
@@ -1300,8 +1458,19 @@ sub_add_scope(Vs, #sub{s=Scope0}=Sub) ->
Sub#sub{s=Scope}.
sub_subst_scope(#sub{v=S0,s=Scope}=Sub) ->
- S = [{-1,#c_var{name=Sv}} || Sv <- cerl_sets:to_list(Scope)]++S0,
- Sub#sub{v=S}.
+ Initial = case S0 of
+ [{NegInt,_}|_] when is_integer(NegInt), NegInt < 0 ->
+ NegInt - 1;
+ _ ->
+ -1
+ end,
+ S = sub_subst_scope_1(cerl_sets:to_list(Scope), Initial, S0),
+ Sub#sub{v=orddict:from_list(S)}.
+
+%% The keys in an orddict must be unique. Make them so!
+sub_subst_scope_1([H|T], Key, Acc) ->
+ sub_subst_scope_1(T, Key-1, [{Key,#c_var{name=H}}|Acc]);
+sub_subst_scope_1([], _, Acc) -> Acc.
sub_is_val(#c_var{name=V}, #sub{v=S,s=Scope}) ->
%% When the bottleneck in sub_del_var/2 was eliminated, this
@@ -1392,9 +1561,11 @@ will_match(E, [P]) ->
will_match_1({false,_}) -> maybe;
will_match_1({true,_}) -> yes.
-%% opt_bool_case(CoreExpr) - CoreExpr'.
-%% Do various optimizations to case statement that has a
-%% boolean case expression.
+%% opt_bool_case(CoreExpr, Sub) - CoreExpr'.
+%%
+%% In bodies, do various optimizations to case statements that have
+%% boolean case expressions. We don't do the optimizations in guards,
+%% because they would thwart the optimization in v3_kernel.
%%
%% We start with some simple optimizations and normalization
%% to facilitate later optimizations.
@@ -1403,7 +1574,7 @@ will_match_1({true,_}) -> yes.
%% (or fail), we can remove any clause that cannot
%% possibly match 'true' or 'false'. Also, any clause
%% following both 'true' and 'false' clause can
-%% be removed. If successful, we will end up this:
+%% be removed. If successful, we will end up like this:
%%
%% case BoolExpr of case BoolExpr of
%% true -> false ->
@@ -1414,8 +1585,11 @@ will_match_1({true,_}) -> yes.
%%
%% We give up if there are clauses with guards, or if there
%% is a variable clause that matches anything.
-%%
-opt_bool_case(#c_case{arg=Arg}=Case0) ->
+
+opt_bool_case(#c_case{}=Case, #sub{in_guard=true}) ->
+ %% v3_kernel does a better job without "help".
+ Case;
+opt_bool_case(#c_case{arg=Arg}=Case0, #sub{in_guard=false}) ->
case is_bool_expr(Arg) of
false ->
Case0;
@@ -1427,8 +1601,7 @@ opt_bool_case(#c_case{arg=Arg}=Case0) ->
impossible ->
Case0
end
- end;
-opt_bool_case(Core) -> Core.
+ end.
opt_bool_clauses(#c_case{clauses=Cs}=Case) ->
Case#c_case{clauses=opt_bool_clauses(Cs, false, false)}.
@@ -1444,16 +1617,14 @@ opt_bool_clauses(Cs, true, true) ->
[]
end;
opt_bool_clauses([#c_clause{pats=[#c_literal{val=Lit}],
- guard=#c_literal{val=true},
- body=B}=C0|Cs], SeenT, SeenF) ->
+ guard=#c_literal{val=true}}=C|Cs], SeenT, SeenF) ->
case is_boolean(Lit) of
false ->
%% Not a boolean - this clause can't match.
- add_warning(C0, nomatch_clause_type),
+ add_warning(C, nomatch_clause_type),
opt_bool_clauses(Cs, SeenT, SeenF);
true ->
%% This clause will match.
- C = C0#c_clause{body=opt_bool_case(B)},
case {Lit,SeenT,SeenF} of
{false,_,false} ->
[C|opt_bool_clauses(Cs, SeenT, true)];
@@ -1729,10 +1900,10 @@ case_opt_arg_1(E0, Cs0, LitExpr) ->
true ->
E = case_opt_compiler_generated(E0),
Cs = case_opt_nomatch(E, Cs0, LitExpr),
- case cerl:data_type(E) of
- {atomic,_} ->
+ case cerl:is_literal(E) of
+ true ->
case_opt_lit(E, Cs);
- _ ->
+ false ->
case_opt_data(E, Cs)
end
end.
@@ -1880,10 +2051,10 @@ case_opt_lit_1(_, []) -> [].
%% the clauses where it is actually needed.
case_opt_data(E, Cs0) ->
- Es = cerl:data_es(E),
TypeSig = {cerl:data_type(E),cerl:data_arity(E)},
- try case_opt_data_1(Cs0, Es, TypeSig) of
+ try case_opt_data_1(Cs0, TypeSig) of
Cs ->
+ Es = cerl:data_es(E),
{ok,Es,Cs}
catch
throw:impossible ->
@@ -1891,44 +2062,47 @@ case_opt_data(E, Cs0) ->
{error,Cs0}
end.
-case_opt_data_1([{[P0|Ps0],C,PsAcc,Bs0}|Cs], Es, TypeSig) ->
+case_opt_data_1([{[P0|Ps0],C,PsAcc,Bs0}|Cs], TypeSig) ->
P = case_opt_compiler_generated(P0),
- BindTo = #c_var{name=dummy},
- {Ps1,[{BindTo,_}|Bs1]} = case_data_pat_alias(P, BindTo, TypeSig, []),
- [{Ps1++Ps0,C,PsAcc,Bs1++Bs0}|case_opt_data_1(Cs, Es, TypeSig)];
-case_opt_data_1([], _, _) -> [].
+ {Ps1,Bs} = case_opt_data_2(P, TypeSig, Bs0),
+ [{Ps1++Ps0,C,PsAcc,Bs}|case_opt_data_1(Cs, TypeSig)];
+case_opt_data_1([], _) -> [].
-case_data_pat_alias(P, BindTo0, TypeSig, Bs0) ->
- case cerl:type(P) of
- alias ->
- %% Recursively handle the pattern and bind to
- %% the alias variable.
- BindTo = cerl:alias_var(P),
- Apat0 = cerl:alias_pat(P),
- Ann = [compiler_generated],
- Apat = cerl:set_ann(Apat0, Ann),
- {Ps,Bs} = case_data_pat_alias(Apat, BindTo, TypeSig, Bs0),
- {Ps,[{BindTo0,BindTo}|Bs]};
- var ->
- %% Here we will need to actually build the data and bind
- %% it to the variable.
+case_opt_data_2(P, TypeSig, Bs0) ->
+ case case_analyze_pat(P) of
+ {[],Pat} when Pat =/= none ->
+ DataEs = cerl:data_es(P),
+ {DataEs,Bs0};
+ {[V|Vs],none} ->
{Type,Arity} = TypeSig,
Ann = [compiler_generated],
Vars = make_vars(Ann, Arity),
Data = cerl:ann_make_data(Ann, Type, Vars),
- Bs = [{BindTo0,P},{P,Data}|Bs0],
+ Bs = [{V,Data} | [{Var,V} || Var <- Vs] ++ Bs0],
{Vars,Bs};
- _ ->
- %% Since case_opt_nomatch/3 has removed all clauses that
- %% cannot match, we KNOW that this clause must match and
- %% that the pattern must be a data constructor.
- %% Here we must build the data and bind it to the variable.
+ {[V|Vs],Pat} when Pat =/= none ->
{Type,_} = TypeSig,
- DataEs = cerl:data_es(P),
+ DataEs = cerl:data_es(Pat),
Vars = pat_to_expr_list(DataEs),
Ann = [compiler_generated],
Data = cerl:ann_make_data(Ann, Type, Vars),
- {DataEs,[{BindTo0,Data}]}
+ Bs = [{V,Data} | [{Var,V} || Var <- Vs] ++ Bs0],
+ {DataEs,Bs}
+ end.
+
+case_analyze_pat(P) ->
+ case_analyze_pat_1(P, [], none).
+
+case_analyze_pat_1(P, Vs, Pat) ->
+ case cerl:type(P) of
+ alias ->
+ V = cerl:alias_var(P),
+ Apat = cerl:alias_pat(P),
+ case_analyze_pat_1(Apat, [V|Vs], Pat);
+ var ->
+ {[P|Vs],Pat};
+ _ ->
+ {Vs,P}
end.
%% pat_to_expr(Pattern) -> Expression.
@@ -1972,7 +2146,7 @@ make_var(A) ->
make_var_name() ->
N = get(new_var_num),
put(new_var_num, N+1),
- list_to_atom("fol"++integer_to_list(N)).
+ list_to_atom("@f"++integer_to_list(N)).
letify(Bs, Body) ->
Ann = cerl:get_ann(Body),
@@ -1986,7 +2160,7 @@ letify(Bs, Body) ->
-spec opt_not_in_let(cerl:c_let()) -> cerl:cerl().
opt_not_in_let(#c_let{vars=[_]=Vs0,arg=Arg0,body=Body0}=Let) ->
- case opt_not_in_let(Vs0, Arg0, Body0) of
+ case opt_not_in_let_0(Vs0, Arg0, Body0) of
{[],#c_values{es=[]},Body} ->
Body;
{Vs,Arg,Body} ->
@@ -1994,13 +2168,7 @@ opt_not_in_let(#c_let{vars=[_]=Vs0,arg=Arg0,body=Body0}=Let) ->
end;
opt_not_in_let(Let) -> Let.
-%% opt_not_in_let(Vs, Arg, Body) -> {Vs',Arg',Body'}
-%% Try to optimize away a 'not' operator in a 'let'.
-
--spec opt_not_in_let([cerl:c_var()], cerl:cerl(), cerl:cerl()) ->
- {[cerl:c_var()],cerl:cerl(),cerl:cerl()}.
-
-opt_not_in_let([#c_var{name=V}]=Vs0, Arg0, Body0) ->
+opt_not_in_let_0([#c_var{name=V}]=Vs0, Arg0, Body0) ->
case cerl:type(Body0) of
call ->
%% let <V> = Expr in not V ==>
@@ -2031,33 +2199,29 @@ opt_not_in_let([#c_var{name=V}]=Vs0, Arg0, Body0) ->
end;
_ ->
{Vs0,Arg0,Body0}
- end;
-opt_not_in_let(Vs, Arg, Body) ->
- {Vs,Arg,Body}.
+ end.
opt_not_in_let_1(V, Call, Body) ->
case Call of
#c_call{module=#c_literal{val=erlang},
name=#c_literal{val='not'},
args=[#c_var{name=V}]} ->
- opt_not_in_let_2(Body);
+ opt_not_in_let_2(Body, Call);
_ ->
no
end.
-opt_not_in_let_2(#c_case{clauses=Cs0}=Case) ->
+opt_not_in_let_2(#c_case{clauses=Cs0}=Case, NotCall) ->
Vars = make_vars([], 1),
- Body = #c_call{module=#c_literal{val=erlang},
- name=#c_literal{val='not'},
- args=Vars},
+ Body = NotCall#c_call{args=Vars},
Cs = [begin
Let = #c_let{vars=Vars,arg=B,body=Body},
C#c_clause{body=opt_not_in_let(Let)}
end || #c_clause{body=B}=C <- Cs0],
{yes,Case#c_case{clauses=Cs}};
-opt_not_in_let_2(#c_call{}=Call0) ->
+opt_not_in_let_2(#c_call{}=Call0, _NotCall) ->
invert_call(Call0);
-opt_not_in_let_2(_) -> no.
+opt_not_in_let_2(_, _) -> no.
invert_call(#c_call{module=#c_literal{val=erlang},
name=#c_literal{val=Name0},
@@ -2081,24 +2245,24 @@ inverse_rel_op('=<') -> '>';
inverse_rel_op(_) -> no.
-%% opt_bool_case_in_let(LetExpr, Sub) -> Core
+%% opt_bool_case_in_let(LetExpr) -> Core
opt_bool_case_in_let(#c_let{vars=Vs,arg=Arg,body=B}=Let, Sub) ->
- opt_case_in_let_1(Vs, Arg, B, Let, Sub).
+ opt_bool_case_in_let_1(Vs, Arg, B, Let, Sub).
-opt_case_in_let_1([#c_var{name=V}], Arg,
+opt_bool_case_in_let_1([#c_var{name=V}], Arg,
#c_case{arg=#c_var{name=V}}=Case0, Let, Sub) ->
case is_simple_case_arg(Arg) of
true ->
- Case = opt_bool_case(Case0#c_case{arg=Arg}),
+ Case = opt_bool_case(Case0#c_case{arg=Arg}, Sub),
case core_lib:is_var_used(V, Case) of
- false -> expr(Case, sub_new(Sub));
+ false -> Case;
true -> Let
end;
false ->
Let
end;
-opt_case_in_let_1(_, _, _, Let, _) -> Let.
+opt_bool_case_in_let_1(_, _, _, Let, _) -> Let.
%% is_simple_case_arg(Expr) -> true|false
%% Determine whether the Expr is simple enough to be worth
@@ -2231,9 +2395,7 @@ is_safe_bool_expr_list([], _, _) -> true.
%% as a let or a sequence, move the original let body into the complex
%% expression.
-simplify_let(#c_let{arg=Arg0}=Let0, Sub) ->
- Arg = opt_bool_case(Arg0),
- Let = Let0#c_let{arg=Arg},
+simplify_let(#c_let{arg=Arg}=Let, Sub) ->
move_let_into_expr(Let, Arg, Sub).
move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner,
@@ -2251,11 +2413,11 @@ move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner,
%%
Arg = body(Arg0, Sub0),
ScopeSub0 = sub_subst_scope(Sub0#sub{t=#{}}),
- {OuterVs,ScopeSub} = pattern_list(OuterVs0, ScopeSub0),
+ {OuterVs,ScopeSub} = var_list(OuterVs0, ScopeSub0),
OuterBody = body(OuterBody0, ScopeSub),
- {InnerVs,Sub} = pattern_list(InnerVs0, Sub0),
+ {InnerVs,Sub} = var_list(InnerVs0, Sub0),
InnerBody = body(InnerBody0, Sub),
Outer#c_let{vars=OuterVs,arg=Arg,
body=Inner#c_let{vars=InnerVs,arg=OuterBody,body=InnerBody}};
@@ -2271,39 +2433,49 @@ move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
case {TwoClauses,is_failing_clause(Ca0),is_failing_clause(Cb0)} of
{true,false,true} ->
%% let <Lvars> = case <Case-expr> of
- %% <Cvars> -> <Clause-body>;
- %% <OtherCvars> -> erlang:error(...)
+ %% <Cpats> -> <Clause-body>;
+ %% <OtherCpats> -> erlang:error(...)
%% end
%% in <Let-body>
%%
%% ==>
%%
%% case <Case-expr> of
- %% <Cvars> ->
+ %% <Cpats> ->
%% let <Lvars> = <Clause-body>
%% in <Let-body>;
- %% <OtherCvars> -> erlang:error(...)
+ %% <OtherCpats> -> erlang:error(...)
%% end
Cexpr = body(Cexpr0, Sub0),
- CaVars0 = Ca0#c_clause.pats,
+ CaPats0 = Ca0#c_clause.pats,
G0 = Ca0#c_clause.guard,
B0 = Ca0#c_clause.body,
ScopeSub0 = sub_subst_scope(Sub0#sub{t=#{}}),
- {CaVars,ScopeSub} = pattern_list(CaVars0, ScopeSub0),
- G = guard(G0, ScopeSub),
-
- B1 = body(B0, ScopeSub),
-
- {Lvs,B2,Sub1} = let_substs(Lvs0, B1, Sub0),
- Sub2 = Sub1#sub{s=cerl_sets:union(ScopeSub#sub.s,
- Sub1#sub.s)},
- Lbody = body(Lbody0, Sub2),
- B = Let#c_let{vars=Lvs,arg=core_lib:make_values(B2),body=Lbody},
-
- Ca = Ca0#c_clause{pats=CaVars,guard=G,body=B},
- Cb = clause(Cb0, Cexpr, value, Sub0),
- Case#c_case{arg=Cexpr,clauses=[Ca,Cb]};
+ try pattern_list(CaPats0, ScopeSub0) of
+ {CaPats,ScopeSub} ->
+ G = guard(G0, ScopeSub),
+
+ B1 = body(B0, ScopeSub),
+
+ {Lvs,B2,Sub1} = let_substs(Lvs0, B1, Sub0),
+ Sub2 = Sub1#sub{s=cerl_sets:union(ScopeSub#sub.s,
+ Sub1#sub.s)},
+ Lbody = body(Lbody0, Sub2),
+ B = Let#c_let{vars=Lvs,
+ arg=core_lib:make_values(B2),
+ body=Lbody},
+
+ Ca = Ca0#c_clause{pats=CaPats,guard=G,body=B},
+ Cb = clause(Cb0, Cexpr, value, Sub0),
+ Case#c_case{arg=Cexpr,clauses=[Ca,Cb]}
+ catch
+ nomatch ->
+ %% This is not a defeat. The code will eventually
+ %% be optimized to erlang:error(...) by the other
+ %% optimizations done in this module.
+ impossible
+ end;
{_,_,_} -> impossible
end;
move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
@@ -2479,11 +2651,10 @@ opt_simple_let_0(#c_let{arg=Arg0}=Let, Ctxt, Sub) ->
opt_simple_let_1(#c_let{vars=Vs0,body=B0}=Let, Arg0, Ctxt, Sub0) ->
%% Optimise let and add new substitutions.
- {Vs1,Args,Sub1} = let_substs(Vs0, Arg0, Sub0),
- BodySub = update_let_types(Vs1, Args, Sub1),
- B1 = body(B0, Ctxt, BodySub),
- Arg1 = core_lib:make_values(Args),
- {Vs,Arg,B} = opt_not_in_let(Vs1, Arg1, B1),
+ {Vs,Args,Sub1} = let_substs(Vs0, Arg0, Sub0),
+ BodySub = update_let_types(Vs, Args, Sub1),
+ B = body(B0, Ctxt, BodySub),
+ Arg = core_lib:make_values(Args),
opt_simple_let_2(Let, Vs, Arg, B, B0, Ctxt, Sub1).
opt_simple_let_2(Let0, Vs0, Arg0, Body, PrevBody, Ctxt, Sub) ->
@@ -2496,25 +2667,23 @@ opt_simple_let_2(Let0, Vs0, Arg0, Body, PrevBody, Ctxt, Sub) ->
false ->
%% let <Var> = Arg in <OtherVar> ==> seq Arg OtherVar
Arg = maybe_suppress_warnings(Arg1, Vs0, PrevBody),
- expr(#c_seq{arg=Arg,body=Body}, Ctxt,
- sub_new_preserve_types(Sub))
+ #c_seq{arg=Arg,body=Body}
end;
{[],#c_values{es=[]},_} ->
%% No variables left.
Body;
{Vs,Arg1,#c_literal{}} ->
Arg = maybe_suppress_warnings(Arg1, Vs, PrevBody),
- E = case Ctxt of
- effect ->
- %% Throw away the literal body.
- Arg;
- value ->
- %% Since the variable is not used in the body, we
- %% can rewrite the let to a sequence.
- %% let <Var> = Arg in Literal ==> seq Arg Literal
- #c_seq{arg=Arg,body=Body}
- end,
- expr(E, Ctxt, sub_new_preserve_types(Sub));
+ case Ctxt of
+ effect ->
+ %% Throw away the literal body.
+ Arg;
+ value ->
+ %% Since the variable is not used in the body, we
+ %% can rewrite the let to a sequence.
+ %% let <Var> = Arg in Literal ==> seq Arg Literal
+ #c_seq{arg=Arg,body=Body}
+ end;
{Vs,Arg1,Body} ->
%% If none of the variables are used in the body, we can
%% rewrite the let to a sequence:
@@ -2523,12 +2692,10 @@ opt_simple_let_2(Let0, Vs0, Arg0, Body, PrevBody, Ctxt, Sub) ->
case is_any_var_used(Vs, Body) of
false ->
Arg = maybe_suppress_warnings(Arg1, Vs, PrevBody),
- expr(#c_seq{arg=Arg,body=Body}, Ctxt,
- sub_new_preserve_types(Sub));
+ #c_seq{arg=Arg,body=Body};
true ->
Let1 = Let0#c_let{vars=Vs,arg=Arg1,body=Body},
- Let2 = opt_bool_case_in_let(Let1, Sub),
- opt_case_in_let_arg(Let2, Ctxt, Sub)
+ opt_bool_case_in_let(Let1, Sub)
end
end.
@@ -2595,7 +2762,7 @@ move_case_into_arg(#c_case{arg=#c_let{vars=OuterVars0,arg=OuterArg,
%% in case <InnerArg> of <InnerClauses> end
%%
ScopeSub0 = sub_subst_scope(Sub#sub{t=#{}}),
- {OuterVars,ScopeSub} = pattern_list(OuterVars0, ScopeSub0),
+ {OuterVars,ScopeSub} = var_list(OuterVars0, ScopeSub0),
InnerArg = body(InnerArg0, ScopeSub),
Outer#c_let{vars=OuterVars,arg=OuterArg,
body=Inner#c_case{arg=InnerArg,clauses=InnerClauses}};
@@ -2624,14 +2791,18 @@ move_case_into_arg(#c_case{arg=#c_case{arg=OuterArg,
%% end
%%
ScopeSub0 = sub_subst_scope(Sub#sub{t=#{}}),
- {OuterPats,ScopeSub} = pattern_list(OuterPats0, ScopeSub0),
- OuterGuard = guard(OuterGuard0, ScopeSub),
- InnerArg = body(InnerArg0, ScopeSub),
- Inner = Inner0#c_case{arg=InnerArg,clauses=InnerClauses},
- OuterCa = OuterCa0#c_clause{pats=OuterPats,guard=OuterGuard,
- body=Inner},
- Outer#c_case{arg=OuterArg,
- clauses=[OuterCa,OuterCb]};
+
+ %% We KNOW that pattern_list/2 has already been called for OuterPats0;
+ %% therefore, it cannot throw an exception.
+ {OuterPats,ScopeSub} = pattern_list(OuterPats0, ScopeSub0),
+ OuterGuard = guard(OuterGuard0, ScopeSub),
+ InnerArg = body(InnerArg0, ScopeSub),
+ Inner = Inner0#c_case{arg=InnerArg,clauses=InnerClauses},
+ OuterCa = OuterCa0#c_clause{pats=OuterPats,
+ guard=OuterGuard,
+ body=Inner},
+ Outer#c_case{arg=OuterArg,
+ clauses=[OuterCa,OuterCb]};
false ->
impossible
end;
@@ -2652,48 +2823,6 @@ move_case_into_arg(#c_case{arg=#c_seq{arg=OuterArg,body=InnerArg}=Outer,
move_case_into_arg(_, _) ->
impossible.
-%% In guards only, rewrite a case in a let argument like
-%%
-%% let <Var> = case <> of
-%% <> when AnyGuard -> Literal1;
-%% <> when AnyGuard -> Literal2
-%% end
-%% in LetBody
-%%
-%% to
-%%
-%% case <> of
-%% <> when AnyGuard ->
-%% let <Var> = Literal1 in LetBody
-%% <> when 'true' ->
-%% let <Var> = Literal2 in LetBody
-%% end
-%%
-%% In the worst case, the size of the code could increase.
-%% In practice, though, substituting the literals into
-%% LetBody and doing constant folding will decrease the code
-%% size. (Doing this transformation outside of guards could
-%% lead to a substantational increase in code size.)
-%%
-opt_case_in_let_arg(#c_let{arg=#c_case{}=Case}=Let, Ctxt,
- #sub{in_guard=true}=Sub) ->
- opt_case_in_let_arg_1(Let, Case, Ctxt, Sub);
-opt_case_in_let_arg(Let, _, _) -> Let.
-
-opt_case_in_let_arg_1(Let0, #c_case{arg=#c_values{es=[]},
- clauses=Cs}=Case0, Ctxt, Sub) ->
- Let = mark_compiler_generated(Let0),
- case Cs of
- [#c_clause{body=#c_literal{}=BodyA}=Ca0,
- #c_clause{body=#c_literal{}=BodyB}=Cb0] ->
- Ca = Ca0#c_clause{body=Let#c_let{arg=BodyA}},
- Cb = Cb0#c_clause{body=Let#c_let{arg=BodyB}},
- Case = Case0#c_case{clauses=[Ca,Cb]},
- expr(Case, Ctxt, sub_new_preserve_types(Sub));
- _ -> Let
- end;
-opt_case_in_let_arg_1(Let, _, _, _) -> Let.
-
is_any_var_used([#c_var{name=V}|Vs], Expr) ->
case core_lib:is_var_used(V, Expr) of
false -> is_any_var_used(Vs, Expr);
@@ -2793,12 +2922,20 @@ extract_type_1(Expr, Sub) ->
true -> bool
end.
+returns_integer('band', [_,_]) -> true;
+returns_integer('bnot', [_]) -> true;
+returns_integer('bor', [_,_]) -> true;
+returns_integer('bxor', [_,_]) -> true;
returns_integer(bit_size, [_]) -> true;
returns_integer('bsl', [_,_]) -> true;
returns_integer('bsr', [_,_]) -> true;
returns_integer(byte_size, [_]) -> true;
+returns_integer(ceil, [_]) -> true;
+returns_integer('div', [_,_]) -> true;
+returns_integer(floor, [_]) -> true;
returns_integer(length, [_]) -> true;
returns_integer('rem', [_,_]) -> true;
+returns_integer('round', [_]) -> true;
returns_integer(size, [_]) -> true;
returns_integer(tuple_size, [_]) -> true;
returns_integer(trunc, [_]) -> true;
@@ -2813,15 +2950,8 @@ update_types(Expr, Pat, #sub{t=Tdb0}=Sub) ->
Tdb = update_types_1(Expr, Pat, Tdb0),
Sub#sub{t=Tdb}.
-update_types_1(#c_var{name=V,anno=Anno}, Pat, Types) ->
- case member(reuse_for_context, Anno) of
- true ->
- %% If a variable has been marked for reuse of binary context,
- %% optimizations based on type information are unsafe.
- kill_types(V, Types);
- false ->
- update_types_2(V, Pat, Types)
- end;
+update_types_1(#c_var{name=V}, Pat, Types) ->
+ update_types_2(V, Pat, Types);
update_types_1(_, _, Types) -> Types.
update_types_2(V, [#c_tuple{}=P], Types) ->
@@ -2864,274 +2994,14 @@ copy_type(_, _, Tdb) -> Tdb.
void() -> #c_literal{val=ok}.
-%%%
-%%% Annotate bit syntax matching to faciliate optimization in further passes.
-%%%
-
-bsm_an(#c_case{arg=#c_var{}=V}=Case) ->
- bsm_an_1([V], Case);
-bsm_an(#c_case{arg=#c_values{es=Es}}=Case) ->
- bsm_an_1(Es, Case);
-bsm_an(Other) -> Other.
-
-bsm_an_1(Vs, #c_case{clauses=Cs}=Case) ->
- case bsm_leftmost(Cs) of
- none -> Case;
- Pos -> bsm_an_2(Vs, Cs, Case, Pos)
- end.
-
-bsm_an_2(Vs, Cs, Case, Pos) ->
- case bsm_nonempty(Cs, Pos) of
- true -> bsm_an_3(Vs, Cs, Case, Pos);
- false -> Case
- end.
-
-bsm_an_3(Vs, Cs, Case, Pos) ->
- try
- bsm_ensure_no_partition(Cs, Pos),
- bsm_do_an(Vs, Pos, Cs, Case)
- catch
- throw:{problem,Where,What} ->
- add_bin_opt_info(Where, What),
- Case
- end.
-
-bsm_do_an(Vs0, Pos, Cs0, Case) ->
- case nth(Pos, Vs0) of
- #c_var{name=Vname}=V0 ->
- Cs = bsm_do_an_var(Vname, Pos, Cs0, []),
- V = bsm_annotate_for_reuse(V0),
- Bef = lists:sublist(Vs0, Pos-1),
- Aft = lists:nthtail(Pos, Vs0),
- case Bef ++ [V|Aft] of
- [_] ->
- Case#c_case{arg=V,clauses=Cs};
- Vs ->
- Case#c_case{arg=#c_values{es=Vs},clauses=Cs}
- end;
- _ ->
- Case
- end.
-
-bsm_do_an_var(V, S, [#c_clause{pats=Ps,guard=G,body=B0}=C0|Cs], Acc) ->
- case nth(S, Ps) of
- #c_var{name=VarName} ->
- case core_lib:is_var_used(V, G) of
- true -> bsm_problem(C0, orig_bin_var_used_in_guard);
- false -> ok
- end,
- case core_lib:is_var_used(VarName, G) of
- true -> bsm_problem(C0, bin_var_used_in_guard);
- false -> ok
- end,
- B1 = bsm_maybe_ctx_to_binary(VarName, B0),
- B = bsm_maybe_ctx_to_binary(V, B1),
- C = C0#c_clause{body=B},
- bsm_do_an_var(V, S, Cs, [C|Acc]);
- #c_alias{}=P ->
- case bsm_could_match_binary(P) of
- false ->
- bsm_do_an_var(V, S, Cs, [C0|Acc]);
- true ->
- bsm_problem(C0, bin_opt_alias)
- end;
- P ->
- case bsm_could_match_binary(P) andalso bsm_is_var_used(V, G, B0) of
- false ->
- bsm_do_an_var(V, S, Cs, [C0|Acc]);
- true ->
- bsm_problem(C0, bin_var_used)
- end
- end;
-bsm_do_an_var(_, _, [], Acc) -> reverse(Acc).
-
-bsm_annotate_for_reuse(#c_var{anno=Anno}=Var) ->
- case member(reuse_for_context, Anno) of
- false -> Var#c_var{anno=[reuse_for_context|Anno]};
- true -> Var
- end.
-
-bsm_is_var_used(V, G, B) ->
- core_lib:is_var_used(V, G) orelse core_lib:is_var_used(V, B).
-
-bsm_maybe_ctx_to_binary(V, B) ->
- case core_lib:is_var_used(V, B) andalso not previous_ctx_to_binary(V, B) of
- false ->
- B;
- true ->
- #c_seq{arg=#c_primop{name=#c_literal{val=bs_context_to_binary},
- args=[#c_var{name=V}]},
- body=B}
- end.
-
-previous_ctx_to_binary(V, Core) ->
- case Core of
- #c_seq{arg=#c_primop{name=#c_literal{val=bs_context_to_binary},
- args=[#c_var{name=V}]}} ->
- true;
- _ ->
- false
- end.
-
-%% bsm_leftmost(Cs) -> none | ArgumentNumber
-%% Find the leftmost argument that does binary matching. Return
-%% the number of the argument (1-N).
-
-bsm_leftmost(Cs) ->
- bsm_leftmost_1(Cs, none).
-
-bsm_leftmost_1([#c_clause{pats=Ps}|Cs], Pos) ->
- bsm_leftmost_2(Ps, Cs, 1, Pos);
-bsm_leftmost_1([], Pos) -> Pos.
-
-bsm_leftmost_2(_, Cs, Pos, Pos) ->
- bsm_leftmost_1(Cs, Pos);
-bsm_leftmost_2([#c_binary{}|_], Cs, N, _) ->
- bsm_leftmost_1(Cs, N);
-bsm_leftmost_2([_|Ps], Cs, N, Pos) ->
- bsm_leftmost_2(Ps, Cs, N+1, Pos);
-bsm_leftmost_2([], Cs, _, Pos) ->
- bsm_leftmost_1(Cs, Pos).
-
-%% bsm_nonempty(Cs, Pos) -> true|false
-%% Check if at least one of the clauses matches a non-empty
-%% binary in the given argument position.
-%%
-bsm_nonempty([#c_clause{pats=Ps}|Cs], Pos) ->
- case nth(Pos, Ps) of
- #c_binary{segments=[_|_]} ->
- true;
- _ ->
- bsm_nonempty(Cs, Pos)
- end;
-bsm_nonempty([], _ ) -> false.
-
-%% bsm_ensure_no_partition(Cs, Pos) -> ok (exception if problem)
-%% We must make sure that matching is not partitioned between
-%% variables like this:
-%% foo(<<...>>) -> ...
-%% foo(<Variable>) when ... -> ...
-%% foo(<Any non-variable pattern>) ->
-%% If there is such partition, we are not allowed to reuse the binary variable
-%% for the match context.
-%%
-%% Also, arguments to the left of the argument that is matched
-%% against a binary, are only allowed to be simple variables, not
-%% used in guards. The reason is that we must know that the binary is
-%% only matched in one place (i.e. there must be only one bs_start_match2
-%% instruction emitted).
-
-bsm_ensure_no_partition(Cs, Pos) ->
- bsm_ensure_no_partition_1(Cs, Pos, before).
-
-%% Loop through each clause.
-bsm_ensure_no_partition_1([#c_clause{pats=Ps,guard=G}|Cs], Pos, State0) ->
- State = bsm_ensure_no_partition_2(Ps, Pos, G, simple_vars, State0),
- case State of
- 'after' ->
- bsm_ensure_no_partition_after(Cs, Pos);
- _ ->
- ok
- end,
- bsm_ensure_no_partition_1(Cs, Pos, State);
-bsm_ensure_no_partition_1([], _, _) -> ok.
-
-%% Loop through each pattern for this clause.
-bsm_ensure_no_partition_2([#c_binary{}=Where|_], 1, _, Vstate, State) ->
- case State of
- before when Vstate =:= simple_vars -> within;
- before -> bsm_problem(Where, Vstate);
- within when Vstate =:= simple_vars -> within;
- within -> bsm_problem(Where, Vstate)
- end;
-bsm_ensure_no_partition_2([#c_alias{}=Alias|_], 1, N, Vstate, State) ->
- %% Retrieve the real pattern that the alias refers to and check that.
- P = bsm_real_pattern(Alias),
- bsm_ensure_no_partition_2([P], 1, N, Vstate, State);
-bsm_ensure_no_partition_2([_|_], 1, _, _Vstate, before=State) ->
- %% No binary matching yet - therefore no partition.
- State;
-bsm_ensure_no_partition_2([P|_], 1, _, Vstate, State) ->
- case bsm_could_match_binary(P) of
- false ->
- %% If clauses can be freely arranged (Vstate =:= simple_vars),
- %% a clause that cannot match a binary will not partition the clause.
- %% Example:
- %%
- %% a(Var, <<>>) -> ...
- %% a(Var, []) -> ...
- %% a(Var, <<B>>) -> ...
- %%
- %% But if the clauses can't be freely rearranged, as in
- %%
- %% b(Var, <<X>>) -> ...
- %% b(1, 2) -> ...
- %%
- %% we do have a problem.
- %%
- case Vstate of
- simple_vars -> State;
- _ -> bsm_problem(P, Vstate)
- end;
- true ->
- %% The pattern P *may* match a binary, so we must update the state.
- %% (P must be a variable.)
- case State of
- within -> 'after';
- 'after' -> 'after'
- end
- end;
-bsm_ensure_no_partition_2([#c_var{name=V}|Ps], N, G, Vstate, S) ->
- case core_lib:is_var_used(V, G) of
- false ->
- bsm_ensure_no_partition_2(Ps, N-1, G, Vstate, S);
- true ->
- bsm_ensure_no_partition_2(Ps, N-1, G, bin_left_var_used_in_guard, S)
- end;
-bsm_ensure_no_partition_2([_|Ps], N, G, _, S) ->
- bsm_ensure_no_partition_2(Ps, N-1, G, bin_argument_order, S).
-
-bsm_ensure_no_partition_after([#c_clause{pats=Ps}=C|Cs], Pos) ->
- case nth(Pos, Ps) of
- #c_var{} ->
- bsm_ensure_no_partition_after(Cs, Pos);
- _ ->
- bsm_problem(C, bin_partition)
- end;
-bsm_ensure_no_partition_after([], _) -> ok.
-
-bsm_could_match_binary(#c_alias{pat=P}) -> bsm_could_match_binary(P);
-bsm_could_match_binary(#c_cons{}) -> false;
-bsm_could_match_binary(#c_tuple{}) -> false;
-bsm_could_match_binary(#c_literal{val=Lit}) -> is_bitstring(Lit);
-bsm_could_match_binary(_) -> true.
-
-bsm_real_pattern(#c_alias{pat=P}) -> bsm_real_pattern(P);
-bsm_real_pattern(P) -> P.
-
-bsm_problem(Where, What) ->
- throw({problem,Where,What}).
%%%
%%% Handling of warnings.
%%%
-mark_compiler_generated(Term) ->
- cerl_trees:map(fun mark_compiler_generated_1/1, Term).
-
-mark_compiler_generated_1(#c_call{anno=Anno}=Term) ->
- Term#c_call{anno=[compiler_generated|Anno--[compiler_generated]]};
-mark_compiler_generated_1(Term) -> Term.
-
init_warnings() ->
put({?MODULE,warnings}, []).
-add_bin_opt_info(Core, Term) ->
- case get(bin_opt_info) of
- true -> add_warning(Core, Term);
- false -> ok
- end.
-
add_warning(Core, Term) ->
case should_suppress_warning(Core) of
true ->
@@ -3207,6 +3077,29 @@ format_error(nomatch_shadow) ->
"this clause cannot match because a previous clause always matches";
format_error(nomatch_guard) ->
"the guard for this clause evaluates to 'false'";
+format_error({nomatch_bit_syntax_truncated,Signess,Val,Sz}) ->
+ S = case Signess of
+ signed -> "a 'signed'";
+ unsigned -> "an 'unsigned'"
+ end,
+ F = "this clause cannot match because the value ~P"
+ " will not fit in ~s binary segment of size ~p",
+ flatten(io_lib:format(F, [Val,10,S,Sz]));
+format_error({nomatch_bit_syntax_unsigned,Val}) ->
+ F = "this clause cannot match because the negative value ~P"
+ " will never match the value of an 'unsigned' binary segment",
+ flatten(io_lib:format(F, [Val,10]));
+format_error({nomatch_bit_syntax_size,Sz}) ->
+ F = "this clause cannot match because '~P' is not a valid size for a binary segment",
+ flatten(io_lib:format(F, [Sz,10]));
+format_error({nomatch_bit_syntax_type,Val,Type}) ->
+ F = "this clause cannot match because '~P' is not of the"
+ " expected type '~p'",
+ flatten(io_lib:format(F, [Val,10,Type]));
+format_error({nomatch_bit_syntax_unicode,Val}) ->
+ F = "this clause cannot match because the value ~p"
+ " is not a valid Unicode code point",
+ flatten(io_lib:format(F, [Val]));
format_error(no_clause_match) ->
"no clause will ever match";
format_error(nomatch_clause_type) ->
@@ -3227,29 +3120,10 @@ format_error({no_effect,{erlang,F,A}}) ->
format_error(result_ignored) ->
"the result of the expression is ignored "
"(suppress the warning by assigning the expression to the _ variable)";
+format_error(invalid_call) ->
+ "invalid function call";
format_error(useless_building) ->
- "a term is constructed, but never used";
-format_error(bin_opt_alias) ->
- "INFO: the '=' operator will prevent delayed sub binary optimization";
-format_error(bin_partition) ->
- "INFO: matching non-variables after a previous clause matching a variable "
- "will prevent delayed sub binary optimization";
-format_error(bin_left_var_used_in_guard) ->
- "INFO: a variable to the left of the binary pattern is used in a guard; "
- "will prevent delayed sub binary optimization";
-format_error(bin_argument_order) ->
- "INFO: matching anything else but a plain variable to the left of "
- "binary pattern will prevent delayed sub binary optimization; "
- "SUGGEST changing argument order";
-format_error(bin_var_used) ->
- "INFO: using a matched out sub binary will prevent "
- "delayed sub binary optimization";
-format_error(orig_bin_var_used_in_guard) ->
- "INFO: using the original binary variable in a guard will prevent "
- "delayed sub binary optimization";
-format_error(bin_var_used_in_guard) ->
- "INFO: using a matched out sub binary in a guard will prevent "
- "delayed sub binary optimization".
+ "a term is constructed, but never used".
-ifdef(DEBUG).
%% In order for simplify_let/2 to work correctly, the list of
@@ -3260,12 +3134,18 @@ format_error(bin_var_used_in_guard) ->
verify_scope(E, #sub{s=Scope}) ->
Free0 = cerl_trees:free_variables(E),
Free = [V || V <- Free0, not is_tuple(V)], %Ignore function names.
- case ordsets:is_subset(Free, cerl_sets:to_list(Scope)) of
- true -> true;
+ case is_subset_of_scope(Free, Scope) of
+ true ->
+ true;
false ->
io:format("~p\n", [E]),
io:format("~p\n", [Free]),
- io:format("~p\n", [cerl_sets:to_list(Scope)]),
+ io:format("~p\n", [ordsets:from_list(cerl_sets:to_list(Scope))]),
false
end.
+
+is_subset_of_scope([V|Vs], Scope) ->
+ cerl_sets:is_element(V, Scope) andalso is_subset_of_scope(Vs, Scope);
+is_subset_of_scope([], _) -> true.
+
-endif.
diff --git a/lib/compiler/src/sys_core_inline.erl b/lib/compiler/src/sys_core_inline.erl
index 838dda68c6..8c1f69d5de 100644
--- a/lib/compiler/src/sys_core_inline.erl
+++ b/lib/compiler/src/sys_core_inline.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/sys_pre_attributes.erl b/lib/compiler/src/sys_pre_attributes.erl
index f0cb630205..67adae5acf 100644
--- a/lib/compiler/src/sys_pre_attributes.erl
+++ b/lib/compiler/src/sys_pre_attributes.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
@@ -25,10 +25,10 @@
-define(OPTION_TAG, attributes).
--record(state, {forms,
- pre_ops = [],
- post_ops = [],
- options}).
+-record(state, {forms :: [form()],
+ pre_ops = [] :: [op()],
+ post_ops = [] :: [op()],
+ options :: [option()]}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Inserts, deletes and replaces Erlang compiler attributes.
@@ -59,9 +59,23 @@
%% due to that the pre_transform pass did not find the attribute plus
%% all insert operations.
+-type attribute() :: atom().
+-type value() :: term().
+-type form() :: {function, integer(), atom(), arity(), _}
+ | {attribute, integer(), attribute(), _}.
+-type option() :: compile:option()
+ | {'attribute', 'insert', attribute(), value()}
+ | {'attribute', 'replace', attribute(), value()}
+ | {'attribute', 'delete', attribute()}.
+-type op() :: {'insert', attribute(), value()}
+ | {'replace', attribute(), value()}
+ | {'delete', attribute()}.
+
+-spec parse_transform([form()], [option()]) -> [form()].
+
parse_transform(Forms, Options) ->
S = #state{forms = Forms, options = Options},
- S2 = init_transform(S),
+ S2 = init_transform(Options, S),
report_verbose("Pre options: ~p~n", [S2#state.pre_ops], S2),
report_verbose("Post options: ~p~n", [S2#state.post_ops], S2),
S3 = pre_transform(S2),
@@ -71,13 +85,6 @@ parse_transform(Forms, Options) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Computes the lists of pre_ops and post_ops that are
%% used in the real transformation.
-init_transform(S) ->
- case S#state.options of
- Options when is_list(Options) ->
- init_transform(Options, S);
- Option ->
- init_transform([Option], S)
- end.
init_transform([{attribute, insert, Name, Val} | Tail], S) ->
Op = {insert, Name, Val},
@@ -92,12 +99,9 @@ init_transform([{attribute, delete, Name} | Tail], S) ->
Op = {delete, Name},
PreOps = [Op | S#state.pre_ops],
init_transform(Tail, S#state{pre_ops = PreOps});
-init_transform([], S) ->
- S;
init_transform([_ | T], S) ->
init_transform(T, S);
-init_transform(BadOpt, S) ->
- report_error("Illegal option (ignored): ~p~n", [BadOpt], S),
+init_transform([], S) ->
S.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -176,18 +180,9 @@ attrs([], _, _) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Report functions.
%%
-%% Errors messages are controlled with the 'report_errors' compiler option
%% Warning messages are controlled with the 'report_warnings' compiler option
%% Verbose messages are controlled with the 'verbose' compiler option
-report_error(Format, Args, S) ->
- case is_error(S) of
- true ->
- io:format("~p: * ERROR * " ++ Format, [?MODULE | Args]);
- false ->
- ok
- end.
-
report_warning(Format, Args, S) ->
case is_warning(S) of
true ->
@@ -204,9 +199,6 @@ report_verbose(Format, Args, S) ->
ok
end.
-is_error(S) ->
- lists:member(report_errors, S#state.options) or is_verbose(S).
-
is_warning(S) ->
lists:member(report_warnings, S#state.options) or is_verbose(S).
diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl
deleted file mode 100644
index d9cc4b530c..0000000000
--- a/lib/compiler/src/sys_pre_expand.erl
+++ /dev/null
@@ -1,671 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2015. 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%
-%%
-%% Purpose : Expand some source Erlang constructions. This is part of the
-%% pre-processing phase.
-
-%% N.B. Although structs (tagged tuples) are not yet allowed in the
-%% language there is code included in pattern/2 and expr/3 (commented out)
-%% that handles them by transforming them to tuples.
-
--module(sys_pre_expand).
-
-%% Main entry point.
--export([module/2]).
-
--import(ordsets, [from_list/1,union/2]).
--import(lists, [member/2,foldl/3,foldr/3]).
-
--include("../include/erl_bits.hrl").
-
--type fa() :: {atom(), arity()}.
-
--record(expand, {module=[], %Module name
- exports=[], %Exports
- imports=[], %Imports
- attributes=[], %Attributes
- callbacks=[], %Callbacks
- optional_callbacks=[] :: [fa()], %Optional callbacks
- defined, %Defined functions (gb_set)
- vcount=0, %Variable counter
- func=[], %Current function
- arity=[], %Arity for current function
- fcount=0 %Local fun count
- }).
-
-%% module(Forms, CompileOptions)
-%% {ModuleName,Exports,TransformedForms,CompileOptions'}
-%% Expand the forms in one module. N.B.: the lists of predefined
-%% exports and imports are really ordsets!
-%% CompileOptions is augmented with options from -compile attributes.
-
-module(Fs0, Opts0) ->
-
- %% Expand records. Normalise guard tests.
- Fs = erl_expand_records:module(Fs0, Opts0),
-
- Opts = compiler_options(Fs) ++ Opts0,
-
- %% Set pre-defined exported functions.
- PreExp = [{module_info,0},{module_info,1}],
-
- %% Build initial expand record.
- St0 = #expand{exports=PreExp,
- defined=PreExp
- },
- %% Expand the functions.
- {Tfs,St1} = forms(Fs, define_functions(Fs, St0)),
- %% Get the correct list of exported functions.
- Exports = case member(export_all, Opts) of
- true -> gb_sets:to_list(St1#expand.defined);
- false -> St1#expand.exports
- end,
- %% Generate all functions from stored info.
- {Ats,St3} = module_attrs(St1#expand{exports = Exports}),
- {Mfs,St4} = module_predef_funcs(St3),
- {St4#expand.module, St4#expand.exports, Ats ++ Tfs ++ Mfs,
- Opts}.
-
-compiler_options(Forms) ->
- lists:flatten([C || {attribute,_,compile,C} <- Forms]).
-
-%% define_function(Form, State) -> State.
-%% Add function to defined if form is a function.
-
-define_functions(Forms, #expand{defined=Predef}=St) ->
- Fs = foldl(fun({function,_,N,A,_Cs}, Acc) -> [{N,A}|Acc];
- (_, Acc) -> Acc
- end, Predef, Forms),
- St#expand{defined=gb_sets:from_list(Fs)}.
-
-module_attrs(#expand{attributes=Attributes}=St) ->
- Attrs = [{attribute,Line,Name,Val} || {Name,Line,Val} <- Attributes],
- Callbacks = [Callback || {_,_,callback,_}=Callback <- Attrs],
- OptionalCallbacks = get_optional_callbacks(Attrs),
- {Attrs,St#expand{callbacks=Callbacks,
- optional_callbacks=OptionalCallbacks}}.
-
-get_optional_callbacks(Attrs) ->
- L = [O ||
- {attribute, _, optional_callbacks, O} <- Attrs,
- is_fa_list(O)],
- lists:append(L).
-
-is_fa_list([{FuncName, Arity}|L])
- when is_atom(FuncName), is_integer(Arity), Arity >= 0 ->
- is_fa_list(L);
-is_fa_list([]) -> true;
-is_fa_list(_) -> false.
-
-module_predef_funcs(St) ->
- {Mpf1,St1}=module_predef_func_beh_info(St),
- {Mpf2,St2}=module_predef_funcs_mod_info(St1),
- Mpf = [erl_parse:new_anno(F) || F <- Mpf1++Mpf2],
- {Mpf,St2}.
-
-module_predef_func_beh_info(#expand{callbacks=[]}=St) ->
- {[], St};
-module_predef_func_beh_info(#expand{callbacks=Callbacks,
- optional_callbacks=OptionalCallbacks,
- defined=Defined,
- exports=Exports}=St) ->
- PreDef=[{behaviour_info,1}],
- PreExp=PreDef,
- {[gen_beh_info(Callbacks, OptionalCallbacks)],
- St#expand{defined=gb_sets:union(gb_sets:from_list(PreDef), Defined),
- exports=union(from_list(PreExp), Exports)}}.
-
-gen_beh_info(Callbacks, OptionalCallbacks) ->
- List = make_list(Callbacks),
- OptionalList = make_optional_list(OptionalCallbacks),
- {function,0,behaviour_info,1,
- [{clause,0,[{atom,0,callbacks}],[],
- [List]},
- {clause,0,[{atom,0,optional_callbacks}],[],
- [OptionalList]}]}.
-
-make_list([]) -> {nil,0};
-make_list([{_,_,_,[{{Name,Arity},_}]}|Rest]) ->
- {cons,0,
- {tuple,0,
- [{atom,0,Name},
- {integer,0,Arity}]},
- make_list(Rest)}.
-
-make_optional_list([]) -> {nil,0};
-make_optional_list([{Name,Arity}|Rest]) ->
- {cons,0,
- {tuple,0,
- [{atom,0,Name},
- {integer,0,Arity}]},
- make_optional_list(Rest)}.
-
-module_predef_funcs_mod_info(St) ->
- PreDef = [{module_info,0},{module_info,1}],
- PreExp = PreDef,
- {[{function,0,module_info,0,
- [{clause,0,[],[],
- [{call,0,{remote,0,{atom,0,erlang},{atom,0,get_module_info}},
- [{atom,0,St#expand.module}]}]}]},
- {function,0,module_info,1,
- [{clause,0,[{var,0,'X'}],[],
- [{call,0,{remote,0,{atom,0,erlang},{atom,0,get_module_info}},
- [{atom,0,St#expand.module},{var,0,'X'}]}]}]}],
- St#expand{defined=gb_sets:union(gb_sets:from_list(PreDef),
- St#expand.defined),
- exports=union(from_list(PreExp), St#expand.exports)}}.
-
-%% forms(Forms, State) ->
-%% {TransformedForms,State'}
-%% Process the forms. Attributes are lost and just affect the state.
-%% Ignore uninteresting forms like eof and type.
-
-forms([{attribute,_,file,_File}=F|Fs0], St0) ->
- {Fs,St1} = forms(Fs0, St0),
- {[F|Fs],St1};
-forms([{attribute,Line,Name,Val}|Fs0], St0) ->
- St1 = attribute(Name, Val, Line, St0),
- forms(Fs0, St1);
-forms([{function,L,N,A,Cs}|Fs0], St0) ->
- {Ff,St1} = function(L, N, A, Cs, St0),
- {Fs,St2} = forms(Fs0, St1),
- {[Ff|Fs],St2};
-forms([_|Fs], St) -> forms(Fs, St);
-forms([], St) -> {[],St}.
-
-%% attribute(Attribute, Value, Line, State) -> State'.
-%% Process an attribute, this just affects the state.
-
-attribute(module, Module, _L, St) ->
- true = is_atom(Module),
- St#expand{module=Module};
-attribute(export, Es, _L, St) ->
- St#expand{exports=union(from_list(Es), St#expand.exports)};
-attribute(import, Is, _L, St) ->
- import(Is, St);
-attribute(compile, _C, _L, St) ->
- St;
-attribute(Name, Val, Line, St) when is_list(Val) ->
- St#expand{attributes=St#expand.attributes ++ [{Name,Line,Val}]};
-attribute(Name, Val, Line, St) ->
- St#expand{attributes=St#expand.attributes ++ [{Name,Line,[Val]}]}.
-
-function(L, N, A, Cs0, St0) ->
- {Cs,St} = clauses(Cs0, St0#expand{func=N,arity=A,fcount=0}),
- {{function,L,N,A,Cs},St}.
-
-%% clauses([Clause], State) ->
-%% {[TransformedClause],State}.
-%% Expand function clauses.
-
-clauses([{clause,Line,H0,G0,B0}|Cs0], St0) ->
- {H,St1} = head(H0, St0),
- {G,St2} = guard(G0, St1),
- {B,St3} = exprs(B0, St2),
- {Cs,St4} = clauses(Cs0, St3),
- {[{clause,Line,H,G,B}|Cs],St4};
-clauses([], St) -> {[],St}.
-
-%% head(HeadPatterns, State) ->
-%% {TransformedPatterns,Variables,UsedVariables,State'}
-
-head(As, St) -> pattern_list(As, St).
-
-%% pattern(Pattern, State) ->
-%% {TransformedPattern,State'}
-%%
-
-pattern({var,_,'_'}=Var, St) -> %Ignore anonymous variable.
- {Var,St};
-pattern({var,_,_}=Var, St) ->
- {Var,St};
-pattern({char,_,_}=Char, St) ->
- {Char,St};
-pattern({integer,_,_}=Int, St) ->
- {Int,St};
-pattern({float,_,_}=Float, St) ->
- {Float,St};
-pattern({atom,_,_}=Atom, St) ->
- {Atom,St};
-pattern({string,_,_}=String, St) ->
- {String,St};
-pattern({nil,_}=Nil, St) ->
- {Nil,St};
-pattern({cons,Line,H,T}, St0) ->
- {TH,St1} = pattern(H, St0),
- {TT,St2} = pattern(T, St1),
- {{cons,Line,TH,TT},St2};
-pattern({tuple,Line,Ps}, St0) ->
- {TPs,St1} = pattern_list(Ps, St0),
- {{tuple,Line,TPs},St1};
-pattern({map,Line,Ps}, St0) ->
- {TPs,St1} = pattern_list(Ps, St0),
- {{map,Line,TPs},St1};
-pattern({map_field_exact,Line,K0,V0}, St0) ->
- %% Key should be treated as an expression
- %% but since expressions are not allowed yet,
- %% process it through pattern .. and handle assoc
- %% (normalise unary op integer -> integer)
- {K,St1} = pattern(K0, St0),
- {V,St2} = pattern(V0, St1),
- {{map_field_exact,Line,K,V},St2};
-pattern({map_field_assoc,Line,K0,V0}, St0) ->
- %% when keys are Maps
- {K,St1} = pattern(K0, St0),
- {V,St2} = pattern(V0, St1),
- {{map_field_assoc,Line,K,V},St2};
-%%pattern({struct,Line,Tag,Ps}, St0) ->
-%% {TPs,TPsvs,St1} = pattern_list(Ps, St0),
-%% {{tuple,Line,[{atom,Line,Tag}|TPs]},TPsvs,St1};
-pattern({bin,Line,Es0}, St0) ->
- {Es1,St1} = pattern_bin(Es0, St0),
- {{bin,Line,Es1},St1};
-pattern({op,_,'++',{nil,_},R}, St) ->
- pattern(R, St);
-pattern({op,_,'++',{cons,Li,H,T},R}, St) ->
- pattern({cons,Li,H,{op,Li,'++',T,R}}, St);
-pattern({op,_,'++',{string,Li,L},R}, St) ->
- pattern(string_to_conses(Li, L, R), St);
-pattern({match,Line,Pat1, Pat2}, St0) ->
- {TH,St1} = pattern(Pat2, St0),
- {TT,St2} = pattern(Pat1, St1),
- {{match,Line,TT,TH},St2};
-%% Compile-time pattern expressions, including unary operators.
-pattern({op,_Line,_Op,_A}=Op, St) ->
- {erl_eval:partial_eval(Op),St};
-pattern({op,_Line,_Op,_L,_R}=Op, St) ->
- {erl_eval:partial_eval(Op),St}.
-
-pattern_list([P0|Ps0], St0) ->
- {P,St1} = pattern(P0, St0),
- {Ps,St2} = pattern_list(Ps0, St1),
- {[P|Ps],St2};
-pattern_list([], St) -> {[],St}.
-
-%% guard(Guard, State) ->
-%% {TransformedGuard,State'}
-%% Transform a list of guard tests. We KNOW that this has been checked
-%% and what the guards test are. Use expr for transforming the guard
-%% expressions.
-
-guard([G0|Gs0], St0) ->
- {G,St1} = guard_tests(G0, St0),
- {Gs,St2} = guard(Gs0, St1),
- {[G|Gs],St2};
-guard([], St) -> {[],St}.
-
-guard_tests([Gt0|Gts0], St0) ->
- {Gt1,St1} = guard_test(Gt0, St0),
- {Gts1,St2} = guard_tests(Gts0, St1),
- {[Gt1|Gts1],St2};
-guard_tests([], St) -> {[],St}.
-
-guard_test(Test, St) ->
- expr(Test, St).
-
-%% exprs(Expressions, State) ->
-%% {TransformedExprs,State'}
-
-exprs([E0|Es0], St0) ->
- {E,St1} = expr(E0, St0),
- {Es,St2} = exprs(Es0, St1),
- {[E|Es],St2};
-exprs([], St) -> {[],St}.
-
-%% expr(Expression, State) ->
-%% {TransformedExpression,State'}
-
-expr({var,_,_}=Var, St) ->
- {Var,St};
-expr({char,_,_}=Char, St) ->
- {Char,St};
-expr({integer,_,_}=Int, St) ->
- {Int,St};
-expr({float,_,_}=Float, St) ->
- {Float,St};
-expr({atom,_,_}=Atom, St) ->
- {Atom,St};
-expr({string,_,_}=String, St) ->
- {String,St};
-expr({nil,_}=Nil, St) ->
- {Nil,St};
-expr({cons,Line,H0,T0}, St0) ->
- {H,St1} = expr(H0, St0),
- {T,St2} = expr(T0, St1),
- {{cons,Line,H,T},St2};
-expr({lc,Line,E0,Qs0}, St0) ->
- {Qs1,St1} = lc_tq(Line, Qs0, St0),
- {E1,St2} = expr(E0, St1),
- {{lc,Line,E1,Qs1},St2};
-expr({bc,Line,E0,Qs0}, St0) ->
- {Qs1,St1} = lc_tq(Line, Qs0, St0),
- {E1,St2} = expr(E0, St1),
- {{bc,Line,E1,Qs1},St2};
-expr({tuple,Line,Es0}, St0) ->
- {Es1,St1} = expr_list(Es0, St0),
- {{tuple,Line,Es1},St1};
-%%expr({struct,Line,Tag,Es0}, Vs, St0) ->
-%% {Es1,Esvs,Esus,St1} = expr_list(Es0, Vs, St0),
-%% {{tuple,Line,[{atom,Line,Tag}|Es1]},Esvs,Esus,St1};
-expr({map,Line,Es0}, St0) ->
- {Es1,St1} = expr_list(Es0, St0),
- {{map,Line,Es1},St1};
-expr({map,Line,E0,Es0}, St0) ->
- {E1,St1} = expr(E0, St0),
- {Es1,St2} = expr_list(Es0, St1),
- {{map,Line,E1,Es1},St2};
-expr({map_field_assoc,Line,K0,V0}, St0) ->
- {K,St1} = expr(K0, St0),
- {V,St2} = expr(V0, St1),
- {{map_field_assoc,Line,K,V},St2};
-expr({map_field_exact,Line,K0,V0}, St0) ->
- {K,St1} = expr(K0, St0),
- {V,St2} = expr(V0, St1),
- {{map_field_exact,Line,K,V},St2};
-expr({bin,Line,Es0}, St0) ->
- {Es1,St1} = expr_bin(Es0, St0),
- {{bin,Line,Es1},St1};
-expr({block,Line,Es0}, St0) ->
- {Es,St1} = exprs(Es0, St0),
- {{block,Line,Es},St1};
-expr({'if',Line,Cs0}, St0) ->
- {Cs,St1} = icr_clauses(Cs0, St0),
- {{'if',Line,Cs},St1};
-expr({'case',Line,E0,Cs0}, St0) ->
- {E,St1} = expr(E0, St0),
- {Cs,St2} = icr_clauses(Cs0, St1),
- {{'case',Line,E,Cs},St2};
-expr({'receive',Line,Cs0}, St0) ->
- {Cs,St1} = icr_clauses(Cs0, St0),
- {{'receive',Line,Cs},St1};
-expr({'receive',Line,Cs0,To0,ToEs0}, St0) ->
- {To,St1} = expr(To0, St0),
- {ToEs,St2} = exprs(ToEs0, St1),
- {Cs,St3} = icr_clauses(Cs0, St2),
- {{'receive',Line,Cs,To,ToEs},St3};
-expr({'fun',Line,Body}, St) ->
- fun_tq(Line, Body, St);
-expr({named_fun,Line,Name,Cs}, St) ->
- fun_tq(Line, Cs, St, Name);
-expr({call,Line,{atom,La,N}=Atom,As0}, St0) ->
- {As,St1} = expr_list(As0, St0),
- Ar = length(As),
- case defined(N,Ar,St1) of
- true ->
- {{call,Line,Atom,As},St1};
- _ ->
- case imported(N, Ar, St1) of
- {yes,Mod} ->
- {{call,Line,{remote,La,{atom,La,Mod},Atom},As},St1};
- no ->
- case erl_internal:bif(N, Ar) of
- true ->
- {{call,Line,{remote,La,{atom,La,erlang},Atom},As},St1};
- false -> %% This should have been handled by erl_lint
- {{call,Line,Atom,As},St1}
- end
- end
- end;
-expr({call,Line,{remote,Lr,M0,F},As0}, St0) ->
- {[M1,F1|As1],St1} = expr_list([M0,F|As0], St0),
- {{call,Line,{remote,Lr,M1,F1},As1},St1};
-expr({call,Line,F,As0}, St0) ->
- {[Fun1|As1],St1} = expr_list([F|As0], St0),
- {{call,Line,Fun1,As1},St1};
-expr({'try',Line,Es0,Scs0,Ccs0,As0}, St0) ->
- {Es1,St1} = exprs(Es0, St0),
- {Scs1,St2} = icr_clauses(Scs0, St1),
- {Ccs1,St3} = icr_clauses(Ccs0, St2),
- {As1,St4} = exprs(As0, St3),
- {{'try',Line,Es1,Scs1,Ccs1,As1},St4};
-expr({'catch',Line,E0}, St0) ->
- %% Catch exports no new variables.
- {E,St1} = expr(E0, St0),
- {{'catch',Line,E},St1};
-expr({match,Line,P0,E0}, St0) ->
- {E,St1} = expr(E0, St0),
- {P,St2} = pattern(P0, St1),
- {{match,Line,P,E},St2};
-expr({op,Line,Op,A0}, St0) ->
- {A,St1} = expr(A0, St0),
- {{op,Line,Op,A},St1};
-expr({op,Line,Op,L0,R0}, St0) ->
- {L,St1} = expr(L0, St0),
- {R,St2} = expr(R0, St1),
- {{op,Line,Op,L,R},St2}.
-
-expr_list([E0|Es0], St0) ->
- {E,St1} = expr(E0, St0),
- {Es,St2} = expr_list(Es0, St1),
- {[E|Es],St2};
-expr_list([], St) -> {[],St}.
-
-%% icr_clauses([Clause], State) -> {[TransformedClause],State'}
-%% Be very careful here to return the variables that are really used
-%% and really new.
-
-icr_clauses([], St) -> {[],St};
-icr_clauses(Clauses, St) -> icr_clauses2(Clauses, St).
-
-icr_clauses2([{clause,Line,H0,G0,B0}|Cs0], St0) ->
- {H,St1} = head(H0, St0),
- {G,St2} = guard(G0, St1),
- {B,St3} = exprs(B0, St2),
- {Cs,St4} = icr_clauses2(Cs0, St3),
- {[{clause,Line,H,G,B}|Cs],St4};
-icr_clauses2([], St) -> {[],St}.
-
-%% lc_tq(Line, Qualifiers, State) ->
-%% {[TransQual],State'}
-
-lc_tq(Line, [{generate,Lg,P0,G0} | Qs0], St0) ->
- {G1,St1} = expr(G0, St0),
- {P1,St2} = pattern(P0, St1),
- {Qs1,St3} = lc_tq(Line, Qs0, St2),
- {[{generate,Lg,P1,G1} | Qs1],St3};
-
-lc_tq(Line, [{b_generate,Lg,P0,G0}|Qs0], St0) ->
- {G1,St1} = expr(G0, St0),
- {P1,St2} = pattern(P0, St1),
- {Qs1,St3} = lc_tq(Line, Qs0, St2),
- {[{b_generate,Lg,P1,G1}|Qs1],St3};
-lc_tq(Line, [F0 | Qs0], St0) ->
- case erl_lint:is_guard_test(F0) of
- true ->
- {F1,St1} = guard_test(F0, St0),
- {Qs1,St2} = lc_tq(Line, Qs0, St1),
- {[F1|Qs1],St2};
- false ->
- {F1,St1} = expr(F0, St0),
- {Qs1,St2} = lc_tq(Line, Qs0, St1),
- {[F1 | Qs1],St2}
- end;
-lc_tq(_Line, [], St0) ->
- {[],St0}.
-
-
-%% fun_tq(Line, Body, State) ->
-%% {Fun,State'}
-%% Transform an "explicit" fun {'fun', Line, {clauses, Cs}} into an
-%% extended form {'fun', Line, {clauses, Cs}, Info}, unless it is the
-%% name of a BIF (erl_lint has checked that it is not an import).
-%% "Implicit" funs {'fun', Line, {function, F, A}} are not changed.
-
-fun_tq(Lf, {function,F,A}=Function, St0) ->
- case erl_internal:bif(F, A) of
- true ->
- {As,St1} = new_vars(A, Lf, St0),
- Cs = [{clause,Lf,As,[],[{call,Lf,{atom,Lf,F},As}]}],
- fun_tq(Lf, {clauses,Cs}, St1);
- false ->
- {Fname,St1} = new_fun_name(St0),
- Index = Uniq = 0,
- {{'fun',Lf,Function,{Index,Uniq,Fname}},St1}
- end;
-fun_tq(L, {function,M,F,A}, St) when is_atom(M), is_atom(F), is_integer(A) ->
- %% This is the old format for external funs, generated by a pre-R15
- %% compiler. That means that a tool, such as the debugger or xref,
- %% directly invoked this module with the abstract code from a
- %% pre-R15 BEAM file. Be helpful, and translate it to the new format.
- fun_tq(L, {function,{atom,L,M},{atom,L,F},{integer,L,A}}, St);
-fun_tq(Lf, {function,_,_,_}=ExtFun, St) ->
- {{'fun',Lf,ExtFun},St};
-fun_tq(Lf, {clauses,Cs0}, St0) ->
- {Cs1,St1} = fun_clauses(Cs0, St0),
- {Fname,St2} = new_fun_name(St1),
- %% Set dummy values for Index and Uniq -- the real values will
- %% be assigned by beam_asm.
- Index = Uniq = 0,
- {{'fun',Lf,{clauses,Cs1},{Index,Uniq,Fname}},St2}.
-
-fun_tq(Line, Cs0, St0, Name) ->
- {Cs1,St1} = fun_clauses(Cs0, St0),
- {Fname,St2} = new_fun_name(St1, Name),
- {{named_fun,Line,Name,Cs1,{0,0,Fname}},St2}.
-
-fun_clauses([{clause,L,H0,G0,B0}|Cs0], St0) ->
- {H,St1} = head(H0, St0),
- {G,St2} = guard(G0, St1),
- {B,St3} = exprs(B0, St2),
- {Cs,St4} = fun_clauses(Cs0, St3),
- {[{clause,L,H,G,B}|Cs],St4};
-fun_clauses([], St) -> {[],St}.
-
-%% new_fun_name(State) -> {FunName,State}.
-
-new_fun_name(St) ->
- new_fun_name(St, 'fun').
-
-new_fun_name(#expand{func=F,arity=A,fcount=I}=St, FName) ->
- Name = "-" ++ atom_to_list(F) ++ "/" ++ integer_to_list(A)
- ++ "-" ++ atom_to_list(FName) ++ "-" ++ integer_to_list(I) ++ "-",
- {list_to_atom(Name),St#expand{fcount=I+1}}.
-
-%% pattern_bin([Element], State) -> {[Element],[Variable],[UsedVar],State}.
-
-pattern_bin(Es0, St) ->
- Es1 = bin_expand_strings(Es0),
- foldr(fun (E, Acc) -> pattern_element(E, Acc) end, {[],St}, Es1).
-
-pattern_element({bin_element,Line,Expr0,Size0,Type0}, {Es,St0}) ->
- {Expr1,St1} = pattern(Expr0, St0),
- {Size1,St2} = pat_bit_size(Size0, St1),
- {Size,Type} = make_bit_type(Line, Size1, Type0),
- Expr = coerce_to_float(Expr1, Type0),
- {[{bin_element,Line,Expr,Size,Type}|Es],St2}.
-
-pat_bit_size(default, St) -> {default,St};
-pat_bit_size({atom,_La,all}=All, St) -> {All,St};
-pat_bit_size({var,_Lv,_V}=Var, St) -> {Var,St};
-pat_bit_size(Size, St) ->
- Line = element(2, Size),
- {value,Sz,_} = erl_eval:expr(Size, erl_eval:new_bindings()),
- {{integer,Line,Sz},St}.
-
-make_bit_type(Line, default, Type0) ->
- case erl_bits:set_bit_type(default, Type0) of
- {ok,all,Bt} -> {{atom,Line,all},erl_bits:as_list(Bt)};
- {ok,undefined,Bt} -> {{atom,Line,undefined},erl_bits:as_list(Bt)};
- {ok,Size,Bt} -> {{integer,Line,Size},erl_bits:as_list(Bt)}
- end;
-make_bit_type(_Line, Size, Type0) -> %Integer or 'all'
- {ok,Size,Bt} = erl_bits:set_bit_type(Size, Type0),
- {Size,erl_bits:as_list(Bt)}.
-
-coerce_to_float({integer,L,I}=E, [float|_]) ->
- try
- {float,L,float(I)}
- catch
- error:badarg -> E;
- error:badarith -> E
- end;
-coerce_to_float(E, _) -> E.
-
-%% expr_bin([Element], State) -> {[Element],State}.
-
-expr_bin(Es0, St) ->
- Es1 = bin_expand_strings(Es0),
- foldr(fun (E, Acc) -> bin_element(E, Acc) end, {[],St}, Es1).
-
-bin_element({bin_element,Line,Expr,Size,Type}, {Es,St0}) ->
- {Expr1,St1} = expr(Expr, St0),
- {Size1,St2} = if Size == default -> {default,St1};
- true -> expr(Size, St1)
- end,
- {Size2,Type1} = make_bit_type(Line, Size1, Type),
- {[{bin_element,Line,Expr1,Size2,Type1}|Es],St2}.
-
-bin_expand_strings(Es) ->
- foldr(fun ({bin_element,Line,{string,_,S},Sz,Ts}, Es1) ->
- foldr(fun (C, Es2) ->
- [{bin_element,Line,{char,Line,C},Sz,Ts}|Es2]
- end, Es1, S);
- (E, Es1) -> [E|Es1]
- end, [], Es).
-
-%% new_var_name(State) -> {VarName,State}.
-
-new_var_name(St) ->
- C = St#expand.vcount,
- {list_to_atom("pre" ++ integer_to_list(C)),St#expand{vcount=C+1}}.
-
-%% new_var(Line, State) -> {Var,State}.
-
-new_var(L, St0) ->
- {New,St1} = new_var_name(St0),
- {{var,L,New},St1}.
-
-%% new_vars(Count, Line, State) -> {[Var],State}.
-%% Make Count new variables.
-
-new_vars(N, L, St) -> new_vars(N, L, St, []).
-
-new_vars(N, L, St0, Vs) when N > 0 ->
- {V,St1} = new_var(L, St0),
- new_vars(N-1, L, St1, [V|Vs]);
-new_vars(0, _L, St, Vs) -> {Vs,St}.
-
-string_to_conses(Line, Cs, Tail) ->
- foldr(fun (C, T) -> {cons,Line,{char,Line,C},T} end, Tail, Cs).
-
-
-%% import(Line, Imports, State) ->
-%% State'
-%% imported(Name, Arity, State) ->
-%% {yes,Module} | no
-%% Handle import declarations and test for imported functions. No need to
-%% check when building imports as code is correct.
-
-import({Mod,Fs}, St) ->
- true = is_atom(Mod),
- Mfs = from_list(Fs),
- St#expand{imports=add_imports(Mod, Mfs, St#expand.imports)}.
-
-add_imports(Mod, [F|Fs], Is) ->
- add_imports(Mod, Fs, orddict:store(F, Mod, Is));
-add_imports(_, [], Is) -> Is.
-
-imported(F, A, St) ->
- case orddict:find({F,A}, St#expand.imports) of
- {ok,Mod} -> {yes,Mod};
- error -> no
- end.
-
-defined(F, A, St) ->
- gb_sets:is_element({F,A}, St#expand.defined).
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
index 2a89305f4d..47c1567f10 100644
--- a/lib/compiler/src/v3_codegen.erl
+++ b/lib/compiler/src/v3_codegen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -69,6 +69,10 @@
stk=[], %Stack table
res=[]}). %Reserved regs: [{reserved,I,V}]
+-type life_module() :: {module(),_,_,[_]}.
+
+-spec module(life_module(), [compile:option()]) -> {'ok',beam_asm:module_code()}.
+
module({Mod,Exp,Attr,Forms}, _Options) ->
{Fs,St} = functions(Forms, {atom,Mod}),
{ok,{Mod,Exp,Attr,Fs,St#cg.lcount}}.
@@ -151,6 +155,8 @@ cg({bif,Bif,As,Rs}, Le, Vdb, Bef, St) ->
bif_cg(Bif, As, Rs, Le, Vdb, Bef, St);
cg({gc_bif,Bif,As,Rs}, Le, Vdb, Bef, St) ->
gc_bif_cg(Bif, As, Rs, Le, Vdb, Bef, St);
+cg({internal,Bif,As,Rs}, Le, Vdb, Bef, St) ->
+ internal_cg(Bif, As, Rs, Le, Vdb, Bef, St);
cg({receive_loop,Te,Rvar,Rm,Tes,Rs}, Le, Vdb, Bef, St) ->
recv_loop_cg(Te, Rvar, Rm, Tes, Rs, Le, Vdb, Bef, St);
cg(receive_next, Le, Vdb, Bef, St) ->
@@ -208,15 +214,10 @@ need_heap_1(#l{ke={set,_,Val}}, H) ->
{tuple,Es} -> 1 + length(Es);
_Other -> 0
end};
-need_heap_1(#l{ke={bif,dsetelement,_As,_Rs},i=I}, H) ->
- {need_heap_need(I, H),0};
-need_heap_1(#l{ke={bif,{make_fun,_,_,_,_},_As,_Rs},i=I}, H) ->
- {need_heap_need(I, H),0};
-need_heap_1(#l{ke={bif,bs_init_writable,_As,_Rs},i=I}, H) ->
- {need_heap_need(I, H),0};
need_heap_1(#l{ke={bif,_Bif,_As,_Rs}}, H) ->
{[],H};
need_heap_1(#l{i=I}, H) ->
+ %% Call or call-like instruction such as set_tuple_element/3.
{need_heap_need(I, H),0}.
need_heap_need(_I, 0) -> [];
@@ -366,7 +367,7 @@ bsm_rename_ctx(#l{ke={match,Ms0,Rs}}=L, Old, New, InProt) ->
bsm_rename_ctx(#l{ke={guard_match,Ms0,Rs}}=L, Old, New, InProt) ->
Ms = bsm_rename_ctx(Ms0, Old, New, InProt),
L#l{ke={guard_match,Ms,Rs}};
-bsm_rename_ctx(#l{ke={test,_,_}}=L, _, _, _) -> L;
+bsm_rename_ctx(#l{ke={test,_,_,_}}=L, _, _, _) -> L;
bsm_rename_ctx(#l{ke={bif,_,_,_}}=L, _, _, _) -> L;
bsm_rename_ctx(#l{ke={gc_bif,_,_,_}}=L, _, _, _) -> L;
bsm_rename_ctx(#l{ke={set,_,_}}=L, _, _, _) -> L;
@@ -827,21 +828,24 @@ select_extract_bin([{var,Hd},{var,Tl}], Size0, Unit, Type, Flags, Vf,
{bs_save2,CtxReg,{Ctx,Tl}}],Int1}
end,
{Es,clear_dead(Aft, I, Vdb),St};
-select_extract_bin([{var,Hd}], Size0, Unit, binary, Flags, Vf,
+select_extract_bin([{var,Hd}], Size, Unit, binary, Flags, Vf,
I, Vdb, Bef, Ctx, Body, St) ->
- SizeReg = get_bin_size_reg(Size0, Bef),
+ %% Match the last segment of a binary. We KNOW that the size
+ %% must be 'all'.
+ Size = {atom,all}, %Assertion.
{Es,Aft} =
case vdb_find(Hd, Vdb) of
{_,_,Lhd} when Lhd =< I ->
+ %% The result will not be used. Furthermore, since we
+ %% we are at the end of the binary, the position will
+ %% not be used again; thus, it is safe to do a cheaper
+ %% test of the unit.
CtxReg = fetch_var(Ctx, Bef),
- {case SizeReg =:= {atom,all} andalso is_context_unused(Body) of
- true when Unit =:= 1 ->
+ {case Unit of
+ 1 ->
[];
- true ->
- [{test,bs_test_unit,{f,Vf},[CtxReg,Unit]}];
- false ->
- [{test,bs_skip_bits2,{f,Vf},
- [CtxReg,SizeReg,Unit,{field_flags,Flags}]}]
+ _ ->
+ [{test,bs_test_unit,{f,Vf},[CtxReg,Unit]}]
end,Bef};
{_,_,_} ->
case is_context_unused(Body) of
@@ -853,7 +857,7 @@ select_extract_bin([{var,Hd}], Size0, Unit, binary, Flags, Vf,
Name = bs_get_binary2,
Live = max_reg(Bef#sr.reg),
{[{test,Name,{f,Vf},Live,
- [CtxReg,SizeReg,Unit,{field_flags,Flags}],Rhd}],
+ [CtxReg,Size,Unit,{field_flags,Flags}],Rhd}],
Int1};
true ->
%% Since the matching context will not be used again,
@@ -868,7 +872,7 @@ select_extract_bin([{var,Hd}], Size0, Unit, binary, Flags, Vf,
Name = bs_get_binary2,
Live = max_reg(Int1#sr.reg),
{[{test,Name,{f,Vf},Live,
- [CtxReg,SizeReg,Unit,{field_flags,Flags}],CtxReg}],
+ [CtxReg,Size,Unit,{field_flags,Flags}],CtxReg}],
Int1}
end
end,
@@ -1051,8 +1055,15 @@ guard_cg(#l{ke={protected,Ts,Rs},i=I,vdb=Pdb}, Fail, _Vdb, Bef, St) ->
protected_cg(Ts, Rs, Fail, I, Pdb, Bef, St);
guard_cg(#l{ke={block,Ts},i=I,vdb=Bdb}, Fail, _Vdb, Bef, St) ->
guard_cg_list(Ts, Fail, I, Bdb, Bef, St);
-guard_cg(#l{ke={test,Test,As},i=I,vdb=_Tdb}, Fail, Vdb, Bef, St) ->
- test_cg(Test, As, Fail, I, Vdb, Bef, St);
+guard_cg(#l{ke={test,Test,As,Inverted},i=I,vdb=_Tdb}, Fail, Vdb, Bef, St0) ->
+ case Inverted of
+ false ->
+ test_cg(Test, As, Fail, I, Vdb, Bef, St0);
+ true ->
+ {Psucc,St1} = new_label(St0),
+ {Is,Aft,St2} = test_cg(Test, As, Psucc, I, Vdb, Bef, St1),
+ {Is++[{jump,{f,Fail}},{label,Psucc}],Aft,St2}
+ end;
guard_cg(G, _Fail, Vdb, Bef, St) ->
%%ok = io:fwrite("cg ~w: ~p~n", [?LINE,{G,Fail,Vdb,Bef}]),
{Gis,Aft,St1} = cg(G, Vdb, Bef, St),
@@ -1086,6 +1097,30 @@ protected_cg(Ts, Rs, _Fail, I, Vdb, Bef, St0) ->
%% test_cg(TestName, Args, Fail, I, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
%% Generate test instruction. Use explicit fail label here.
+test_cg(is_map, [A], Fail, I, Vdb, Bef, St) ->
+ %% We must avoid creating code like this:
+ %%
+ %% move x(0) y(0)
+ %% is_map Fail [x(0)]
+ %% make_fun => x(0) %% Overwrite x(0)
+ %% put_map_assoc y(0) ...
+ %%
+ %% The code is safe, but beam_validator does not understand that.
+ %% Extending beam_validator to handle such (rare) code as the
+ %% above would make it slower for all programs. Instead, change
+ %% the code generator to always prefer the Y register for is_map()
+ %% and put_map_assoc() instructions, ensuring that they use the
+ %% same register.
+ Arg = cg_reg_arg_prefer_y(A, Bef),
+ Aft = clear_dead(Bef, I, Vdb),
+ {[{test,is_map,{f,Fail},[Arg]}],Aft,St};
+test_cg(is_boolean, [{atom,Val}], Fail, I, Vdb, Bef, St) ->
+ Aft = clear_dead(Bef, I, Vdb),
+ Is = case is_boolean(Val) of
+ true -> [];
+ false -> [{jump,{f,Fail}}]
+ end,
+ {Is,Aft,St};
test_cg(Test, As, Fail, I, Vdb, Bef, St) ->
Args = cg_reg_args(As, Bef),
Aft = clear_dead(Bef, I, Vdb),
@@ -1152,19 +1187,15 @@ call_cg(Func, As, Rs, Le, Vdb, Bef, St0) ->
%% Inside a guard. The only allowed function call is to
%% erlang:error/1,2. We will generate the following code:
%%
- %% jump FailureLabel
%% move {atom,ok} DestReg
- %%
- %% The 'move' instruction will never be executed, but we
- %% generate it anyway in case the beam_validator is run
- %% on unoptimized code.
+ %% jump FailureLabel
{remote,{atom,erlang},{atom,error}} = Func, %Assertion.
[{var,DestVar}] = Rs,
Int0 = clear_dead(Bef, Le#l.i, Vdb),
Reg = put_reg(DestVar, Int0#sr.reg),
Int = Int0#sr{reg=Reg},
Dst = fetch_reg(DestVar, Reg),
- {[{jump,{f,Fail}},{move,{atom,ok},Dst}],
+ {[{move,{atom,ok},Dst},{jump,{f,Fail}}],
clear_dead(Int, Le#l.i, Vdb),St0};
#cg{} ->
%% Ordinary function call in a function body.
@@ -1285,10 +1316,10 @@ trap_bif(erlang, group_leader, 2) -> true;
trap_bif(erlang, exit, 2) -> true;
trap_bif(_, _, _) -> false.
-%% bif_cg(Bif, [Arg], [Ret], Le, Vdb, StackReg, State) ->
+%% internal_cg(Bif, [Arg], [Ret], Le, Vdb, StackReg, State) ->
%% {[Ainstr],StackReg,State}.
-bif_cg(bs_context_to_binary=Instr, [Src0], [], Le, Vdb, Bef, St0) ->
+internal_cg(bs_context_to_binary=Instr, [Src0], [], Le, Vdb, Bef, St0) ->
[Src] = cg_reg_args([Src0], Bef),
case is_register(Src) of
false ->
@@ -1296,25 +1327,34 @@ bif_cg(bs_context_to_binary=Instr, [Src0], [], Le, Vdb, Bef, St0) ->
true ->
{[{Instr,Src}],clear_dead(Bef, Le#l.i, Vdb), St0}
end;
-bif_cg(dsetelement, [Index0,Tuple0,New0], _Rs, Le, Vdb, Bef, St0) ->
+internal_cg(dsetelement, [Index0,Tuple0,New0], _Rs, Le, Vdb, Bef, St0) ->
[New,Tuple,{integer,Index1}] = cg_reg_args([New0,Tuple0,Index0], Bef),
Index = Index1-1,
{[{set_tuple_element,New,Tuple,Index}],
clear_dead(Bef, Le#l.i, Vdb), St0};
-bif_cg({make_fun,Func,Arity,Index,Uniq}, As, Rs, Le, Vdb, Bef, St0) ->
+internal_cg(make_fun, [Func0,Arity0|As], Rs, Le, Vdb, Bef, St0) ->
%% This behaves more like a function call.
+ {atom,Func} = Func0,
+ {integer,Arity} = Arity0,
{Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
{FuncLbl,St1} = local_func_label(Func, Arity, St0),
- MakeFun = {make_fun2,{f,FuncLbl},Index,Uniq,length(As)},
+ MakeFun = {make_fun2,{f,FuncLbl},0,0,length(As)},
{Sis ++ [MakeFun],
clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb),
St1};
-bif_cg(bs_init_writable=I, As, Rs, Le, Vdb, Bef, St) ->
+internal_cg(bs_init_writable=I, As, Rs, Le, Vdb, Bef, St) ->
%% This behaves like a function call.
{Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
{Sis++[I],clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb),St};
+internal_cg(raise, As, Rs, Le, Vdb, Bef, St) ->
+ %% raise can be treated like a guard BIF.
+ bif_cg(raise, As, Rs, Le, Vdb, Bef, St).
+
+%% bif_cg(Bif, [Arg], [Ret], Le, Vdb, StackReg, State) ->
+%% {[Ainstr],StackReg,State}.
+
bif_cg(Bif, As, [{var,V}], Le, Vdb, Bef, St0) ->
Ars = cg_reg_args(As, Bef),
@@ -1535,14 +1575,12 @@ set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef, #cg{bfail=Bfail}=St) ->
%% Now generate the complete code for constructing the binary.
Code = cg_binary(PutCode, Target, Temp, Fail, MaxRegs, Le#l.a),
{Sis++Code,Aft,St};
-% Map single variable key
-set_cg([{var,R}], {map,Op,Map,[{map_pair,{var,_}=K,V}]}, Le, Vdb, Bef,
- #cg{bfail=Bfail}=St) ->
- Fail = {f,Bfail},
- {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St),
+%% Map: single variable key.
+set_cg([{var,R}], {map,Op,Map,[{map_pair,{var,_}=K,V}]}, Le, Vdb, Bef, St0) ->
+ {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0),
- SrcReg = cg_reg_arg(Map,Int0),
+ SrcReg = cg_reg_arg_prefer_y(Map, Int0),
Line = line(Le#l.a),
List = [cg_reg_arg(K,Int0),cg_reg_arg(V,Int0)],
@@ -1554,22 +1592,17 @@ set_cg([{var,R}], {map,Op,Map,[{map_pair,{var,_}=K,V}]}, Le, Vdb, Bef,
Aft = Aft0#sr{reg=put_reg(R, Aft0#sr.reg)},
Target = fetch_reg(R, Aft#sr.reg),
- I = case Op of
- assoc -> put_map_assoc;
- exact -> put_map_exact
- end,
- {Sis++[Line]++[{I,Fail,SrcReg,Target,Live,{list,List}}],Aft,St};
+ {Is,St1} = set_cg_map(Line, Op, SrcReg, Target, Live, List, St0),
+ {Sis++Is,Aft,St1};
-% Map (possibly) multiple literal keys
-set_cg([{var,R}], {map,Op,Map,Es}, Le, Vdb, Bef,
- #cg{bfail=Bfail}=St) ->
+%% Map: (possibly) multiple literal keys.
+set_cg([{var,R}], {map,Op,Map,Es}, Le, Vdb, Bef, St0) ->
%% assert key literals
[] = [Var||{map_pair,{var,_}=Var,_} <- Es],
- Fail = {f,Bfail},
- {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St),
- SrcReg = cg_reg_arg(Map,Int0),
+ {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0),
+ SrcReg = cg_reg_arg_prefer_y(Map, Int0),
Line = line(Le#l.a),
%% fetch registers for values to be put into the map
@@ -1583,11 +1616,10 @@ set_cg([{var,R}], {map,Op,Map,Es}, Le, Vdb, Bef,
Aft = Aft0#sr{reg=put_reg(R, Aft0#sr.reg)},
Target = fetch_reg(R, Aft#sr.reg),
- I = case Op of
- assoc -> put_map_assoc;
- exact -> put_map_exact
- end,
- {Sis++[Line]++[{I,Fail,SrcReg,Target,Live,{list,List}}],Aft,St};
+ {Is,St1} = set_cg_map(Line, Op, SrcReg, Target, Live, List, St0),
+ {Sis++Is,Aft,St1};
+
+%% Everything else.
set_cg([{var,R}], Con, Le, Vdb, Bef, St) ->
%% Find a place for the return register first.
Int = Bef#sr{reg=put_reg(R, Bef#sr.reg)},
@@ -1600,6 +1632,34 @@ set_cg([{var,R}], Con, Le, Vdb, Bef, St) ->
end,
{Ais,clear_dead(Int, Le#l.i, Vdb),St}.
+
+set_cg_map(Line, Op0, SrcReg, Target, Live, List, St0) ->
+ Bfail = St0#cg.bfail,
+ Fail = {f,St0#cg.bfail},
+ Op = case Op0 of
+ assoc -> put_map_assoc;
+ exact -> put_map_exact
+ end,
+ {OkLbl,St1} = new_label(St0),
+ {BadLbl,St2} = new_label(St1),
+ Is = if
+ Bfail =:= 0 orelse Op =:= put_map_assoc ->
+ [Line,{Op,{f,0},SrcReg,Target,Live,{list,List}}];
+ true ->
+ %% Ensure that Target is always set, even if
+ %% the map update operation fails. That is necessary
+ %% because Target may be included in a test_heap
+ %% instruction.
+ [Line,
+ {Op,{f,BadLbl},SrcReg,Target,Live,{list,List}},
+ {jump,{f,OkLbl}},
+ {label,BadLbl},
+ {move,{atom,ok},Target},
+ {jump,Fail},
+ {label,OkLbl}]
+ end,
+ {Is,St2}.
+
%%%
%%% Code generation for constructing binaries.
%%%
@@ -1842,6 +1902,9 @@ cg_reg_args(As, Bef) -> [cg_reg_arg(A, Bef) || A <- As].
cg_reg_arg({var,V}, Bef) -> fetch_var(V, Bef);
cg_reg_arg(Literal, _) -> Literal.
+cg_reg_arg_prefer_y({var,V}, Bef) -> fetch_var_prefer_y(V, Bef);
+cg_reg_arg_prefer_y(Literal, _) -> Literal.
+
%% cg_setup_call([Arg], Bef, Cur, Vdb) -> {[Instr],Aft}.
%% Do the complete setup for a call/enter.
@@ -2083,6 +2146,12 @@ fetch_var(V, Sr) ->
error -> fetch_stack(V, Sr#sr.stk)
end.
+fetch_var_prefer_y(V, #sr{reg=Reg,stk=Stk}) ->
+ case find_stack(V, Stk) of
+ {ok,R} -> R;
+ error -> fetch_reg(V, Reg)
+ end.
+
load_vars(Vs, Regs) ->
foldl(fun ({var,V}, Rs) -> put_reg(V, Rs) end, Regs, Vs).
@@ -2156,11 +2225,11 @@ fetch_stack(Var, Stk) -> fetch_stack(Var, Stk, 0).
fetch_stack(V, [{V}|_], I) -> {yy,I};
fetch_stack(V, [_|Stk], I) -> fetch_stack(V, Stk, I+1).
-% find_stack(Var, Stk) -> find_stack(Var, Stk, 0).
+find_stack(Var, Stk) -> find_stack(Var, Stk, 0).
-% find_stack(V, [{V}|Stk], I) -> {ok,{yy,I}};
-% find_stack(V, [O|Stk], I) -> find_stack(V, Stk, I+1);
-% find_stack(V, [], I) -> error.
+find_stack(V, [{V}|_], I) -> {ok,{yy,I}};
+find_stack(V, [_|Stk], I) -> find_stack(V, Stk, I+1);
+find_stack(_, [], _) -> error.
on_stack(V, Stk) -> keymember(V, 1, Stk).
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 7d93e2ae16..ae650546e5 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. 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.
@@ -137,11 +137,13 @@
-record(core, {vcount=0 :: non_neg_integer(), %Variable counter
fcount=0 :: non_neg_integer(), %Function counter
+ function={none,0} :: fa(), %Current function.
in_guard=false :: boolean(), %In guard or not.
wanted=true :: boolean(), %Result wanted or not.
opts :: [compile:option()], %Options.
ws=[] :: [warning()], %Warnings.
- file=[{file,""}]}). %File
+ file=[{file,""}] %File.
+ }).
%% XXX: The following type declarations do not belong in this module
-type fa() :: {atom(), arity()}.
@@ -149,38 +151,73 @@
-type form() :: {function, integer(), atom(), arity(), _}
| {attribute, integer(), attribute(), _}.
--spec module({module(), [fa()], [form()]}, [compile:option()]) ->
+-record(imodule, {name = [],
+ exports = ordsets:new(),
+ attrs = [],
+ defs = [],
+ file = [],
+ opts = [],
+ ws = []}).
+
+-spec module([form()], [compile:option()]) ->
{'ok',cerl:c_module(),[warning()]}.
-module({Mod,Exp,Forms}, Opts) ->
- Cexp = map(fun ({_N,_A} = NA) -> #c_var{name=NA} end, Exp),
- {Kfs0,As0,Ws,_File} = foldl(fun (F, Acc) ->
- form(F, Acc, Opts)
- end, {[],[],[],[]}, Forms),
- Kfs = reverse(Kfs0),
+module(Forms0, Opts) ->
+ Forms = erl_internal:add_predefined_functions(Forms0),
+ Module = foldl(fun (F, Acc) ->
+ form(F, Acc, Opts)
+ end, #imodule{}, Forms),
+ #imodule{name=Mod,exports=Exp0,attrs=As0,defs=Kfs0,ws=Ws} = Module,
+ Exp = case member(export_all, Opts) of
+ true -> defined_functions(Forms);
+ false -> Exp0
+ end,
+ Cexp = [#c_var{name=FA} || {_,_}=FA <- Exp],
As = reverse(As0),
+ Kfs = reverse(Kfs0),
{ok,#c_module{name=#c_literal{val=Mod},exports=Cexp,attrs=As,defs=Kfs},Ws}.
-form({function,_,_,_,_}=F0, {Fs,As,Ws0,File}, Opts) ->
+form({function,_,_,_,_}=F0, Module, Opts) ->
+ #imodule{file=File,defs=Defs,ws=Ws0} = Module,
{F,Ws} = function(F0, Ws0, File, Opts),
- {[F|Fs],As,Ws,File};
-form({attribute,_,file,{File,_Line}}, {Fs,As,Ws,_}, _Opts) ->
- {Fs,As,Ws,File};
-form({attribute,_,_,_}=F, {Fs,As,Ws,File}, _Opts) ->
- {Fs,[attribute(F)|As],Ws,File}.
-
-attribute(Attribute) ->
- Fun = fun(A) -> [erl_anno:location(A)] end,
- {attribute,Line,Name,Val} = erl_parse:map_anno(Fun, Attribute),
+ Module#imodule{defs=[F|Defs],ws=Ws};
+form({attribute,_,module,Mod}, Module, _Opts) ->
+ true = is_atom(Mod),
+ Module#imodule{name=Mod};
+form({attribute,_,file,{File,_Line}}=F, #imodule{attrs=As}=Module, _Opts) ->
+ Module#imodule{file=File, attrs=[attribute(F)|As]};
+form({attribute,_,import,_}, Module, _Opts) ->
+ %% Ignore. We have no futher use for imports.
+ Module;
+form({attribute,_,export,Es}, #imodule{exports=Exp0}=Module, _Opts) ->
+ Exp = ordsets:union(ordsets:from_list(Es), Exp0),
+ Module#imodule{exports=Exp};
+form({attribute,_,_,_}=F, #imodule{attrs=As}=Module, _Opts) ->
+ Module#imodule{attrs=[attribute(F)|As]};
+form(_, Module, _Opts) ->
+ %% Ignore uninteresting forms such as 'eof'.
+ Module.
+
+attribute({attribute,A,Name,Val0}) ->
+ Line = [erl_anno:location(A)],
+ Val = if
+ is_list(Val0) -> Val0;
+ true -> [Val0]
+ end,
{#c_literal{val=Name, anno=Line}, #c_literal{val=Val, anno=Line}}.
+defined_functions(Forms) ->
+ Fs = [{Name,Arity} || {function,_,Name,Arity,_} <- Forms],
+ ordsets:from_list(Fs).
+
%% function_dump(module_info,_,_,_) -> ok;
%% function_dump(Name,Arity,Format,Terms) ->
%% io:format("~w/~w " ++ Format,[Name,Arity]++Terms),
%% ok.
function({function,_,Name,Arity,Cs0}, Ws0, File, Opts) ->
- St0 = #core{vcount=0,opts=Opts,ws=Ws0,file=[{file,File}]},
+ St0 = #core{vcount=0,function={Name,Arity},opts=Opts,
+ ws=Ws0,file=[{file,File}]},
{B0,St1} = body(Cs0, Name, Arity, St0),
%% ok = function_dump(Name,Arity,"body:~n~p~n",[B0]),
{B1,St2} = ubody(B0, St1),
@@ -469,7 +506,8 @@ unforce_tree([#iset{var=#c_var{name=V},arg=Arg0}|Es], D0) ->
unforce_tree(Es, D);
unforce_tree([#icall{}=Call], D) ->
unforce_tree_subst(Call, D);
-unforce_tree([Top], _) -> Top.
+unforce_tree([#c_var{name=V}], D) ->
+ gb_trees:get(V, D).
unforce_tree_subst(#icall{module=#c_literal{val=erlang},
name=#c_literal{val='=:='},
@@ -631,9 +669,11 @@ expr({'catch',L,E0}, St0) ->
{E1,Eps,St1} = expr(E0, St0),
Lanno = lineno_anno(L, St1),
{#icatch{anno=#a{anno=Lanno},body=Eps ++ [E1]},[],St1};
-expr({'fun',L,{function,F,A},{_,_,_}=Id}, St) ->
- Lanno = full_anno(L, St),
- {#c_var{anno=Lanno++[{id,Id}],name={F,A}},[],St};
+expr({'fun',L,{function,F,A}}, St0) ->
+ {Fname,St1} = new_fun_name(St0),
+ Lanno = full_anno(L, St1),
+ Id = {0,0,Fname},
+ {#c_var{anno=Lanno++[{id,Id}],name={F,A}},[],St1};
expr({'fun',L,{function,M,F,A}}, St0) ->
{As,Aps,St1} = safe_list([M,F,A], St0),
Lanno = full_anno(L, St1),
@@ -641,12 +681,12 @@ expr({'fun',L,{function,M,F,A}}, St0) ->
module=#c_literal{val=erlang},
name=#c_literal{val=make_fun},
args=As},Aps,St1};
-expr({'fun',L,{clauses,Cs},Id}, St) ->
- fun_tq(Id, Cs, L, St, unnamed);
-expr({named_fun,L,'_',Cs,Id}, St) ->
- fun_tq(Id, Cs, L, St, unnamed);
-expr({named_fun,L,Name,Cs,Id}, St) ->
- fun_tq(Id, Cs, L, St, {named,Name});
+expr({'fun',L,{clauses,Cs}}, St) ->
+ fun_tq(Cs, L, St, unnamed);
+expr({named_fun,L,'_',Cs}, St) ->
+ fun_tq(Cs, L, St, unnamed);
+expr({named_fun,L,Name,Cs}, St) ->
+ fun_tq(Cs, L, St, {named,Name});
expr({call,L,{remote,_,M,F},As0}, St0) ->
{[M1,F1|As1],Aps,St1} = safe_list([M,F|As0], St0),
Anno = full_anno(L, St1),
@@ -680,9 +720,36 @@ expr({match,L,P0,E0}, St0) ->
Fc = fail_clause([Fpat], Lanno, c_tuple([#c_literal{val=badmatch},Fpat])),
case P2 of
nomatch ->
- St = add_warning(L, nomatch, St5),
- {#icase{anno=#a{anno=Lanno},
- args=[E2],clauses=[],fc=Fc},Eps1++Eps2,St};
+ %% The pattern will not match. We must take care here to
+ %% bind all variables that the pattern would have bound
+ %% so that subsequent expressions do not refer to unbound
+ %% variables.
+ %%
+ %% As an example, this code:
+ %%
+ %% [X] = {Y} = E,
+ %% X + Y.
+ %%
+ %% will be rewritten to:
+ %%
+ %% error({badmatch,E}),
+ %% case E of
+ %% {[X],{Y}} ->
+ %% X + Y;
+ %% Other ->
+ %% error({badmatch,Other})
+ %% end.
+ %%
+ St6 = add_warning(L, nomatch, St5),
+ {Expr,Eps3,St7} = safe(E1, St6),
+ SanPat0 = sanitize(P1),
+ {SanPat,Eps4,St} = pattern(SanPat0, St7),
+ Badmatch = c_tuple([#c_literal{val=badmatch},Expr]),
+ Fail = #iprimop{anno=#a{anno=Lanno},
+ name=#c_literal{val=match_fail},
+ args=[Badmatch]},
+ Eps = Eps3 ++ Eps4 ++ [Fail],
+ {#imatch{anno=#a{anno=Lanno},pat=SanPat,arg=Expr,fc=Fc},Eps,St};
Other when not is_atom(Other) ->
{#imatch{anno=#a{anno=Lanno},pat=P2,arg=E2,fc=Fc},Eps1++Eps2,St5}
end;
@@ -724,6 +791,32 @@ expr({op,L,Op,L0,R0}, St0) ->
module=#c_literal{anno=LineAnno,val=erlang},
name=#c_literal{anno=LineAnno,val=Op},args=As},Aps,St1}.
+
+%% sanitize(Pat) -> SanitizedPattern
+%% Rewrite Pat so that it will be accepted by pattern/2 and will
+%% bind the same variables as the original pattern.
+%%
+%% Here is an example of a pattern that would cause a pattern/2
+%% to generate a 'nomatch' exception:
+%%
+%% #{k:=X,k:=Y} = [Z]
+%%
+%% The sanitized pattern will look like:
+%%
+%% {{X,Y},[Z]}
+
+sanitize({match,L,P1,P2}) ->
+ {tuple,L,[sanitize(P1),sanitize(P2)]};
+sanitize({cons,L,H,T}) ->
+ {cons,L,sanitize(H),sanitize(T)};
+sanitize({tuple,L,Ps0}) ->
+ Ps = [sanitize(P) || P <- Ps0],
+ {tuple,L,Ps};
+sanitize({map,L,Ps0}) ->
+ Ps = [sanitize(V) || {map_field_exact,_,_,V} <- Ps0],
+ {tuple,L,Ps};
+sanitize(P) -> P.
+
make_bool_switch(L, E, V, T, F, #core{in_guard=true}) ->
make_bool_switch_guard(L, E, V, T, F);
make_bool_switch(L, E, V, T, F, #core{}) ->
@@ -783,22 +876,36 @@ badmap_term(_Map, #core{in_guard=true}) ->
%% since it is not user-visible.
#c_literal{val=badmap};
badmap_term(Map, #core{in_guard=false}) ->
- #c_tuple{es=[#c_literal{val=badmap},Map]}.
+ c_tuple([#c_literal{val=badmap},Map]).
map_build_pairs(Map, Es0, Ann, St0) ->
- {Es,Pre,St1} = map_build_pairs_1(Es0, St0),
+ {Es,Pre,_,St1} = map_build_pairs_1(Es0, cerl_sets:new(), St0),
{ann_c_map(Ann, Map, Es),Pre,St1}.
-map_build_pairs_1([{Op0,L,K0,V0}|Es], St0) ->
+map_build_pairs_1([{Op0,L,K0,V0}|Es], Used0, St0) ->
{K,Pre0,St1} = safe(K0, St0),
{V,Pre1,St2} = safe(V0, St1),
- {Pairs,Pre2,St3} = map_build_pairs_1(Es, St2),
+ {Pairs,Pre2,Used1,St3} = map_build_pairs_1(Es, Used0, St2),
As = lineno_anno(L, St3),
Op = map_op(Op0),
+ {Used2,St4} = maybe_warn_repeated_keys(K, L, Used1, St3),
Pair = cerl:ann_c_map_pair(As, Op, K, V),
- {[Pair|Pairs],Pre0++Pre1++Pre2,St3};
-map_build_pairs_1([], St) ->
- {[],[],St}.
+ {[Pair|Pairs],Pre0++Pre1++Pre2,Used2,St4};
+map_build_pairs_1([], Used, St) ->
+ {[],[],Used,St}.
+
+maybe_warn_repeated_keys(Ck,Line,Used,St) ->
+ case cerl:is_literal(Ck) of
+ false -> {Used,St};
+ true ->
+ K = cerl:concrete(Ck),
+ case cerl_sets:is_element(K,Used) of
+ true ->
+ {Used, add_warning(Line, {map_key_repeated,K}, St)};
+ false ->
+ {cerl_sets:add_element(K,Used), St}
+ end
+ end.
map_op(map_field_assoc) -> #c_literal{val=assoc};
map_op(map_field_exact) -> #c_literal{val=exact}.
@@ -814,12 +921,16 @@ try_exception(Ecs0, St0) ->
{Evs,St1} = new_vars(3, St0), % Tag, Value, Info
{Ecs1,Ceps,St2} = clauses(Ecs0, St1),
[_,Value,Info] = Evs,
- Ec = #iclause{anno=#a{anno=[compiler_generated]},
+ LA = case Ecs1 of
+ [] -> [];
+ [C|_] -> get_lineno_anno(C)
+ end,
+ Ec = #iclause{anno=#a{anno=[compiler_generated|LA]},
pats=[c_tuple(Evs)],guard=[#c_literal{val=true}],
body=[#iprimop{anno=#a{}, %Must have an #a{}
name=#c_literal{val=raise},
args=[Info,Value]}]},
- Hs = [#icase{anno=#a{},args=[c_tuple(Evs)],clauses=Ecs1,fc=Ec}],
+ Hs = [#icase{anno=#a{anno=LA},args=[c_tuple(Evs)],clauses=Ecs1,fc=Ec}],
{Evs,Ceps++Hs,St2}.
try_after(As, St0) ->
@@ -841,14 +952,29 @@ try_after(As, St0) ->
%% record whereas c_literal should not have a wrapped annotation
expr_bin(Es0, Anno, St0) ->
- case constant_bin(Es0) of
+ Es1 = [bin_element(E) || E <- Es0],
+ case constant_bin(Es1) of
error ->
- {Es,Eps,St} = expr_bin_1(Es0, St0),
+ {Es,Eps,St} = expr_bin_1(bin_expand_strings(Es1), St0),
{#ibinary{anno=#a{anno=Anno},segments=Es},Eps,St};
Bin ->
{#c_literal{anno=Anno,val=Bin},[],St0}
end.
+bin_element({bin_element,Line,Expr,Size0,Type0}) ->
+ {Size,Type} = make_bit_type(Line, Size0, Type0),
+ {bin_element,Line,Expr,Size,Type}.
+
+make_bit_type(Line, default, Type0) ->
+ case erl_bits:set_bit_type(default, Type0) of
+ {ok,all,Bt} -> {{atom,Line,all},erl_bits:as_list(Bt)};
+ {ok,undefined,Bt} -> {{atom,Line,undefined},erl_bits:as_list(Bt)};
+ {ok,Size,Bt} -> {{integer,Line,Size},erl_bits:as_list(Bt)}
+ end;
+make_bit_type(_Line, Size, Type0) -> %Integer or 'all'
+ {ok,Size,Bt} = erl_bits:set_bit_type(Size, Type0),
+ {Size,erl_bits:as_list(Bt)}.
+
%% constant_bin([{bin_element,_,_,_,_}]) -> binary() | error
%% If the binary construction is truly constant (no variables,
%% no native fields), and does not contain fields whose expansion
@@ -865,7 +991,8 @@ constant_bin(Es) ->
constant_bin_1(Es) ->
verify_suitable_fields(Es),
EmptyBindings = erl_eval:new_bindings(),
- EvalFun = fun({integer,_,I}, B) -> {value,I,B};
+ EvalFun = fun({string,_,S}, B) -> {value,S,B};
+ ({integer,_,I}, B) -> {value,I,B};
({char,_,C}, B) -> {value,C,B};
({float,_,F}, B) -> {value,F,B};
({atom,_,undefined}, B) -> {value,undefined,B}
@@ -886,6 +1013,9 @@ verify_suitable_fields([{bin_element,_,Val,SzTerm,Opts}|Es]) ->
end,
{unit,Unit} = keyfind(unit, 1, Opts),
case {SzTerm,Val} of
+ {{atom,_,undefined},{string,_,_}} ->
+ %% UTF-8/16/32.
+ ok;
{{atom,_,undefined},{char,_,_}} ->
%% UTF-8/16/32.
ok;
@@ -925,6 +1055,31 @@ count_bits(Int) ->
count_bits_1(0, Bits) -> Bits;
count_bits_1(Int, Bits) -> count_bits_1(Int bsr 64, Bits+64).
+bin_expand_strings(Es0) ->
+ foldr(fun ({bin_element,Line,{string,_,S},{integer,_,8},_}, Es) ->
+ bin_expand_string(S, Line, 0, 0) ++ Es;
+ ({bin_element,Line,{string,_,S},Sz,Ts}, Es1) ->
+ foldr(
+ fun (C, Es) ->
+ [{bin_element,Line,{char,Line,C},Sz,Ts}|Es]
+ end, Es1, S);
+ (E, Es) ->
+ [E|Es]
+ end, [], Es0).
+
+bin_expand_string(S, Line, Val, Size) when Size >= 2048 ->
+ Combined = make_combined(Line, Val, Size),
+ [Combined|bin_expand_string(S, Line, 0, 0)];
+bin_expand_string([H|T], Line, Val, Size) ->
+ bin_expand_string(T, Line, (Val bsl 8) bor H, Size+8);
+bin_expand_string([], Line, Val, Size) ->
+ [make_combined(Line, Val, Size)].
+
+make_combined(Line, Val, Size) ->
+ {bin_element,Line,{integer,Line,Val},
+ {integer,Line,Size},
+ [integer,{unit,1},unsigned,big]}.
+
expr_bin_1(Es, St) ->
foldr(fun (E, {Ces,Esp,St0}) ->
{Ce,Ep,St1} = bitstr(E, St0),
@@ -960,17 +1115,19 @@ bitstr({bin_element,_,E0,Size0,[Type,{unit,Unit}|Flags]}, St0) ->
%% fun_tq(Id, [Clauses], Line, State, NameInfo) -> {Fun,[PreExp],State}.
-fun_tq({_,_,Name}=Id, Cs0, L, St0, NameInfo) ->
+fun_tq(Cs0, L, St0, NameInfo) ->
Arity = clause_arity(hd(Cs0)),
{Cs1,Ceps,St1} = clauses(Cs0, St0),
{Args,St2} = new_vars(Arity, St1),
{Ps,St3} = new_vars(Arity, St2), %Need new variables here
Anno = full_anno(L, St3),
+ {Name,St4} = new_fun_name(St3),
Fc = function_clause(Ps, Anno, {Name,Arity}),
+ Id = {0,0,Name},
Fun = #ifun{anno=#a{anno=Anno},
id=[{id,Id}], %We KNOW!
vars=Args,clauses=Cs1,fc=Fc,name=NameInfo},
- {Fun,Ceps,St3}.
+ {Fun,Ceps,St4}.
%% lc_tq(Line, Exp, [Qualifier], Mc, State) -> {LetRec,[PreExp],State}.
%% This TQ from Simon PJ pp 127-138.
@@ -1079,13 +1236,39 @@ bc_tq1(Line, E, [#igen{anno=GAnno,ceps=Ceps,
bc_tq1(Line, E, [#ifilter{}=Filter|Qs], Mc, St) ->
filter_tq(Line, E, Filter, Mc, St, Qs, fun bc_tq1/5);
bc_tq1(_, {bin,Bl,Elements}, [], AccVar, St0) ->
- {E,Pre,St} = expr({bin,Bl,[{bin_element,Bl,
- {var,Bl,AccVar#c_var.name},
- {atom,Bl,all},
- [binary,{unit,1}]}|Elements]}, St0),
+ bc_tq_build(Bl, [], AccVar, Elements, St0);
+bc_tq1(Line, E0, [], AccVar, St0) ->
+ BsFlags = [binary,{unit,1}],
+ BsSize = {atom,Line,all},
+ {E1,Pre0,St1} = safe(E0, St0),
+ case E1 of
+ #c_var{name=VarName} ->
+ Var = {var,Line,VarName},
+ Els = [{bin_element,Line,Var,BsSize,BsFlags}],
+ bc_tq_build(Line, Pre0, AccVar, Els, St1);
+ #c_literal{val=Val} when is_bitstring(Val) ->
+ Bits = bit_size(Val),
+ <<Int0:Bits>> = Val,
+ Int = {integer,Line,Int0},
+ Sz = {integer,Line,Bits},
+ Els = [{bin_element,Line,Int,Sz,[integer,{unit,1},big]}],
+ bc_tq_build(Line, Pre0, AccVar, Els, St1);
+ _ ->
+ %% Any other safe (cons, tuple, literal) is not a
+ %% bitstring. Force the evaluation to fail (and
+ %% generate a warning).
+ Els = [{bin_element,Line,{atom,Line,bad_value},BsSize,BsFlags}],
+ bc_tq_build(Line, Pre0, AccVar, Els, St1)
+ end.
+
+bc_tq_build(Line, Pre0, #c_var{name=AccVar}, Elements0, St0) ->
+ Elements = [{bin_element,Line,{var,Line,AccVar},{atom,Line,all},
+ [binary,{unit,1}]}|Elements0],
+ {E,Pre,St} = expr({bin,Line,Elements}, St0),
#a{anno=A} = Anno0 = get_anno(E),
Anno = Anno0#a{anno=[compiler_generated,single_use|A]},
- {set_anno(E, Anno),Pre,St}.
+ {set_anno(E, Anno),Pre0++Pre,St}.
+
%% filter_tq(Line, Expr, Filter, Mc, State, [Qualifier], TqFun) ->
%% {Case,[PreExpr],State}.
@@ -1270,8 +1453,9 @@ list_gen_pattern(P0, Line, St) ->
%%% the result binary in a binary comprehension.
%%%
-bc_initial_size(E, Q, St0) ->
+bc_initial_size(E0, Q, St0) ->
try
+ E = bin_bin_element(E0),
{ElemSzExpr,ElemSzPre,EVs,St1} = bc_elem_size(E, St0),
{V,St2} = new_var(St1),
{GenSzExpr,GenSzPre,St3} = bc_gen_size(Q, EVs, St2),
@@ -1306,13 +1490,19 @@ bc_elem_size({bin,_,El}, St0) ->
Vs = [V || {_,#c_var{name=V}} <- Vars0],
{E,Pre,St} = bc_mul_pairs(F, #c_literal{val=Bits}, [], St0),
{E,Pre,Vs,St}
- end.
+ end;
+bc_elem_size(_, _) ->
+ throw(impossible).
-bc_elem_size_1([{bin_element,_,_,{integer,_,N},Flags}|Es], Bits, Vars) ->
- {unit,U} = keyfind(unit, 1, Flags),
+bc_elem_size_1([{bin_element,_,{string,_,String},{integer,_,N},_}=El|Es],
+ Bits, Vars) ->
+ U = get_unit(El),
+ bc_elem_size_1(Es, Bits+U*N*length(String), Vars);
+bc_elem_size_1([{bin_element,_,_,{integer,_,N},_}=El|Es], Bits, Vars) ->
+ U = get_unit(El),
bc_elem_size_1(Es, Bits+U*N, Vars);
-bc_elem_size_1([{bin_element,_,_,{var,_,Var},Flags}|Es], Bits, Vars) ->
- {unit,U} = keyfind(unit, 1, Flags),
+bc_elem_size_1([{bin_element,_,_,{var,_,Var},_}=El|Es], Bits, Vars) ->
+ U = get_unit(El),
bc_elem_size_1(Es, Bits, [{U,#c_var{name=Var}}|Vars]);
bc_elem_size_1([_|_], _, _) ->
throw(impossible);
@@ -1369,7 +1559,9 @@ bc_gen_size_1([{generate,L,El,Gen}|Qs], EVs, E0, Pre0, St0) ->
{E,Pre,St} = bc_gen_size_mul(E0, #c_literal{val=Len}, Pre0, St0),
bc_gen_size_1(Qs, EVs, E, Pre, St)
end;
-bc_gen_size_1([{b_generate,_,El,Gen}|Qs], EVs, E0, Pre0, St0) ->
+bc_gen_size_1([{b_generate,_,El0,Gen0}|Qs], EVs, E0, Pre0, St0) ->
+ El = bin_bin_element(El0),
+ Gen = bin_bin_element(Gen0),
bc_verify_non_filtering(El, EVs),
{MatchSzExpr,Pre1,_,St1} = bc_elem_size(El, St0),
Pre2 = reverse(Pre1, Pre0),
@@ -1385,6 +1577,10 @@ bc_gen_size_1([], _, E, Pre, St) ->
bc_gen_size_1(_, _, _, _, _) ->
throw(impossible).
+bin_bin_element({bin,L,El}) ->
+ {bin,L,[bin_element(E) || E <- El]};
+bin_bin_element(Other) -> Other.
+
bc_gen_bit_size({var,L,V}, Pre0, St0) ->
Lanno = lineno_anno(L, St0),
{SzVar,St} = new_var(St0),
@@ -1427,8 +1623,11 @@ bc_list_length(_, _) ->
bc_bin_size({bin,_,Els}) ->
bc_bin_size_1(Els, 0).
-bc_bin_size_1([{bin_element,_,_,{integer,_,Sz},Flags}|Els], N) ->
- {unit,U} = keyfind(unit, 1, Flags),
+bc_bin_size_1([{bin_element,_,{string,_,String},{integer,_,Sz},_}=El|Els], N) ->
+ U = get_unit(El),
+ bc_bin_size_1(Els, N+U*Sz*length(String));
+bc_bin_size_1([{bin_element,_,_,{integer,_,Sz},_}=El|Els], N) ->
+ U = get_unit(El),
bc_bin_size_1(Els, N+U*Sz);
bc_bin_size_1([], N) -> N;
bc_bin_size_1(_, _) -> throw(impossible).
@@ -1463,11 +1662,24 @@ bc_bsr(E1, E2) ->
name=#c_literal{val='bsr'},
args=[E1,E2]}.
-%% is_guard_test(Expression) -> true | false.
-%% Test if a general expression is a guard test. Use erl_lint here
-%% as it now allows sys_pre_expand transformed source.
+get_unit({bin_element,_,_,_,Flags}) ->
+ {unit,U} = keyfind(unit, 1, Flags),
+ U.
-is_guard_test(E) -> erl_lint:is_guard_test(E).
+%% is_guard_test(Expression) -> true | false.
+%% Test if a general expression is a guard test.
+%%
+%% Note that a local function overrides a BIF with the same name.
+%% For example, if there is a local function named is_list/1,
+%% any unqualified call to is_list/1 will be to the local function.
+%% The guard function must be explicitly called as erlang:is_list/1.
+
+is_guard_test(E) ->
+ %% erl_expand_records has added a module prefix to any call
+ %% to a BIF or imported function. Any call without a module
+ %% prefix that remains must therefore be to a local function.
+ IsOverridden = fun({_,_}) -> true end,
+ erl_lint:is_guard_test(E, [], IsOverridden).
%% novars(Expr, State) -> {Novars,[PreExpr],State}.
%% Generate a novars expression, basically a call or a safe. At this
@@ -1610,7 +1822,18 @@ pattern({bin,L,Ps}, St) ->
pattern({match,_,P1,P2}, St) ->
{Cp1,Eps1,St1} = pattern(P1,St),
{Cp2,Eps2,St2} = pattern(P2,St1),
- {pat_alias(Cp1,Cp2),Eps1++Eps2,St2}.
+ {pat_alias(Cp1,Cp2),Eps1++Eps2,St2};
+%% Evaluate compile-time expressions.
+pattern({op,_,'++',{nil,_},R}, St) ->
+ pattern(R, St);
+pattern({op,_,'++',{cons,Li,H,T},R}, St) ->
+ pattern({cons,Li,H,{op,Li,'++',T,R}}, St);
+pattern({op,_,'++',{string,Li,L},R}, St) ->
+ pattern(string_to_conses(Li, L, R), St);
+pattern({op,_Line,_Op,_A}=Op, St) ->
+ pattern(erl_eval:partial_eval(Op), St);
+pattern({op,_Line,_Op,_L,_R}=Op, St) ->
+ pattern(erl_eval:partial_eval(Op), St).
%% pattern_map_pairs([MapFieldExact],State) -> [#c_map_pairs{}]
pattern_map_pairs(Ps, St) ->
@@ -1650,16 +1873,29 @@ pat_alias_map_pairs_1([]) -> [].
%% pat_bin([BinElement], State) -> [BinSeg].
-pat_bin(Ps, St) -> [pat_segment(P, St) || P <- Ps].
-
-pat_segment({bin_element,_,Val,Size,[Type,{unit,Unit}|Flags]}, St) ->
- {Pval,[],St1} = pattern(Val,St),
- {Psize,[],_St2} = pattern(Size,St1),
- #c_bitstr{val=Pval,size=Psize,
+pat_bin(Ps, St) -> [pat_segment(P, St) || P <- bin_expand_strings(Ps)].
+
+pat_segment({bin_element,L,Val,Size0,Type0}, St) ->
+ {Size,Type1} = make_bit_type(L, Size0, Type0),
+ [Type,{unit,Unit}|Flags] = Type1,
+ Anno = lineno_anno(L, St),
+ {Pval0,[],St1} = pattern(Val, St),
+ Pval = coerce_to_float(Pval0, Type0),
+ {Psize,[],_St2} = pattern(Size, St1),
+ #c_bitstr{anno=Anno,
+ val=Pval,size=Psize,
unit=#c_literal{val=Unit},
type=#c_literal{val=Type},
flags=#c_literal{val=Flags}}.
+coerce_to_float(#c_literal{val=Int}=E, [float|_]) when is_integer(Int) ->
+ try
+ E#c_literal{val=float(Int)}
+ catch
+ error:badarg -> E
+ end;
+coerce_to_float(E, _) -> E.
+
%% pat_alias(CorePat, CorePat) -> AliasPat.
%% Normalise aliases. Trap bad aliases by throwing 'nomatch'.
@@ -1729,11 +1965,18 @@ pattern_list([P0|Ps0], St0) ->
pattern_list([], St) ->
{[],[],St}.
+string_to_conses(Line, Cs, Tail) ->
+ foldr(fun (C, T) -> {cons,Line,{char,Line,C},T} end, Tail, Cs).
%% make_vars([Name]) -> [{Var,Name}].
make_vars(Vs) -> [ #c_var{name=V} || V <- Vs ].
+new_fun_name(#core{function={F,A},fcount=I}=St) ->
+ Name = "-" ++ atom_to_list(F) ++ "/" ++ integer_to_list(A)
+ ++ "-fun-" ++ integer_to_list(I) ++ "-",
+ {list_to_atom(Name),St#core{fcount=I+1}}.
+
%% new_fun_name(Type, State) -> {FunName,State}.
new_fun_name(Type, #core{fcount=C}=St) ->
@@ -1742,7 +1985,7 @@ new_fun_name(Type, #core{fcount=C}=St) ->
%% new_var_name(State) -> {VarName,State}.
new_var_name(#core{vcount=C}=St) ->
- {list_to_atom("cor" ++ integer_to_list(C)),St#core{vcount=C + 1}}.
+ {list_to_atom("@c" ++ integer_to_list(C)),St#core{vcount=C + 1}}.
%% new_var(State) -> {{var,Name},State}.
%% new_var(LineAnno, State) -> {{var,Name},State}.
@@ -1852,27 +2095,22 @@ uguard(Pg, Gs0, Ks, St0) ->
%% uexprs([Kexpr], [KnownVar], State) -> {[Kexpr],State}.
uexprs([#imatch{anno=A,pat=P0,arg=Arg,fc=Fc}|Les], Ks, St0) ->
- %% Optimise for simple set of unbound variable.
- case upattern(P0, Ks, St0) of
- {#c_var{},[],_Pvs,_Pus,_} ->
- %% Throw our work away and just set to iset.
+ case upat_is_new_var(P0, Ks) of
+ true ->
+ %% Assignment to a new variable.
uexprs([#iset{var=P0,arg=Arg}|Les], Ks, St0);
- _Other ->
- %% Throw our work away and set to icase.
- if
- Les =:= [] ->
- %% Need to explicitly return match "value", make
- %% safe for efficiency.
- {La0,Lps,St1} = force_safe(Arg, St0),
- La = mark_compiler_generated(La0),
- Mc = #iclause{anno=A,pats=[P0],guard=[],body=[La]},
- uexprs(Lps ++ [#icase{anno=A,
- args=[La0],clauses=[Mc],fc=Fc}], Ks, St1);
- true ->
- Mc = #iclause{anno=A,pats=[P0],guard=[],body=Les},
- uexprs([#icase{anno=A,args=[Arg],
- clauses=[Mc],fc=Fc}], Ks, St0)
- end
+ false when Les =:= [] ->
+ %% Need to explicitly return match "value", make
+ %% safe for efficiency.
+ {La0,Lps,St1} = force_safe(Arg, St0),
+ La = mark_compiler_generated(La0),
+ Mc = #iclause{anno=A,pats=[P0],guard=[],body=[La]},
+ uexprs(Lps ++ [#icase{anno=A,
+ args=[La0],clauses=[Mc],fc=Fc}], Ks, St1);
+ false ->
+ Mc = #iclause{anno=A,pats=[P0],guard=[],body=Les},
+ uexprs([#icase{anno=A,args=[Arg],
+ clauses=[Mc],fc=Fc}], Ks, St0)
end;
uexprs([Le0|Les0], Ks, St0) ->
{Le1,St1} = uexpr(Le0, Ks, St0),
@@ -1880,6 +2118,15 @@ uexprs([Le0|Les0], Ks, St0) ->
{[Le1|Les1],St2};
uexprs([], _, St) -> {[],St}.
+%% upat_is_new_var(Pattern, [KnownVar]) -> true|false.
+%% Test whether the pattern is a single, previously unknown
+%% variable.
+
+upat_is_new_var(#c_var{name=V}, Ks) ->
+ not is_element(V, Ks);
+upat_is_new_var(_, _) ->
+ false.
+
%% Mark a "safe" as compiler-generated.
mark_compiler_generated(#c_cons{anno=A,hd=H,tl=T}) ->
ann_c_cons([compiler_generated|A], mark_compiler_generated(H),
@@ -2010,7 +2257,8 @@ upattern(#c_var{name=V}=Var, Ks, St0) ->
true ->
{N,St1} = new_var_name(St0),
New = #c_var{name=N},
- Test = #icall{anno=#a{us=add_element(N, [V])},
+ LA = get_lineno_anno(Var),
+ Test = #icall{anno=#a{anno=LA,us=add_element(N, [V])},
module=#c_literal{val=erlang},
name=#c_literal{val='=:='},
args=[New,Var]},
@@ -2382,7 +2630,11 @@ format_error(nomatch) ->
format_error(bad_binary) ->
"binary construction will fail because of a type mismatch";
format_error(badmap) ->
- "map construction will fail because of a type mismatch".
+ "map construction will fail because of a type mismatch";
+format_error({map_key_repeated,Key}) when is_atom(Key) ->
+ io_lib:format("key '~w' will be overridden in expression", [Key]);
+format_error({map_key_repeated,Key}) ->
+ io_lib:format("key ~p will be overridden in expression", [Key]).
add_warning(Anno, Term, #core{ws=Ws,file=[{file,File}]}=St) ->
case erl_anno:generated(Anno) of
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index 7ee564683b..1fc05109c5 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. 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.
@@ -82,7 +82,7 @@
-export([module/2,format_error/1]).
-import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,splitwith/2,member/2,
- keymember/3,keyfind/3,partition/2,droplast/1,last/1]).
+ keymember/3,keyfind/3,partition/2,droplast/1,last/1,sort/1]).
-import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]).
-import(cerl, [c_tuple/1]).
@@ -117,7 +117,7 @@ copy_anno(Kdst, Ksrc) ->
fcount=0, %Fun counter
ds=cerl_sets:new() :: cerl_sets:set(), %Defined variables
funs=[], %Fun functions
- free=[], %Free variables
+ free=#{}, %Free variables
ws=[] :: [warning()], %Warnings.
guard_refc=0}). %> 0 means in guard
@@ -143,11 +143,17 @@ attributes([]) -> [].
include_attribute(type) -> false;
include_attribute(spec) -> false;
+include_attribute(callback) -> false;
include_attribute(opaque) -> false;
include_attribute(export_type) -> false;
+include_attribute(record) -> false;
+include_attribute(optional_callbacks) -> false;
+include_attribute(file) -> false;
+include_attribute(compile) -> false;
include_attribute(_) -> true.
function({#c_var{name={F,Arity}=FA},Body}, St0) ->
+ %%io:format("~w/~w~n", [F,Arity]),
try
St1 = St0#kern{func=FA,ff=undefined,vcount=0,fcount=0,ds=cerl_sets:new()},
{#ifun{anno=Ab,vars=Kvs,body=B0},[],St2} = expr(Body, new_sub(), St1),
@@ -187,9 +193,479 @@ body(Ce, Sub, St0) ->
guard(G0, Sub, St0) ->
{G1,St1} = wrap_guard(G0, St0),
{Ge0,Pre,St2} = expr(G1, Sub, St1),
- {Ge,St} = gexpr_test(Ge0, St2),
+ {Ge1,St3} = gexpr_test(Ge0, St2),
+ {Ge,St} = guard_opt(Ge1, St3),
{pre_seq(Pre, Ge),St}.
+%% guard_opt(Kexpr, State) -> {Kexpr,State}.
+%% Optimize the Kexpr for the guard. Instead of evaluating a boolean
+%% expression comparing it to 'true' in a final #k_test{},
+%% replace BIF calls with #k_test{} in the expression.
+%%
+%% As an example, take the guard:
+%%
+%% when is_integer(V0), is_atom(V1) ->
+%%
+%% The unoptimized Kexpr translated to pseudo BEAM assembly
+%% code would look like:
+%%
+%% bif is_integer V0 => Bool0
+%% bif is_atom V1 => Bool1
+%% bif and Bool0 Bool1 => Bool
+%% test Bool =:= true else goto Fail
+%% ...
+%% Fail:
+%% ...
+%%
+%% The optimized code would look like:
+%%
+%% test is_integer V0 else goto Fail
+%% test is_atom V1 else goto Fail
+%% ...
+%% Fail:
+%% ...
+%%
+%% An 'or' operation is only slightly more complicated:
+%%
+%% test is_integer V0 else goto NotFailedYet
+%% goto Success
+%%
+%% NotFailedYet:
+%% test is_atom V1 else goto Fail
+%%
+%% Success:
+%% ...
+%% Fail:
+%% ...
+
+guard_opt(G, St0) ->
+ {Root,Forest0,St1} = make_forest(G, St0),
+ {Exprs,Forest,St} = rewrite_bool(Root, Forest0, false, St1),
+ E = forest_pre_seq(Exprs, Forest),
+ {G#k_try{arg=E},St}.
+
+%% rewrite_bool(Kexpr, Forest, Inv, St) -> {[Kexpr],Forest,St}.
+%% Rewrite Kexpr to use #k_test{} operations instead of comparison
+%% and type test BIFs.
+%%
+%% If Kexpr is a #k_test{} operation, the call will always
+%% succeed. Otherwise, a 'not_possible' exception will be
+%% thrown if Kexpr cannot be rewritten.
+
+rewrite_bool(#k_test{op=#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val='=:='}},
+ args=[#k_var{}=V,#k_atom{val=true}]}=Test, Forest0, Inv, St0) ->
+ try rewrite_bool_var(V, Forest0, Inv, St0) of
+ {_,_,_}=Res ->
+ Res
+ catch
+ throw:not_possible ->
+ {[Test],Forest0,St0}
+ end;
+rewrite_bool(#k_test{op=#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val='=:='}},
+ args=[#k_var{}=V,#k_atom{val=false}]}=Test, Forest0, Inv, St0) ->
+ try rewrite_bool_var(V, Forest0, not Inv, St0) of
+ {_,_,_}=Res ->
+ Res
+ catch
+ throw:not_possible ->
+ {[Test],Forest0,St0}
+ end;
+rewrite_bool(#k_test{op=#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val='=:='}},
+ args=[#k_atom{val=V1},#k_atom{val=V2}]}, Forest0, false, St0) ->
+ case V1 =:= V2 of
+ true ->
+ {[make_test(is_boolean, [#k_atom{val=true}])],Forest0,St0};
+ false ->
+ {[make_failing_test()],Forest0,St0}
+ end;
+rewrite_bool(#k_test{}=Test, Forest, false, St) ->
+ {[Test],Forest,St};
+rewrite_bool(#k_try{vars=[#k_var{name=X}],body=#k_var{name=X},
+ handler=#k_atom{val=false},ret=[]}=Prot,
+ Forest0, Inv, St0) ->
+ {Root,Forest1,St1} = make_forest(Prot, Forest0, St0),
+ {Exprs,Forest2,St} = rewrite_bool(Root, Forest1, Inv, St1),
+ InnerForest = maps:without(maps:keys(Forest0), Forest2),
+ Forest = maps:without(maps:keys(InnerForest), Forest2),
+ E = forest_pre_seq(Exprs, InnerForest),
+ {[Prot#k_try{arg=E}],Forest,St};
+rewrite_bool(#k_match{body=Body,ret=[]}, Forest, Inv, St) ->
+ rewrite_match(Body, Forest, Inv, St);
+rewrite_bool(Other, Forest, Inv, St) ->
+ case extract_bif(Other) of
+ {Name,Args} ->
+ rewrite_bif(Name, Args, Forest, Inv, St);
+ error ->
+ throw(not_possible)
+ end.
+
+%% rewrite_bool_var(Var, Forest, Inv, St) -> {[Kexpr],Forest,St}.
+%% Rewrite the boolean expression whose key in Forest is
+%% given by Var. Throw a 'not_possible' expression if something
+%% prevents the rewriting.
+
+rewrite_bool_var(Arg, Forest0, Inv, St) ->
+ {Expr,Forest} = forest_take_expr(Arg, Forest0),
+ rewrite_bool(Expr, Forest, Inv, St).
+
+%% rewrite_bool_args([Kexpr], Forest, Inv, St) -> {[[Kexpr]],Forest,St}.
+%% Rewrite each Kexpr in the list. The input Kexpr should be variables
+%% or boolean values. Throw a 'not_possible' expression if something
+%% prevents the rewriting.
+%%
+%% This function is suitable for handling the arguments for both
+%% 'and' and 'or'.
+
+rewrite_bool_args([#k_atom{val=B}=A|Vs], Forest0, false=Inv, St0) when is_boolean(B) ->
+ {Tail,Forest1,St1} = rewrite_bool_args(Vs, Forest0, Inv, St0),
+ Bif = make_bif('=:=', [A,#k_atom{val=true}]),
+ {Exprs,Forest,St} = rewrite_bool(Bif, Forest1, Inv, St1),
+ {[Exprs|Tail],Forest,St};
+rewrite_bool_args([#k_var{}=Var|Vs], Forest0, false=Inv, St0) ->
+ {Tail,Forest1,St1} = rewrite_bool_args(Vs, Forest0, Inv, St0),
+ {Exprs,Forest,St} =
+ case is_bool_expr(Var, Forest0) of
+ true ->
+ rewrite_bool_var(Var, Forest1, Inv, St1);
+ false ->
+ Bif = make_bif('=:=', [Var,#k_atom{val=true}]),
+ rewrite_bool(Bif, Forest1, Inv, St1)
+ end,
+ {[Exprs|Tail],Forest,St};
+rewrite_bool_args([_|_], _Forest, _Inv, _St) ->
+ throw(not_possible);
+rewrite_bool_args([], Forest, _Inv, St) ->
+ {[],Forest,St}.
+
+%% rewrite_bif(Name, [Kexpr], Forest, Inv, St) -> {[Kexpr],Forest,St}.
+%% Rewrite a BIF. Throw a 'not_possible' expression if something
+%% prevents the rewriting.
+
+rewrite_bif('or', Args, Forest, true, St) ->
+ rewrite_not_args('and', Args, Forest, St);
+rewrite_bif('and', Args, Forest, true, St) ->
+ rewrite_not_args('or', Args, Forest, St);
+rewrite_bif('and', [#k_atom{val=Val},Arg], Forest0, Inv, St0) ->
+ false = Inv, %Assertion.
+ case Val of
+ true ->
+ %% The result only depends on Arg.
+ rewrite_bool_var(Arg, Forest0, Inv, St0);
+ _ ->
+ %% Will fail. There is no need to evalute the expression
+ %% represented by Arg. Take it out from the forest and
+ %% discard the expression.
+ Failing = make_failing_test(),
+ try rewrite_bool_var(Arg, Forest0, Inv, St0) of
+ {_,Forest,St} ->
+ {[Failing],Forest,St}
+ catch
+ throw:not_possible ->
+ try forest_take_expr(Arg, Forest0) of
+ {_,Forest} ->
+ {[Failing],Forest,St0}
+ catch
+ throw:not_possible ->
+ %% Arg is probably a variable bound in an
+ %% outer scope.
+ {[Failing],Forest0,St0}
+ end
+ end
+ end;
+rewrite_bif('and', [Arg,#k_atom{}=Atom], Forest, Inv, St) ->
+ false = Inv, %Assertion.
+ rewrite_bif('and', [Atom,Arg], Forest, Inv, St);
+rewrite_bif('and', Args, Forest0, Inv, St0) ->
+ false = Inv, %Assertion.
+ {[Es1,Es2],Forest,St} = rewrite_bool_args(Args, Forest0, Inv, St0),
+ {Es1 ++ Es2,Forest,St};
+rewrite_bif('or', Args, Forest0, Inv, St0) ->
+ false = Inv, %Assertion.
+ {[First,Then],Forest,St} = rewrite_bool_args(Args, Forest0, Inv, St0),
+ Alt = make_alt(First, Then),
+ {[Alt],Forest,St};
+rewrite_bif('xor', [_,_], _Forest, _Inv, _St) ->
+ %% Rewriting 'xor' is not practical. Fortunately, 'xor' is
+ %% almost never used in practice.
+ throw(not_possible);
+rewrite_bif('not', [Arg], Forest0, Inv, St) ->
+ {Expr,Forest} = forest_take_expr(Arg, Forest0),
+ rewrite_bool(Expr, Forest, not Inv, St);
+rewrite_bif(Op, Args, Forest, Inv, St) ->
+ case is_test(Op, Args) of
+ true ->
+ rewrite_bool(make_test(Op, Args, Inv), Forest, false, St);
+ false ->
+ throw(not_possible)
+ end.
+
+rewrite_not_args(Op, [A0,B0], Forest0, St0) ->
+ {A,Forest1,St1} = rewrite_not_args_1(A0, Forest0, St0),
+ {B,Forest2,St2} = rewrite_not_args_1(B0, Forest1, St1),
+ rewrite_bif(Op, [A,B], Forest2, false, St2).
+
+rewrite_not_args_1(Arg, Forest, St) ->
+ Not = make_bif('not', [Arg]),
+ forest_add_expr(Not, Forest, St).
+
+%% rewrite_match(Kvar, TypeClause, Forest, Inv, St) ->
+%% {[Kexpr],Forest,St}.
+%% Try to rewrite a #k_match{} originating from an 'andalso' or an 'orelse'.
+
+rewrite_match(#k_alt{first=First,then=Then}, Forest, Inv, St) ->
+ case {First,Then} of
+ {#k_select{var=#k_var{name=V}=Var,types=[TypeClause]},#k_var{name=V}} ->
+ rewrite_match_1(Var, TypeClause, Forest, Inv, St);
+ {_,_} ->
+ throw(not_possible)
+ end.
+
+rewrite_match_1(Var, #k_type_clause{values=Cs0}, Forest0, Inv, St0) ->
+ Cs = sort([{Val,B} || #k_val_clause{val=#k_atom{val=Val},body=B} <- Cs0]),
+ case Cs of
+ [{false,False},{true,True}] ->
+ rewrite_match_2(Var, False, True, Forest0, Inv, St0);
+ _ ->
+ throw(not_possible)
+ end.
+
+rewrite_match_2(Var, False, #k_atom{val=true}, Forest0, Inv, St0) ->
+ %% Originates from an 'orelse'.
+ case False of
+ #k_atom{val=NotBool} when not is_boolean(NotBool) ->
+ rewrite_bool(Var, Forest0, Inv, St0);
+ _ ->
+ {CodeVar,Forest1,St1} = add_protected_expr(False, Forest0, St0),
+ rewrite_bif('or', [Var,CodeVar], Forest1, Inv, St1)
+ end;
+rewrite_match_2(Var, #k_atom{val=false}, True, Forest0, Inv, St0) ->
+ %% Originates from an 'andalso'.
+ {CodeVar,Forest1,St1} = add_protected_expr(True, Forest0, St0),
+ rewrite_bif('and', [Var,CodeVar], Forest1, Inv, St1);
+rewrite_match_2(_V, _, _, _Forest, _Inv, _St) ->
+ throw(not_possible).
+
+%% is_bool_expr(#k_var{}, Forest) -> true|false.
+%% Return true if the variable refers to a boolean expression
+%% that does not need an explicit '=:= true' test.
+
+is_bool_expr(V, Forest) ->
+ case forest_peek_expr(V, Forest) of
+ error ->
+ %% Defined outside of the guard. We can't know.
+ false;
+ Expr ->
+ case extract_bif(Expr) of
+ {Name,Args} ->
+ is_test(Name, Args) orelse
+ erl_internal:bool_op(Name, length(Args));
+ error ->
+ %% Not a BIF. Should be possible to rewrite
+ %% to a boolean. Definitely does not need
+ %% a '=:= true' test.
+ true
+ end
+ end.
+
+make_bif(Op, Args) ->
+ #k_bif{op=#k_remote{mod=#k_atom{val=erlang},
+ name=#k_atom{val=Op},
+ arity=length(Args)},
+ args=Args}.
+
+extract_bif(#k_bif{op=#k_remote{mod=#k_atom{val=erlang},
+ name=#k_atom{val=Name}},
+ args=Args}) ->
+ {Name,Args};
+extract_bif(_) ->
+ error.
+
+%% make_alt(First, Then) -> KMatch.
+%% Make a #k_alt{} within a #k_match{} to implement
+%% 'or' or 'orelse'.
+
+make_alt(First0, Then0) ->
+ First1 = pre_seq(droplast(First0), last(First0)),
+ Then1 = pre_seq(droplast(Then0), last(Then0)),
+ First2 = make_protected(First1),
+ Then2 = make_protected(Then1),
+ Body = #k_atom{val=ignored},
+ First3 = #k_guard_clause{guard=First2,body=Body},
+ Then3 = #k_guard_clause{guard=Then2,body=Body},
+ First = #k_guard{clauses=[First3]},
+ Then = #k_guard{clauses=[Then3]},
+ Alt = #k_alt{first=First,then=Then},
+ #k_match{vars=[],body=Alt}.
+
+add_protected_expr(#k_atom{}=Atom, Forest, St) ->
+ {Atom,Forest,St};
+add_protected_expr(#k_var{}=Var, Forest, St) ->
+ {Var,Forest,St};
+add_protected_expr(E0, Forest, St) ->
+ E = make_protected(E0),
+ forest_add_expr(E, Forest, St).
+
+make_protected(#k_try{}=Try) ->
+ Try;
+make_protected(B) ->
+ #k_try{arg=B,vars=[#k_var{name=''}],body=#k_var{name=''},
+ handler=#k_atom{val=false}}.
+
+make_failing_test() ->
+ make_test(is_boolean, [#k_atom{val=fail}]).
+
+make_test(Op, Args) ->
+ make_test(Op, Args, false).
+
+make_test(Op, Args, Inv) ->
+ Remote = #k_remote{mod=#k_atom{val=erlang},
+ name=#k_atom{val=Op},
+ arity=length(Args)},
+ #k_test{op=Remote,args=Args,inverted=Inv}.
+
+is_test(Op, Args) ->
+ A = length(Args),
+ erl_internal:new_type_test(Op, A) orelse erl_internal:comp_op(Op, A).
+
+%% make_forest(Kexpr, St) -> {RootKexpr,Forest,St}.
+%% Build a forest out of Kexpr. RootKexpr is the final expression
+%% nested inside Kexpr.
+
+make_forest(G, St) ->
+ make_forest_1(G, #{}, 0, St).
+
+%% make_forest(Kexpr, St) -> {RootKexpr,Forest,St}.
+%% Add to Forest from Kexpr. RootKexpr is the final expression
+%% nested inside Kexpr.
+
+make_forest(G, Forest0, St) ->
+ N = forest_next_index(Forest0),
+ make_forest_1(G, Forest0, N, St).
+
+make_forest_1(#k_try{arg=B}, Forest, I, St) ->
+ make_forest_1(B, Forest, I, St);
+make_forest_1(#iset{vars=[]}=Iset0, Forest, I, St0) ->
+ {UnrefVar,St} = new_var(St0),
+ Iset = Iset0#iset{vars=[UnrefVar]},
+ make_forest_1(Iset, Forest, I, St);
+make_forest_1(#iset{vars=[#k_var{name=V}],arg=Arg,body=B}, Forest0, I, St) ->
+ Forest = Forest0#{V => {I,Arg}, {untaken,V} => true},
+ make_forest_1(B, Forest, I+1, St);
+make_forest_1(Innermost, Forest, _I, St) ->
+ {Innermost,Forest,St}.
+
+%% forest_take_expr(Kexpr, Forest) -> {Expr,Forest}.
+%% If Kexpr is a variable, take out the expression corresponding
+%% to variable in Forest. Expressions that have been taken out
+%% of the forest will not be included the Kexpr returned
+%% by forest_pre_seq/2.
+%%
+%% Throw a 'not_possible' exception if Kexpr is not a variable or
+%% if the name of the variable is not a key in Forest.
+
+forest_take_expr(#k_var{name=V}, Forest0) ->
+ %% v3_core currently always generates guard expressions that can
+ %% be represented as a tree. Other code generators (such as LFE)
+ %% could generate guard expressions that can only be represented
+ %% as a DAG (i.e. some nodes are referenced more than once). To
+ %% handle DAGs, we must never remove a node from the forest, but
+ %% just remove the {untaken,V} marker. That will effectively convert
+ %% the DAG to a tree by duplicating the shared nodes and their
+ %% descendants.
+
+ case maps:find(V, Forest0) of
+ {ok,{_,Expr}} ->
+ Forest = maps:remove({untaken,V}, Forest0),
+ {Expr,Forest};
+ error ->
+ throw(not_possible)
+ end;
+forest_take_expr(_, _) ->
+ throw(not_possible).
+
+%% forest_peek_expr(Kvar, Forest) -> Kexpr | error.
+%% Return the expression corresponding to Kvar in Forest or
+%% return 'error' if there is a corresponding expression.
+
+forest_peek_expr(#k_var{name=V}, Forest0) ->
+ case maps:find(V, Forest0) of
+ {ok,{_,Expr}} -> Expr;
+ error -> error
+ end.
+
+%% forest_add_expr(Kexpr, Forest, St) -> {Kvar,Forest,St}.
+%% Add a new expression to Forest.
+
+forest_add_expr(Expr, Forest0, St0) ->
+ {#k_var{name=V}=Var,St} = new_var(St0),
+ N = forest_next_index(Forest0),
+ Forest = Forest0#{V => {N,Expr}},
+ {Var,Forest,St}.
+
+forest_next_index(Forest) ->
+ 1 + lists:max([N || {N,_} <- maps:values(Forest),
+ is_integer(N)] ++ [0]).
+
+%% forest_pre_seq([Kexpr], Forest) -> Kexpr.
+%% Package the list of Kexprs into a nested Kexpr, prepending all
+%% expressions in Forest that have not been taken out using
+%% forest_take_expr/2.
+
+forest_pre_seq(Exprs, Forest) ->
+ Es0 = [#k_var{name=V} || {untaken,V} <- maps:keys(Forest)],
+ Es = Es0 ++ Exprs,
+ Vs = extract_all_vars(Es, Forest, []),
+ Pre0 = sort([{maps:get(V, Forest),V} || V <- Vs]),
+ Pre = [#iset{vars=[#k_var{name=V}],arg=A} ||
+ {{_,A},V} <- Pre0],
+ pre_seq(Pre++droplast(Exprs), last(Exprs)).
+
+extract_all_vars(Es, Forest, Acc0) ->
+ case extract_var_list(Es) of
+ [] ->
+ Acc0;
+ [_|_]=Vs0 ->
+ Vs = [V || V <- Vs0, maps:is_key(V, Forest)],
+ NewVs = ordsets:subtract(Vs, Acc0),
+ NewEs = [begin
+ {_,E} = maps:get(V, Forest),
+ E
+ end || V <- NewVs],
+ Acc = union(NewVs, Acc0),
+ extract_all_vars(NewEs, Forest, Acc)
+ end.
+
+extract_vars(#iset{arg=A,body=B}) ->
+ union(extract_vars(A), extract_vars(B));
+extract_vars(#k_bif{args=Args}) ->
+ ordsets:from_list(lit_list_vars(Args));
+extract_vars(#k_call{}) ->
+ [];
+extract_vars(#k_test{args=Args}) ->
+ ordsets:from_list(lit_list_vars(Args));
+extract_vars(#k_match{body=Body}) ->
+ extract_vars(Body);
+extract_vars(#k_alt{first=First,then=Then}) ->
+ union(extract_vars(First), extract_vars(Then));
+extract_vars(#k_guard{clauses=Cs}) ->
+ extract_var_list(Cs);
+extract_vars(#k_guard_clause{guard=G}) ->
+ extract_vars(G);
+extract_vars(#k_select{var=Var,types=Types}) ->
+ union(ordsets:from_list(lit_vars(Var)),
+ extract_var_list(Types));
+extract_vars(#k_type_clause{values=Values}) ->
+ extract_var_list(Values);
+extract_vars(#k_val_clause{body=Body}) ->
+ extract_vars(Body);
+extract_vars(#k_try{arg=Arg}) ->
+ extract_vars(Arg);
+extract_vars(Lit) ->
+ ordsets:from_list(lit_vars(Lit)).
+
+extract_var_list(L) ->
+ union([extract_vars(E) || E <- L]).
+
%% Wrap the entire guard in a try/catch if needed.
wrap_guard(#c_try{}=Try, St) -> {Try,St};
@@ -239,7 +715,7 @@ gexpr_test_add(Ke, St0) ->
expr(#c_var{anno=A,name={_Name,Arity}}=Fname, Sub, St) ->
%% A local in an expression.
%% For now, these are wrapped into a fun by reverse
- %% etha-conversion, but really, there should be exactly one
+ %% eta-conversion, but really, there should be exactly one
%% such "lambda function" for each escaping local name,
%% instead of one for each occurrence as done now.
Vs = [#c_var{name=list_to_atom("V" ++ integer_to_list(V))} ||
@@ -399,7 +875,7 @@ expr(#c_call{anno=A,module=M0,name=F0,args=Cargs}, Sub, St0) ->
Call = #c_call{anno=A,
module=#c_literal{val=erlang},
name=#c_literal{val=apply},
- args=[M0,F0,make_list(Cargs)]},
+ args=[M0,F0,cerl:make_list(Cargs)]},
expr(Call, Sub, St1);
_ ->
{[M1,F1|Kargs],Ap,St} = atomic_list([M0,F0|Cargs], Sub, St1),
@@ -494,7 +970,7 @@ translate_match_fail_1(Anno, As, Sub, #kern{ff=FF}) ->
end.
translate_fc(Args) ->
- [#c_literal{val=function_clause},make_list(Args)].
+ [#c_literal{val=function_clause},cerl:make_list(Args)].
expr_map(A,Var0,Ces,Sub,St0) ->
{Var,Mps,St1} = expr(Var0, Sub, St0),
@@ -837,23 +1313,26 @@ get_vsub(V, Vsub) ->
set_vsub(V, S, Vsub) ->
orddict:store(V, S, Vsub).
-subst_vsub(Key, New, [{K,Key}|Dict]) ->
+subst_vsub(Key, New, Vsub) ->
+ orddict:from_list(subst_vsub_1(Key, New, Vsub)).
+
+subst_vsub_1(Key, New, [{K,Key}|Dict]) ->
%% Fold chained substitution.
- [{K,New}|subst_vsub(Key, New, Dict)];
-subst_vsub(Key, New, [{K,_}|_]=Dict) when Key < K ->
+ [{K,New}|subst_vsub_1(Key, New, Dict)];
+subst_vsub_1(Key, New, [{K,_}|_]=Dict) when Key < K ->
%% Insert the new substitution here, and continue
%% look for chained substitutions.
- [{Key,New}|subst_vsub_1(Key, New, Dict)];
-subst_vsub(Key, New, [{K,_}=E|Dict]) when Key > K ->
- [E|subst_vsub(Key, New, Dict)];
-subst_vsub(Key, New, []) -> [{Key,New}].
+ [{Key,New}|subst_vsub_2(Key, New, Dict)];
+subst_vsub_1(Key, New, [{K,_}=E|Dict]) when Key > K ->
+ [E|subst_vsub_1(Key, New, Dict)];
+subst_vsub_1(Key, New, []) -> [{Key,New}].
-subst_vsub_1(V, S, [{K,V}|Dict]) ->
+subst_vsub_2(V, S, [{K,V}|Dict]) ->
%% Fold chained substitution.
- [{K,S}|subst_vsub_1(V, S, Dict)];
-subst_vsub_1(V, S, [E|Dict]) ->
- [E|subst_vsub_1(V, S, Dict)];
-subst_vsub_1(_, _, []) -> [].
+ [{K,S}|subst_vsub_2(V, S, Dict)];
+subst_vsub_2(V, S, [E|Dict]) ->
+ [E|subst_vsub_2(V, S, Dict)];
+subst_vsub_2(_, _, []) -> [].
get_fsub(F, A, Fsub) ->
case orddict:find({F,A}, Fsub) of
@@ -877,7 +1356,7 @@ new_fun_name(Type, #kern{func={F,Arity},fcount=C}=St) ->
%% new_var_name(State) -> {VarName,State}.
new_var_name(#kern{vcount=C}=St) ->
- {list_to_atom("ker" ++ integer_to_list(C)),St#kern{vcount=C+1}}.
+ {list_to_atom("@k" ++ integer_to_list(C)),St#kern{vcount=C+1}}.
%% new_var(State) -> {#k_var{},State}.
@@ -1347,10 +1826,70 @@ select(T, Cs) -> [ C || C <- Cs, clause_con(C) =:= T ].
%% At this point all the clauses have the same constructor, we must
%% now separate them according to value.
-match_value(Us, T, Cs0, Def, St0) ->
- Css = group_value(T, Cs0),
+match_value(Us0, T, Cs0, Def, St0) ->
+ {Us1,Cs1,St1} = partition_intersection(T, Us0, Cs0, St0),
+ UCss = group_value(T, Us1, Cs1),
%%ok = io:format("match_value ~p ~p~n", [T, Css]),
- mapfoldl(fun (Cs, St) -> match_clause(Us, Cs, Def, St) end, St0, Css).
+ mapfoldl(fun ({Us,Cs}, St) -> match_clause(Us, Cs, Def, St) end, St1, UCss).
+
+%% partition_intersection
+%% Partitions a map into two maps with the most common keys to the first map.
+%% case <M> of
+%% <#{a}>
+%% <#{a,b}>
+%% <#{a,c}>
+%% <#{c}>
+%% end
+%% becomes
+%% case <M,M> of
+%% <#{a}, #{ }>
+%% <#{a}, #{b}>
+%% <#{ }, #{c}>
+%% <#{a}, #{c}>
+%% end
+%% The intention is to group as many keys together as possible and thus
+%% reduce the number of lookups to that key.
+partition_intersection(k_map, [U|_]=Us0, [_,_|_]=Cs0,St0) ->
+ Ps = [clause_val(C) || C <- Cs0],
+ case find_key_partition(Ps) of
+ no_partition ->
+ {Us0,Cs0,St0};
+ Ks ->
+ {Cs1,St1} = mapfoldl(fun(#iclause{pats=[Arg|Args]}=C, Sti) ->
+ {{Arg1,Arg2},St} = partition_key_intersection(Arg, Ks, Sti),
+ {C#iclause{pats=[Arg1,Arg2|Args]}, St}
+ end, St0, Cs0),
+ {[U|Us0],Cs1,St1}
+ end;
+partition_intersection(_, Us, Cs, St) ->
+ {Us,Cs,St}.
+
+partition_key_intersection(#k_map{es=Pairs}=Map,Ks,St0) ->
+ F = fun(#k_map_pair{key=Key}) -> member(map_key_clean(Key), Ks) end,
+ {Ps1,Ps2} = partition(F, Pairs),
+ {{Map#k_map{es=Ps1},Map#k_map{es=Ps2}},St0};
+partition_key_intersection(#ialias{pat=Map}=Alias,Ks,St0) ->
+ %% only alias one of them
+ {{Map1,Map2},St1} = partition_key_intersection(Map, Ks, St0),
+ {{Map1,Alias#ialias{pat=Map2}},St1}.
+
+% Only check for the complete intersection of keys and not commonality
+find_key_partition(Ps) ->
+ Sets = [sets:from_list(Ks)||Ks <- Ps],
+ Is = sets:intersection(Sets),
+ case sets:to_list(Is) of
+ [] -> no_partition;
+ KeyIntersection ->
+ %% Check if the intersection are all keys in all clauses.
+ %% Don't split if they are since this will only
+ %% infer extra is_map instructions with no gain.
+ All = foldl(fun (Kset, Bool) ->
+ Bool andalso sets:is_subset(Kset, Is)
+ end, true, Sets),
+ if All -> no_partition;
+ true -> KeyIntersection
+ end
+ end.
%% group_value([Clause]) -> [[Clause]].
%% Group clauses according to value. Here we know that
@@ -1358,30 +1897,30 @@ match_value(Us, T, Cs0, Def, St0) ->
%% 2. The clauses in bin_segs cannot be reordered only grouped
%% 3. Other types are disjoint and can be reordered
-group_value(k_cons, Cs) -> [Cs]; %These are single valued
-group_value(k_nil, Cs) -> [Cs];
-group_value(k_binary, Cs) -> [Cs];
-group_value(k_bin_end, Cs) -> [Cs];
-group_value(k_bin_seg, Cs) -> group_bin_seg(Cs);
-group_value(k_bin_int, Cs) -> [Cs];
-group_value(k_map, Cs) -> group_map(Cs);
-group_value(_, Cs) ->
+group_value(k_cons, Us, Cs) -> [{Us,Cs}]; %These are single valued
+group_value(k_nil, Us, Cs) -> [{Us,Cs}];
+group_value(k_binary, Us, Cs) -> [{Us,Cs}];
+group_value(k_bin_end, Us, Cs) -> [{Us,Cs}];
+group_value(k_bin_seg, Us, Cs) -> group_bin_seg(Us,Cs);
+group_value(k_bin_int, Us, Cs) -> [{Us,Cs}];
+group_value(k_map, Us, Cs) -> group_map(Us,Cs);
+group_value(_, Us, Cs) ->
%% group_value(Cs).
Cd = foldl(fun (C, Gcs0) -> dict:append(clause_val(C), C, Gcs0) end,
dict:new(), Cs),
- dict:fold(fun (_, Vcs, Css) -> [Vcs|Css] end, [], Cd).
+ dict:fold(fun (_, Vcs, Css) -> [{Us,Vcs}|Css] end, [], Cd).
-group_bin_seg([C1|Cs]) ->
+group_bin_seg(Us, [C1|Cs]) ->
V1 = clause_val(C1),
{More,Rest} = splitwith(fun (C) -> clause_val(C) == V1 end, Cs),
- [[C1|More]|group_bin_seg(Rest)];
-group_bin_seg([]) -> [].
+ [{Us,[C1|More]}|group_bin_seg(Us,Rest)];
+group_bin_seg(_, []) -> [].
-group_map([C1|Cs]) ->
+group_map(Us, [C1|Cs]) ->
V1 = clause_val(C1),
{More,Rest} = splitwith(fun (C) -> clause_val(C) =:= V1 end, Cs),
- [[C1|More]|group_map(Rest)];
-group_map([]) -> [].
+ [{Us,[C1|More]}|group_map(Us,Rest)];
+group_map(_, []) -> [].
%% Profiling shows that this quadratic implementation account for a big amount
%% of the execution time if there are many values.
@@ -1731,15 +2270,15 @@ uexpr(#k_receive_accept{anno=A}, _, St) ->
{#k_receive_accept{anno=#k{us=[],ns=[],a=A}},[],St};
uexpr(#k_receive_next{anno=A}, _, St) ->
{#k_receive_next{anno=#k{us=[],ns=[],a=A}},[],St};
-uexpr(#k_try{anno=A,arg=A0,vars=Vs,body=B0,evars=Evs,handler=H0}=Try,
+uexpr(#k_try{anno=A,arg=A0,vars=Vs,body=B0,evars=Evs,handler=H0},
{break,Rs0}=Br, St0) ->
case is_in_guard(St0) of
true ->
{[#k_var{name=X}],#k_var{name=X}} = {Vs,B0}, %Assertion.
#k_atom{val=false} = H0, %Assertion.
{A1,Bu,St1} = uexpr(A0, Br, St0),
- {Try#k_try{anno=#k{us=Bu,ns=lit_list_vars(Rs0),a=A},
- arg=A1,ret=Rs0},Bu,St1};
+ {#k_protected{anno=#k{us=Bu,ns=lit_list_vars(Rs0),a=A},
+ arg=A1,ret=Rs0},Bu,St1};
false ->
{Avs,St1} = new_vars(length(Vs), St0),
{A1,Au,St2} = ubody(A0, {break,Avs}, St1),
@@ -1788,13 +2327,9 @@ uexpr(#ifun{anno=A,vars=Vs,body=B0}, {break,Rs}, St0) ->
end,
Fun = #k_fdef{anno=#k{us=[],ns=[],a=A},func=Fname,arity=Arity,
vars=Vs ++ Fvs,body=B1},
- %% Set dummy values for Index and Uniq -- the real values will
- %% be assigned by beam_asm.
- Index = Uniq = 0,
{#k_bif{anno=#k{us=Free,ns=lit_list_vars(Rs),a=A},
- op=#k_internal{name=make_fun,arity=length(Free)+3},
- args=[#k_atom{val=Fname},#k_int{val=Arity},
- #k_int{val=Index},#k_int{val=Uniq}|Fvs],
+ op=#k_internal{name=make_fun,arity=length(Free)+2},
+ args=[#k_atom{val=Fname},#k_int{val=Arity}|Fvs],
ret=Rs},
Free,add_local_function(Fun, St)};
uexpr(Lit, {break,Rs0}, St0) ->
@@ -1837,14 +2372,17 @@ handle_reuse_anno_1(V, _St) -> V.
%% get_free(Name, Arity, State) -> [Free].
%% store_free(Name, Arity, [Free], State) -> State.
-get_free(F, A, St) ->
- case orddict:find({F,A}, St#kern.free) of
- {ok,Val} -> Val;
- error -> []
+get_free(F, A, #kern{free=FreeMap}) ->
+ Key = {F,A},
+ case FreeMap of
+ #{Key:=Val} -> Val;
+ _ -> []
end.
-store_free(F, A, Free, St) ->
- St#kern{free=orddict:store({F,A}, Free, St#kern.free)}.
+store_free(F, A, Free, #kern{free=FreeMap0}=St) ->
+ Key = {F,A},
+ FreeMap = FreeMap0#{Key=>Free},
+ St#kern{free=FreeMap}.
break_rets({break,Rs}) -> Rs;
break_rets(return) -> [].
@@ -1983,11 +2521,6 @@ pat_list_vars(Ps) ->
{union(Used0, Used),union(New0, New)} end,
{[],[]}, Ps).
-make_list(Es) ->
- foldr(fun(E, Acc) ->
- #c_cons{hd=E,tl=Acc}
- end, #c_literal{val=[]}, Es).
-
%% List of integers in interval [N,M]. Empty list if N > M.
integers(N, M) when N =< M ->
diff --git a/lib/compiler/src/v3_kernel.hrl b/lib/compiler/src/v3_kernel.hrl
index 03b2eae006..7cd30b25a8 100644
--- a/lib/compiler/src/v3_kernel.hrl
+++ b/lib/compiler/src/v3_kernel.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -58,7 +58,7 @@
-record(k_seq, {anno=[],arg,body}).
-record(k_put, {anno=[],arg,ret=[]}).
-record(k_bif, {anno=[],op,args,ret=[]}).
--record(k_test, {anno=[],op,args}).
+-record(k_test, {anno=[],op,args,inverted=false}).
-record(k_call, {anno=[],op,args,ret=[]}).
-record(k_enter, {anno=[],op,args}).
-record(k_receive, {anno=[],var,body,timeout,action,ret=[]}).
@@ -66,6 +66,7 @@
-record(k_receive_next, {anno=[]}).
-record(k_try, {anno=[],arg,vars,body,evars,handler,ret=[]}).
-record(k_try_enter, {anno=[],arg,vars,body,evars,handler}).
+-record(k_protected, {anno=[],arg,ret=[]}).
-record(k_catch, {anno=[],body,ret=[]}).
-record(k_guard_match, {anno=[],vars,body,ret=[]}).
diff --git a/lib/compiler/src/v3_kernel_pp.erl b/lib/compiler/src/v3_kernel_pp.erl
index 03b034ae98..53097d0d7d 100644
--- a/lib/compiler/src/v3_kernel_pp.erl
+++ b/lib/compiler/src/v3_kernel_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. 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.
@@ -47,7 +47,7 @@
canno(Cthing) -> element(2, Cthing).
--spec format(cerl:cerl()) -> iolist().
+-spec format(#k_mdef{}) -> iolist().
format(Node) -> format(Node, #ctxt{}).
@@ -145,7 +145,7 @@ format_1(#k_local{name=N,arity=A}, Ctxt) ->
"local " ++ format_fa_pair({N,A}, Ctxt);
format_1(#k_remote{mod=M,name=N,arity=A}, _Ctxt) ->
%% This is for our internal translator.
- io_lib:format("remote ~s:~s/~w", [format(M),format(N),A]);
+ io_lib:format("remote ~ts:~ts/~w", [format(M),format(N),A]);
format_1(#k_internal{name=N,arity=A}, Ctxt) ->
"internal " ++ format_fa_pair({N,A}, Ctxt);
format_1(#k_seq{arg=A,body=B}, Ctxt) ->
@@ -235,8 +235,13 @@ format_1(#k_bif{op=Op,args=As,ret=Rs}, Ctxt) ->
[Txt,format_args(As, Ctxt1),
format_ret(Rs, Ctxt1)
];
-format_1(#k_test{op=Op,args=As}, Ctxt) ->
- Txt = ["test (",format(Op, ctxt_bump_indent(Ctxt, 6)),$)],
+format_1(#k_test{op=Op,args=As,inverted=Inverted}, Ctxt) ->
+ Txt = case Inverted of
+ false ->
+ ["test (",format(Op, ctxt_bump_indent(Ctxt, 6)),$)];
+ true ->
+ ["inverted_test (",format(Op, ctxt_bump_indent(Ctxt, 6)),$)]
+ end,
Ctxt1 = ctxt_bump_indent(Ctxt, 2),
[Txt,format_args(As, Ctxt1)];
format_1(#k_put{arg=A,ret=Rs}, Ctxt) ->
@@ -279,6 +284,15 @@ format_1(#k_try_enter{arg=A,vars=Vs,body=B,evars=Evs,handler=H}, Ctxt) ->
nl_indent(Ctxt),
"end"
];
+format_1(#k_protected{arg=A,ret=Rs}, Ctxt) ->
+ Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.body_indent),
+ ["protected",
+ nl_indent(Ctxt1),
+ format(A, Ctxt1),
+ nl_indent(Ctxt),
+ "end",
+ format_ret(Rs, ctxt_bump_indent(Ctxt, 1))
+ ];
format_1(#k_catch{body=B,ret=Rs}, Ctxt) ->
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.body_indent),
["catch",
diff --git a/lib/compiler/src/v3_life.erl b/lib/compiler/src/v3_life.erl
index fa057ae211..be3ade47ff 100644
--- a/lib/compiler/src/v3_life.erl
+++ b/lib/compiler/src/v3_life.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -52,10 +52,15 @@
-include("v3_kernel.hrl").
-include("v3_life.hrl").
+-type fa() :: {atom(),arity()}.
+
%% These are not defined in v3_kernel.hrl.
get_kanno(Kthing) -> element(2, Kthing).
%%set_kanno(Kthing, Anno) -> setelement(2, Kthing, Anno).
+-spec module(#k_mdef{}, [compile:option()]) ->
+ {'ok',{module(),[fa()],[_],[_]}}.
+
module(#k_mdef{name=M,exports=Es,attributes=As,body=Fs0}, _Opts) ->
Fs1 = functions(Fs0, []),
{ok,{M,Es,As,Fs1}}.
@@ -78,9 +83,7 @@ function(#k_fdef{anno=#k{a=Anno},func=F,arity=Ar,vars=Vs,body=Kb}) ->
#k_match{anno=#k{us=Ka#k.us,ns=[],a=Ka#k.a},
vars=Vs,body=Kb,ret=[]}
end,
- put(guard_refc, 0),
{B1,_,Vdb1} = body(B0, 1, Vdb0),
- erase(guard_refc),
{function,F,Ar,As,B1,Vdb1,Anno}
catch
Class:Error ->
@@ -106,12 +109,13 @@ body(Ke, I, Vdb0) ->
E = expr(Ke, I, Vdb1),
{[E],I,Vdb1}.
-%% guard(Kguard, I, Vdb) -> Guard.
+%% protected(Kprotected, I, Vdb) -> Protected.
+%% Only used in guards.
-guard(#k_try{anno=A,arg=Ts,vars=[#k_var{name=X}],body=#k_var{name=X},
- handler=#k_atom{val=false},ret=Rs}, I, Vdb) ->
+protected(#k_protected{anno=A,arg=Ts,ret=Rs}, I, Vdb) ->
%% Lock variables that are alive before try and used afterwards.
- %% Don't lock variables that are only used inside the try expression.
+ %% Don't lock variables that are only used inside the protected
+ %% expression.
Pdb0 = vdb_sub(I, I+1, Vdb),
{T,MaxI,Pdb1} = body(Ts, I+1, Pdb0),
Pdb2 = use_vars(A#k.ns, MaxI+1, Pdb1), %Save "return" values
@@ -119,8 +123,8 @@ guard(#k_try{anno=A,arg=Ts,vars=[#k_var{name=X}],body=#k_var{name=X},
%% expr(Kexpr, I, Vdb) -> Expr.
-expr(#k_test{anno=A,op=Op,args=As}, I, _Vdb) ->
- #l{ke={test,test_op(Op),atomic_list(As)},i=I,a=A#k.a};
+expr(#k_test{anno=A,op=Op,args=As,inverted=Inverted}, I, _Vdb) ->
+ #l{ke={test,test_op(Op),atomic_list(As),Inverted},i=I,a=A#k.a};
expr(#k_call{anno=A,op=Op,args=As,ret=Rs}, I, _Vdb) ->
#l{ke={call,call_op(Op),atomic_list(As),var_list(Rs)},i=I,a=A#k.a};
expr(#k_enter{anno=A,op=Op,args=As}, I, _Vdb) ->
@@ -139,10 +143,9 @@ expr(#k_guard_match{anno=A,body=Kb,ret=Rs}, I, Vdb) ->
M = match(Kb, A#k.us, I+1, [], Mdb),
#l{ke={guard_match,M,var_list(Rs)},i=I,vdb=use_vars(A#k.us, I+1, Mdb),a=A#k.a};
expr(#k_try{}=Try, I, Vdb) ->
- case is_in_guard() of
- false -> body_try(Try, I, Vdb);
- true -> guard(Try, I, Vdb)
- end;
+ body_try(Try, I, Vdb);
+expr(#k_protected{}=Protected, I, Vdb) ->
+ protected(Protected, I, Vdb);
expr(#k_try_enter{anno=A,arg=Ka,vars=Vs,body=Kb,evars=Evs,handler=Kh}, I, Vdb) ->
%% Lock variables that are alive before the catch and used afterwards.
%% Don't lock variables that are only used inside the try.
@@ -213,7 +216,6 @@ body_try(#k_try{anno=A,arg=Ka,vars=Vs,body=Kb,evars=Evs,handler=Kh,ret=Rs},
i=I,vdb=Tdb1,a=A#k.a}.
%% call_op(Op) -> Op.
-%% bif_op(Op) -> Op.
%% test_op(Op) -> Op.
%% Do any necessary name translations here to munge into beam format.
@@ -221,28 +223,14 @@ call_op(#k_local{name=N}) -> N;
call_op(#k_remote{mod=M,name=N}) -> {remote,atomic(M),atomic(N)};
call_op(Other) -> variable(Other).
-bif_op(#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=N}}) -> N;
-bif_op(#k_internal{name=N}) -> N.
-
test_op(#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=N}}) -> N.
%% k_bif(Anno, Op, [Arg], [Ret], Vdb) -> Expr.
-%% Build bifs, do special handling of internal some calls.
-
-k_bif(_A, #k_internal{name=dsetelement,arity=3}, As, []) ->
- {bif,dsetelement,atomic_list(As),[]};
-k_bif(_A, #k_internal{name=bs_context_to_binary=Op,arity=1}, As, []) ->
- {bif,Op,atomic_list(As),[]};
-k_bif(_A, #k_internal{name=bs_init_writable=Op,arity=1}, As, Rs) ->
- {bif,Op,atomic_list(As),var_list(Rs)};
-k_bif(_A, #k_internal{name=make_fun},
- [#k_atom{val=Fun},#k_int{val=Arity},
- #k_int{val=Index},#k_int{val=Uniq}|Free],
- Rs) ->
- {bif,{make_fun,Fun,Arity,Index,Uniq},var_list(Free),var_list(Rs)};
-k_bif(_A, Op, As, Rs) ->
- %% The general case.
- Name = bif_op(Op),
+%% Build bifs.
+
+k_bif(_A, #k_internal{name=Name}, As, Rs) ->
+ {internal,Name,atomic_list(As),var_list(Rs)};
+k_bif(_A, #k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=Name}}, As, Rs) ->
Ar = length(As),
case is_gc_bif(Name, Ar) of
false ->
@@ -303,9 +291,7 @@ val_clause(#k_val_clause{anno=A,val=V,body=Kb}, Ls0, I, Ctxt0, Vdb0) ->
guard_clause(#k_guard_clause{anno=A,guard=Kg,body=Kb}, Ls, I, Ctxt, Vdb0) ->
Vdb1 = use_vars(union(A#k.us, Ls), I+2, Vdb0),
Gdb = vdb_sub(I+1, I+2, Vdb1),
- OldRefc = put(guard_refc, get(guard_refc)+1),
- G = guard(Kg, I+1, Gdb),
- put(guard_refc, OldRefc),
+ G = protected(Kg, I+1, Gdb),
B = match(Kb, Ls, I+2, Ctxt, Vdb1),
#l{ke={guard_clause,G,B},
i=I,vdb=use_vars((get_kanno(Kg))#k.us, I+2, Vdb1),
@@ -394,7 +380,6 @@ is_gc_bif(node, 0) -> false;
is_gc_bif(node, 1) -> false;
is_gc_bif(element, 2) -> false;
is_gc_bif(get, 1) -> false;
-is_gc_bif(raise, 2) -> false;
is_gc_bif(tuple_size, 1) -> false;
is_gc_bif(Bif, Arity) ->
not (erl_internal:bool_op(Bif, Arity) orelse
@@ -431,16 +416,15 @@ use_vars(Vs, I, Vdb) -> vdb_update_vars(Vs, Vdb, I).
add_var(V, F, L, Vdb) ->
vdb_store_new(V, {V,F,L}, Vdb).
-%% is_in_guard() -> true|false.
-
-is_in_guard() ->
- get(guard_refc) > 0.
-
%% vdb
vdb_new(Vs) ->
sort([{V,0,0} || {var,V} <- Vs]).
+-type var() :: atom().
+
+-spec vdb_find(var(), [vdb_entry()]) -> 'error' | vdb_entry().
+
vdb_find(V, Vdb) ->
case lists:keyfind(V, 1, Vdb) of
false -> error;
diff --git a/lib/compiler/src/v3_life.hrl b/lib/compiler/src/v3_life.hrl
index 29a08f8c72..5c76312067 100644
--- a/lib/compiler/src/v3_life.hrl
+++ b/lib/compiler/src/v3_life.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,8 +20,10 @@
%% This record contains variable life-time annotation for a
%% kernel expression. Added by v3_life, used by v3_codegen.
+-type vdb_entry() :: {atom(),non_neg_integer(),non_neg_integer()}.
+
-record(l, {ke, %Kernel expression
- i=0, %Op number
- vdb=[], %Variable database
- a}). %Core annotation
+ i=0 :: non_neg_integer(), %Op number
+ vdb=[] :: [vdb_entry()], %Variable database
+ a=[] :: [term()]}). %Core annotation
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index 6553d10077..63763f31b2 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -8,10 +8,15 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
MODULES= \
andor_SUITE \
apply_SUITE \
+ beam_block_SUITE \
beam_validator_SUITE \
beam_disasm_SUITE \
beam_except_SUITE \
+ beam_jump_SUITE \
+ beam_reorder_SUITE \
+ beam_type_SUITE \
beam_utils_SUITE \
+ bif_SUITE \
bs_bincomp_SUITE \
bs_bit_binaries_SUITE \
bs_construct_SUITE \
@@ -30,7 +35,7 @@ MODULES= \
map_SUITE \
match_SUITE \
misc_SUITE \
- num_bif_SUITE \
+ overridden_bif_SUITE \
receive_SUITE \
record_SUITE \
regressions_SUITE \
@@ -42,8 +47,13 @@ MODULES= \
NO_OPT= \
andor \
apply \
+ beam_block \
beam_except \
+ beam_jump \
+ beam_reorder \
+ beam_type \
beam_utils \
+ bif \
bs_construct \
bs_match \
bs_utf \
@@ -55,7 +65,7 @@ NO_OPT= \
map \
match \
misc \
- num_bif \
+ overridden_bif \
receive \
record \
trycatch
@@ -63,7 +73,9 @@ NO_OPT= \
INLINE= \
andor \
apply \
+ beam_block \
beam_utils \
+ bif \
bs_bincomp \
bs_bit_binaries \
bs_construct \
@@ -77,10 +89,14 @@ INLINE= \
map \
match \
misc \
- num_bif \
+ overridden_bif \
receive \
record
+CORE_MODULES = \
+ lfe_andor_SUITE \
+ lfe_guard_SUITE
+
NO_OPT_MODULES= $(NO_OPT:%=%_no_opt_SUITE)
NO_OPT_ERL_FILES= $(NO_OPT_MODULES:%=%.erl)
POST_OPT_MODULES= $(NO_OPT:%=%_post_opt_SUITE)
@@ -89,6 +105,8 @@ INLINE_MODULES= $(INLINE:%=%_inline_SUITE)
INLINE_ERL_FILES= $(INLINE_MODULES:%=%.erl)
ERL_FILES= $(MODULES:%=%.erl)
+CORE_FILES= $(CORE_MODULES:%=%.core)
+ERL_DUMMY_FILES= $(CORE_MODULES:%=%.erl)
##TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
##INSTALL_PROGS= $(TARGET_FILES)
@@ -105,7 +123,7 @@ RELSYSDIR = $(RELEASE_PATH)/compiler_test
# ----------------------------------------------------
ERL_MAKE_FLAGS +=
-ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include +clint +clint0
+ERL_COMPILE_FLAGS += +clint +clint0
EBIN = .
@@ -122,6 +140,8 @@ make_emakefile: $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) $(INLINE_ERL_FILES)
-o$(EBIN) $(POST_OPT_MODULES) >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +inline $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(INLINE_MODULES) >> $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile +from_core $(ERL_COMPILE_FLAGS) \
+ -o$(EBIN) $(CORE_MODULES) >> $(EMAKEFILE)
tests debug opt: make_emakefile
erl $(ERL_MAKE_FLAGS) -make
@@ -159,6 +179,13 @@ release_tests_spec: make_emakefile
$(EMAKEFILE) $(ERL_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) \
$(INLINE_ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(CORE_FILES) "$(RELSYSDIR)"
+ for file in $(ERL_DUMMY_FILES); do \
+ module=`basename $$file .erl`; \
+ echo "-module($$module). %% dummy .erl file" >$$file; \
+ done
+ $(INSTALL_DATA) $(ERL_DUMMY_FILES) "$(RELSYSDIR)"
+ rm $(ERL_DUMMY_FILES)
chmod -R u+w "$(RELSYSDIR)"
@tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
diff --git a/lib/compiler/test/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl
index fae9597c8a..05c087104d 100644
--- a/lib/compiler/test/andor_SUITE.erl
+++ b/lib/compiler/test/andor_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,10 +22,9 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
t_case/1,t_and_or/1,t_andalso/1,t_orelse/1,inside/1,overlap/1,
- combined/1,in_case/1,before_and_inside_if/1,
- slow_compilation/1]).
+ combined/1,in_case/1,slow_compilation/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -36,7 +35,7 @@ all() ->
groups() ->
[{p,[parallel],
[t_case,t_and_or,t_andalso,t_orelse,inside,overlap,
- combined,in_case,before_and_inside_if]}].
+ combined,in_case,slow_compilation]}].
init_per_suite(Config) ->
Config.
@@ -54,28 +53,28 @@ end_per_group(_GroupName, Config) ->
t_case(Config) when is_list(Config) ->
%% We test boolean cases almost but not quite like cases
%% generated by andalso/orelse.
- ?line less = t_case_a(1, 2),
- ?line not_less = t_case_a(2, 2),
- ?line {'EXIT',{{case_clause,false},_}} = (catch t_case_b({x,y,z}, 2)),
- ?line {'EXIT',{{case_clause,true},_}} = (catch t_case_b(a, a)),
- ?line eq = t_case_c(a, a),
- ?line ne = t_case_c(42, []),
- ?line t = t_case_d(x, x, true),
- ?line f = t_case_d(x, x, false),
- ?line f = t_case_d(x, y, true),
- ?line {'EXIT',{badarg,_}} = (catch t_case_d(x, y, blurf)),
- ?line true = (catch t_case_e({a,b}, {a,b})),
- ?line false = (catch t_case_e({a,b}, 42)),
-
- ?line true = t_case_xy(42, 100, 700),
- ?line true = t_case_xy(42, 100, whatever),
- ?line false = t_case_xy(42, wrong, 700),
- ?line false = t_case_xy(42, wrong, whatever),
-
- ?line true = t_case_xy(0, whatever, 700),
- ?line true = t_case_xy(0, 100, 700),
- ?line false = t_case_xy(0, whatever, wrong),
- ?line false = t_case_xy(0, 100, wrong),
+ less = t_case_a(1, 2),
+ not_less = t_case_a(2, 2),
+ {'EXIT',{{case_clause,false},_}} = (catch t_case_b({x,y,z}, 2)),
+ {'EXIT',{{case_clause,true},_}} = (catch t_case_b(a, a)),
+ eq = t_case_c(a, a),
+ ne = t_case_c(42, []),
+ t = t_case_d(x, x, true),
+ f = t_case_d(x, x, false),
+ f = t_case_d(x, y, true),
+ {'EXIT',{badarg,_}} = (catch t_case_d(x, y, blurf)),
+ true = (catch t_case_e({a,b}, {a,b})),
+ false = (catch t_case_e({a,b}, 42)),
+
+ true = t_case_xy(42, 100, 700),
+ true = t_case_xy(42, 100, whatever),
+ false = t_case_xy(42, wrong, 700),
+ false = t_case_xy(42, wrong, whatever),
+
+ true = t_case_xy(0, whatever, 700),
+ true = t_case_xy(0, 100, 700),
+ false = t_case_xy(0, whatever, wrong),
+ false = t_case_xy(0, 100, wrong),
ok.
@@ -135,35 +134,35 @@ t_case_y(X, Y, Z) ->
end).
t_and_or(Config) when is_list(Config) ->
- ?line true = true and true,
- ?line false = true and false,
- ?line false = false and true,
- ?line false = false and false,
-
- ?line true = id(true) and true,
- ?line false = id(true) and false,
- ?line false = id(false) and true,
- ?line false = id(false) and false,
-
- ?line true = true and id(true),
- ?line false = true and id(false),
- ?line false = false and id(true),
- ?line false = false and id(false),
-
- ?line true = true or true,
- ?line true = true or false,
- ?line true = false or true,
- ?line false = false or false,
-
- ?line true = id(true) or true,
- ?line true = id(true) or false,
- ?line true = id(false) or true,
- ?line false = id(false) or false,
-
- ?line true = true or id(true),
- ?line true = true or id(false),
- ?line true = false or id(true),
- ?line false = false or id(false),
+ true = true and true,
+ false = true and false,
+ false = false and true,
+ false = false and false,
+
+ true = id(true) and true,
+ false = id(true) and false,
+ false = id(false) and true,
+ false = id(false) and false,
+
+ true = true and id(true),
+ false = true and id(false),
+ false = false and id(true),
+ false = false and id(false),
+
+ true = true or true,
+ true = true or false,
+ true = false or true,
+ false = false or false,
+
+ true = id(true) or true,
+ true = id(true) or false,
+ true = id(false) or true,
+ false = id(false) or false,
+
+ true = true or id(true),
+ true = true or id(false),
+ true = false or id(true),
+ false = false or id(false),
True = id(true),
@@ -187,28 +186,28 @@ t_andalso(Config) when is_list(Config) ->
Ps = [{X,Y} || X <- Bs, Y <- Bs],
lists:foreach(fun (P) -> t_andalso_1(P) end, Ps),
- ?line true = true andalso true,
- ?line false = true andalso false,
- ?line false = false andalso true,
- ?line false = false andalso false,
+ true = true andalso true,
+ false = true andalso false,
+ false = false andalso true,
+ false = false andalso false,
- ?line true = ?GUARD(true andalso true),
- ?line false = ?GUARD(true andalso false),
- ?line false = ?GUARD(false andalso true),
- ?line false = ?GUARD(false andalso false),
+ true = ?GUARD(true andalso true),
+ false = ?GUARD(true andalso false),
+ false = ?GUARD(false andalso true),
+ false = ?GUARD(false andalso false),
- ?line false = false andalso glurf,
- ?line false = false andalso exit(exit_now),
+ false = false andalso glurf,
+ false = false andalso exit(exit_now),
- ?line true = not id(false) andalso not id(false),
- ?line false = not id(false) andalso not id(true),
- ?line false = not id(true) andalso not id(false),
- ?line false = not id(true) andalso not id(true),
+ true = not id(false) andalso not id(false),
+ false = not id(false) andalso not id(true),
+ false = not id(true) andalso not id(false),
+ false = not id(true) andalso not id(true),
- ?line {'EXIT',{badarg,_}} = (catch not id(glurf) andalso id(true)),
- ?line {'EXIT',{badarg,_}} = (catch not id(false) andalso not id(glurf)),
- ?line false = id(false) andalso not id(glurf),
- ?line false = false andalso not id(glurf),
+ {'EXIT',{badarg,_}} = (catch not id(glurf) andalso id(true)),
+ {'EXIT',{badarg,_}} = (catch not id(false) andalso not id(glurf)),
+ false = id(false) andalso not id(glurf),
+ false = false andalso not id(glurf),
true = begin (X1 = true) andalso X1, X1 end,
false = false = begin (X2 = false) andalso X2, X2 end,
@@ -220,28 +219,28 @@ t_orelse(Config) when is_list(Config) ->
Ps = [{X,Y} || X <- Bs, Y <- Bs],
lists:foreach(fun (P) -> t_orelse_1(P) end, Ps),
- ?line true = true orelse true,
- ?line true = true orelse false,
- ?line true = false orelse true,
- ?line false = false orelse false,
+ true = true orelse true,
+ true = true orelse false,
+ true = false orelse true,
+ false = false orelse false,
- ?line true = ?GUARD(true orelse true),
- ?line true = ?GUARD(true orelse false),
- ?line true = ?GUARD(false orelse true),
- ?line false = ?GUARD(false orelse false),
+ true = ?GUARD(true orelse true),
+ true = ?GUARD(true orelse false),
+ true = ?GUARD(false orelse true),
+ false = ?GUARD(false orelse false),
- ?line true = true orelse glurf,
- ?line true = true orelse exit(exit_now),
+ true = true orelse glurf,
+ true = true orelse exit(exit_now),
- ?line true = not id(false) orelse not id(false),
- ?line true = not id(false) orelse not id(true),
- ?line true = not id(true) orelse not id(false),
- ?line false = not id(true) orelse not id(true),
+ true = not id(false) orelse not id(false),
+ true = not id(false) orelse not id(true),
+ true = not id(true) orelse not id(false),
+ false = not id(true) orelse not id(true),
- ?line {'EXIT',{badarg,_}} = (catch not id(glurf) orelse id(true)),
- ?line {'EXIT',{badarg,_}} = (catch not id(true) orelse not id(glurf)),
- ?line true = id(true) orelse not id(glurf),
- ?line true = true orelse not id(glurf),
+ {'EXIT',{badarg,_}} = (catch not id(glurf) orelse id(true)),
+ {'EXIT',{badarg,_}} = (catch not id(true) orelse not id(glurf)),
+ true = id(true) orelse not id(glurf),
+ true = true orelse not id(glurf),
true = begin (X1 = true) orelse X1, X1 end,
false = begin (X2 = false) orelse X2, X2 end,
@@ -255,7 +254,7 @@ t_andalso_1({X,Y}) ->
X andalso Y -> true;
true -> false
end,
- check(V1, X and Y).
+ V1 = id(X and Y).
t_orelse_1({X,Y}) ->
io:fwrite("~w orelse ~w: ",[X,Y]),
@@ -264,19 +263,19 @@ t_orelse_1({X,Y}) ->
X orelse Y -> true;
true -> false
end,
- check(V1, X or Y).
+ V1 = id(X or Y).
inside(Config) when is_list(Config) ->
- ?line true = inside(-8, 1),
- ?line false = inside(-53.5, -879798),
- ?line false = inside(1.0, -879),
- ?line false = inside(59, -879),
- ?line false = inside(-11, 1.0),
- ?line false = inside(100, 0.2),
- ?line false = inside(100, 1.2),
- ?line false = inside(-53.5, 4),
- ?line false = inside(1.0, 5.3),
- ?line false = inside(59, 879),
+ true = inside(-8, 1),
+ false = inside(-53.5, -879798),
+ false = inside(1.0, -879),
+ false = inside(59, -879),
+ false = inside(-11, 1.0),
+ false = inside(100, 0.2),
+ false = inside(100, 1.2),
+ false = inside(-53.5, 4),
+ false = inside(1.0, 5.3),
+ false = inside(59, 879),
ok.
inside(Xm, Ym) ->
@@ -311,15 +310,15 @@ inside_guard(Xm, Ym, X, Y, W, H) ->
{false,Xm,Ym,X,Y,W,H}.
overlap(Config) when is_list(Config) ->
- ?line true = overlap(7.0, 2.0, 8.0, 0.5),
- ?line true = overlap(7.0, 2.0, 8.0, 2.5),
- ?line true = overlap(7.0, 2.0, 5.3, 2),
- ?line true = overlap(7.0, 2.0, 0.0, 100.0),
-
- ?line false = overlap(-1, 2, -35, 0.5),
- ?line false = overlap(-1, 2, 777, 0.5),
- ?line false = overlap(-1, 2, 2, 10),
- ?line false = overlap(2, 10, 12, 55.3),
+ true = overlap(7.0, 2.0, 8.0, 0.5),
+ true = overlap(7.0, 2.0, 8.0, 2.5),
+ true = overlap(7.0, 2.0, 5.3, 2),
+ true = overlap(7.0, 2.0, 0.0, 100.0),
+
+ false = overlap(-1, 2, -35, 0.5),
+ false = overlap(-1, 2, 777, 0.5),
+ false = overlap(-1, 2, 2, 10),
+ false = overlap(2, 10, 12, 55.3),
ok.
overlap(Pos1, Len1, Pos2, Len2) ->
@@ -343,33 +342,33 @@ overlap(Pos1, Len1, Pos2, Len2) ->
-define(COMB(A,B,C), (A andalso B orelse C)).
combined(Config) when is_list(Config) ->
- ?line false = comb(false, false, false),
- ?line true = comb(false, false, true),
- ?line false = comb(false, true, false),
- ?line true = comb(false, true, true),
-
- ?line false = comb(true, false, false),
- ?line true = comb(true, true, false),
- ?line true = comb(true, false, true),
- ?line true = comb(true, true, true),
-
- ?line false = comb(false, blurf, false),
- ?line true = comb(false, blurf, true),
- ?line true = comb(true, true, blurf),
-
- ?line false = ?COMB(false, false, false),
- ?line true = ?COMB(false, false, true),
- ?line false = ?COMB(false, true, false),
- ?line true = ?COMB(false, true, true),
-
- ?line false = ?COMB(true, false, false),
- ?line true = ?COMB(true, true, false),
- ?line true = ?COMB(true, false, true),
- ?line true = ?COMB(true, true, true),
-
- ?line false = ?COMB(false, blurf, false),
- ?line true = ?COMB(false, blurf, true),
- ?line true = ?COMB(true, true, blurf),
+ false = comb(false, false, false),
+ true = comb(false, false, true),
+ false = comb(false, true, false),
+ true = comb(false, true, true),
+
+ false = comb(true, false, false),
+ true = comb(true, true, false),
+ true = comb(true, false, true),
+ true = comb(true, true, true),
+
+ false = comb(false, blurf, false),
+ true = comb(false, blurf, true),
+ true = comb(true, true, blurf),
+
+ false = ?COMB(false, false, false),
+ true = ?COMB(false, false, true),
+ false = ?COMB(false, true, false),
+ true = ?COMB(false, true, true),
+
+ false = ?COMB(true, false, false),
+ true = ?COMB(true, true, false),
+ true = ?COMB(true, false, true),
+ true = ?COMB(true, true, true),
+
+ false = ?COMB(false, blurf, false),
+ true = ?COMB(false, blurf, true),
+ true = ?COMB(true, true, blurf),
false = simple_comb(false, false),
false = simple_comb(false, true),
@@ -412,13 +411,13 @@ simple_comb(A, B) ->
%% Test that a boolean expression in a case expression is properly
%% optimized (in particular, that the error behaviour is correct).
in_case(Config) when is_list(Config) ->
- ?line edge_rings = in_case_1(1, 1, 1, 1, 1),
- ?line not_loop = in_case_1(0.5, 1, 1, 1, 1),
- ?line loop = in_case_1(0.5, 0.9, 1.1, 1, 4),
- ?line {'EXIT',{badarith,_}} = (catch in_case_1(1, 1, 1, 1, 0)),
- ?line {'EXIT',{badarith,_}} = (catch in_case_1(1, 1, 1, 1, nan)),
- ?line {'EXIT',{badarg,_}} = (catch in_case_1(1, 1, 1, blurf, 1)),
- ?line {'EXIT',{badarith,_}} = (catch in_case_1([nan], 1, 1, 1, 1)),
+ edge_rings = in_case_1(1, 1, 1, 1, 1),
+ not_loop = in_case_1(0.5, 1, 1, 1, 1),
+ loop = in_case_1(0.5, 0.9, 1.1, 1, 4),
+ {'EXIT',{badarith,_}} = (catch in_case_1(1, 1, 1, 1, 0)),
+ {'EXIT',{badarith,_}} = (catch in_case_1(1, 1, 1, 1, nan)),
+ {'EXIT',{badarg,_}} = (catch in_case_1(1, 1, 1, blurf, 1)),
+ {'EXIT',{badarith,_}} = (catch in_case_1([nan], 1, 1, 1, 1)),
ok.
in_case_1(LenUp, LenDw, LenN, Rotation, Count) ->
@@ -450,64 +449,6 @@ in_case_1_guard(LenUp, LenDw, LenN, Rotation, Count) ->
false -> loop
end.
-before_and_inside_if(Config) when is_list(Config) ->
- ?line no = before_and_inside_if([a], [b], delete),
- ?line no = before_and_inside_if([a], [b], x),
- ?line no = before_and_inside_if([a], [], delete),
- ?line no = before_and_inside_if([a], [], x),
- ?line no = before_and_inside_if([], [], delete),
- ?line yes = before_and_inside_if([], [], x),
- ?line yes = before_and_inside_if([], [b], delete),
- ?line yes = before_and_inside_if([], [b], x),
-
- ?line {ch1,ch2} = before_and_inside_if_2([a], [b], blah),
- ?line {ch1,ch2} = before_and_inside_if_2([a], [b], xx),
- ?line {ch1,ch2} = before_and_inside_if_2([a], [], blah),
- ?line {ch1,ch2} = before_and_inside_if_2([a], [], xx),
- ?line {no,no} = before_and_inside_if_2([], [b], blah),
- ?line {no,no} = before_and_inside_if_2([], [b], xx),
- ?line {ch1,no} = before_and_inside_if_2([], [], blah),
- ?line {no,ch2} = before_and_inside_if_2([], [], xx),
- ok.
-
-%% Thanks to Simon Cornish and Kostis Sagonas.
-%% Used to crash beam_bool.
-before_and_inside_if(XDo1, XDo2, Do3) ->
- Do1 = (XDo1 =/= []),
- Do2 = (XDo2 =/= []),
- if
- %% This expression occurs in a try/catch (protected)
- %% block, which cannot refer to variables outside of
- %% the block that are boolean expressions.
- Do1 =:= true;
- Do1 =:= false, Do2 =:= false, Do3 =:= delete ->
- no;
- true ->
- yes
- end.
-
-%% Thanks to Simon Cornish.
-%% Used to generate code that would not set {y,0} on
-%% all paths before its use (and therefore fail
-%% validation by the beam_validator).
-before_and_inside_if_2(XDo1, XDo2, Do3) ->
- Do1 = (XDo1 =/= []),
- Do2 = (XDo2 =/= []),
- CH1 = if Do1 == true;
- Do1 == false,Do2==false,Do3 == blah ->
- ch1;
- true ->
- no
- end,
- CH2 = if Do1 == true;
- Do1 == false,Do2==false,Do3 == xx ->
- ch2;
- true ->
- no
- end,
- {CH1,CH2}.
-
-
-record(state, {stack = []}).
slow_compilation(_) ->
@@ -539,14 +480,6 @@ slow_compilation_1(T, _) when element(1, T) == a ->
%% Utilities.
-check(V1, V0) ->
- if V1 /= V0 ->
- io:fwrite("error: ~w.\n", [V1]),
- ?t:fail();
- true ->
- io:fwrite("ok: ~w.\n", [V1])
- end.
-
echo(X) ->
io:fwrite("eval(~w); ",[X]),
X.
diff --git a/lib/compiler/test/apply_SUITE.erl b/lib/compiler/test/apply_SUITE.erl
index 3425553fed..cca92e4713 100644
--- a/lib/compiler/test/apply_SUITE.erl
+++ b/lib/compiler/test/apply_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
-export([foo/0,bar/1,baz/2]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -53,44 +53,44 @@ end_per_group(_GroupName, Config) ->
-define(APPLY2(M, F, A1, A2), (fun(Res) -> Res = M:F(A1, A2) end)(apply(M, F, [A1,A2]))).
mfa(Config) when is_list(Config) ->
- ?line ok = ?APPLY0(?MODULE, foo),
- ?line {[a,b]} = ?APPLY1(?MODULE, bar, [a,b]),
- ?line {39,{a}} = ?APPLY2(?MODULE, baz, 39, {a}),
-
- ?line Mod = id(?MODULE),
- ?line ok = ?APPLY0(Mod, foo),
- ?line {[a,b]} = ?APPLY1(Mod, bar, [a,b]),
- ?line {39,{a}} = ?APPLY2(Mod, baz, 39, {a}),
-
- ?line ok = ?APPLY0(?MODULE, (id(foo))),
- ?line {[a,b]} = ?APPLY1(?MODULE, (id(bar)), [a,b]),
- ?line {39,{a}} = ?APPLY2(?MODULE, (id(baz)), 39, {a}),
-
- ?line ok = ?APPLY0(Mod, (id(foo))),
- ?line {[a,b]} = ?APPLY1(Mod, (id(bar)), [a,b]),
- ?line {39,{a}} = ?APPLY2(Mod, (id(baz)), 39, {a}),
-
- ?line {'EXIT',_} = (catch ?APPLY2(Mod, (id(bazzzzzz)), a, b)),
- ?line {'EXIT',_} = (catch ?APPLY2({}, baz, a, b)),
- ?line {'EXIT',_} = (catch ?APPLY2(?MODULE, [], a, b)),
-
- ?line ok = apply(Mod, foo, id([])),
- ?line {[a,b|c]} = apply(Mod, bar, id([[a,b|c]])),
- ?line {[xx],{a}} = apply(?MODULE, baz, id([[xx],{a}])),
-
- ?line Erlang = id(erlang),
- ?line Self = self(),
- ?line Self = ?APPLY0(Erlang, self),
- ?line 42.0 = ?APPLY1(Erlang, abs, -42.0),
- ?line b = ?APPLY2(Erlang, element, 2, {a,b,c}),
- ?line true = ?APPLY1(Erlang, is_function, fun erlang:list_to_binary/1),
- ?line true = ?APPLY1(Erlang, is_function, fun() -> ok end),
- ?line false = ?APPLY1(Erlang, is_function, blurf),
- ?line true = ?APPLY2(Erlang, is_function, fun erlang:list_to_binary/1, 1),
- ?line true = ?APPLY2(Erlang, is_function, fun() -> ok end, 0),
- ?line false = ?APPLY2(Erlang, is_function, blurf, 0),
-
- ?line apply(Mod, foo, []).
+ ok = ?APPLY0(?MODULE, foo),
+ {[a,b]} = ?APPLY1(?MODULE, bar, [a,b]),
+ {39,{a}} = ?APPLY2(?MODULE, baz, 39, {a}),
+
+ Mod = id(?MODULE),
+ ok = ?APPLY0(Mod, foo),
+ {[a,b]} = ?APPLY1(Mod, bar, [a,b]),
+ {39,{a}} = ?APPLY2(Mod, baz, 39, {a}),
+
+ ok = ?APPLY0(?MODULE, (id(foo))),
+ {[a,b]} = ?APPLY1(?MODULE, (id(bar)), [a,b]),
+ {39,{a}} = ?APPLY2(?MODULE, (id(baz)), 39, {a}),
+
+ ok = ?APPLY0(Mod, (id(foo))),
+ {[a,b]} = ?APPLY1(Mod, (id(bar)), [a,b]),
+ {39,{a}} = ?APPLY2(Mod, (id(baz)), 39, {a}),
+
+ {'EXIT',_} = (catch ?APPLY2(Mod, (id(bazzzzzz)), a, b)),
+ {'EXIT',_} = (catch ?APPLY2({}, baz, a, b)),
+ {'EXIT',_} = (catch ?APPLY2(?MODULE, [], a, b)),
+
+ ok = apply(Mod, foo, id([])),
+ {[a,b|c]} = apply(Mod, bar, id([[a,b|c]])),
+ {[xx],{a}} = apply(?MODULE, baz, id([[xx],{a}])),
+
+ Erlang = id(erlang),
+ Self = self(),
+ Self = ?APPLY0(Erlang, self),
+ 42.0 = ?APPLY1(Erlang, abs, -42.0),
+ b = ?APPLY2(Erlang, element, 2, {a,b,c}),
+ true = ?APPLY1(Erlang, is_function, fun erlang:list_to_binary/1),
+ true = ?APPLY1(Erlang, is_function, fun() -> ok end),
+ false = ?APPLY1(Erlang, is_function, blurf),
+ true = ?APPLY2(Erlang, is_function, fun erlang:list_to_binary/1, 1),
+ true = ?APPLY2(Erlang, is_function, fun() -> ok end, 0),
+ false = ?APPLY2(Erlang, is_function, blurf, 0),
+
+ apply(Mod, foo, []).
foo() ->
ok.
@@ -106,21 +106,21 @@ baz(A, B) ->
-define(FUNAPPLY2(F, A1, A2), (fun(Res) -> Res = F(A1, A2) end)(apply(F, [A1,A2]))).
fun_apply(Config) when is_list(Config) ->
- ?line Self = self(),
+ Self = self(),
- ?line Self = ?FUNAPPLY0(fun() -> self() end),
- ?line Self = ?FUNAPPLY0((id(fun() -> self() end))),
- ?line ok = ?FUNAPPLY0(fun ?MODULE:foo/0),
- ?line ok = ?FUNAPPLY0((id(fun ?MODULE:foo/0))),
+ Self = ?FUNAPPLY0(fun() -> self() end),
+ Self = ?FUNAPPLY0((id(fun() -> self() end))),
+ ok = ?FUNAPPLY0(fun ?MODULE:foo/0),
+ ok = ?FUNAPPLY0((id(fun ?MODULE:foo/0))),
- ?line -42 = ?FUNAPPLY1(fun(A) -> -A end, 42),
- ?line [x,yy] = ?FUNAPPLY1((id(fun(T) -> [x|T] end)), [yy]),
- ?line {[a|b]} = ?FUNAPPLY1(fun ?MODULE:bar/1, [a|b]),
- ?line {[a|b]} = ?FUNAPPLY1((id(fun ?MODULE:bar/1)), [a|b]),
+ -42 = ?FUNAPPLY1(fun(A) -> -A end, 42),
+ [x,yy] = ?FUNAPPLY1((id(fun(T) -> [x|T] end)), [yy]),
+ {[a|b]} = ?FUNAPPLY1(fun ?MODULE:bar/1, [a|b]),
+ {[a|b]} = ?FUNAPPLY1((id(fun ?MODULE:bar/1)), [a|b]),
- ?line {a,b} = ?FUNAPPLY2(fun(A, B) -> {A,B} end, a, b),
- ?line {a,[b]} = ?FUNAPPLY2((id(fun(A, B) -> {A,B} end)), a, [b]),
- ?line {42,{a}} = ?FUNAPPLY2((id(fun ?MODULE:baz/2)), 42, {a}),
+ {a,b} = ?FUNAPPLY2(fun(A, B) -> {A,B} end, a, b),
+ {a,[b]} = ?FUNAPPLY2((id(fun(A, B) -> {A,B} end)), a, [b]),
+ {42,{a}} = ?FUNAPPLY2((id(fun ?MODULE:baz/2)), 42, {a}),
ok.
diff --git a/lib/compiler/test/beam_block_SUITE.erl b/lib/compiler/test/beam_block_SUITE.erl
new file mode 100644
index 0000000000..55d5f2dbe8
--- /dev/null
+++ b/lib/compiler/test/beam_block_SUITE.erl
@@ -0,0 +1,244 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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(beam_block_SUITE).
+
+-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ get_map_elements/1,otp_7345/1,move_opt_across_gc_bif/1,
+ erl_202/1,repro/1]).
+
+%% The only test for the following functions is that
+%% the code compiles and is accepted by beam_validator.
+-export([encode_wildcards3/4,find_operands/4]).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ test_lib:recompile(?MODULE),
+ [{group,p}].
+
+groups() ->
+ [{p,[parallel],
+ [get_map_elements,
+ otp_7345,
+ move_opt_across_gc_bif,
+ erl_202,
+ repro
+ ]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+get_map_elements(_Config) ->
+ [{pred,var}] = get_map_elements([{pred,var}], #{}, []),
+ [{pred,var}] = get_map_elements([{pred,var}], #{pred=>[]}, []),
+ acc = get_map_elements([], #{pred=>[]}, acc),
+ ok.
+
+get_map_elements([{Pred,Var}|Left], Map, Acc) ->
+ case Map of
+ #{Var := List} ->
+ case lists:keyfind(Pred, 1, List) of
+ false ->
+ get_map_elements(Left, Map, [{Pred,Var}|Acc])
+ end;
+ #{} ->
+ get_map_elements(Left, Map, [{Pred,Var}|Acc])
+ end;
+get_map_elements([], _Map, Acc) ->
+ Acc.
+
+%% The following code
+%%
+%% {get_list,{x,2},{x,0},{x,1}}.
+%% {gc_bif,length,{f,0},1,[{x,0}],{x,0}}.
+%% {move,{x,0},{x,1}}.
+%%
+%% was incorrectly optimized to
+%%
+%% {get_list,{x,2},{x,0},{y,0}}.
+%% {gc_bif,length,{f,0},3,[{x,0}],{x,1}}.
+%%
+%% because beam_block:is_transparent({x,1},
+%% {gc_bif,length,{f,0},3,[{x,0}],{x,1}}
+%% incorrectly returned true.
+
+-record(contextId,{cid,device_type,contextRef}).
+-record(dpRef,{cid,tlli,ms_device_context_id}).
+-record(qosProfileBssgp,{peak_bit_rate_msb,
+ peak_bit_rate_lsb,
+ t_a_precedence}).
+-record(llUnitdataReq,{sapi,
+ l3_pdu_length,
+ pdu_life}).
+-record(ptmsi,{value}).
+
+otp_7345(_Config) ->
+ #llUnitdataReq{l3_pdu_length=3,pdu_life=4} =
+ otp_7345(#contextId{}, 0, [[1,2,3],4,5]).
+
+
+otp_7345(ObjRef, _RdEnv, Args) ->
+ Cid = ObjRef#contextId.cid,
+ _ = #dpRef{cid = Cid,
+ ms_device_context_id = cid_id,
+ tlli = #ptmsi{value = 0}},
+ _ = #qosProfileBssgp{peak_bit_rate_msb = 0,
+ peak_bit_rate_lsb = 80,
+ t_a_precedence = 49},
+ [Cpdu|_] = Args,
+ LlUnitdataReq =
+ #llUnitdataReq{sapi = 7,
+ l3_pdu_length = length(Cpdu),
+ pdu_life =
+ id(42)
+ div
+ 10},
+ id(LlUnitdataReq).
+
+
+%% Doing move optimizations across GC bifs are in general not safe.
+move_opt_across_gc_bif(_Config) ->
+ [0,true,1] = positive(speaking),
+ ok.
+
+positive(speaking) ->
+ try
+ Positive = 0,
+ [+Positive, case Positive of _ -> true end, paris([], Positive)]
+ after
+ mailing
+ end.
+
+paris([], P) -> P + 1.
+
+
+%% See https://bugs.erlang.org/browse/ERL-202.
+%% Test that move_allocates/1 in beam_block doesn't move allocate
+%% when it would not be safe.
+
+-record(erl_202_r1, {y}).
+-record(erl_202_r2, {x}).
+
+erl_202(_Config) ->
+ Ref = make_ref(),
+ Ref = erl_202({{1,2},Ref}, 42),
+
+ {Ref} = erl_202({7,8}, #erl_202_r1{y=#erl_202_r2{x=Ref}}),
+
+ ok.
+
+erl_202({{_, _},X}, _) ->
+ X;
+erl_202({_, _}, #erl_202_r1{y=R2}) ->
+ {R2#erl_202_r2.x}.
+
+%% See https://bugs.erlang.org/browse/ERL-266.
+%% Instructions with failure labels are not safe to include
+%% in a block. Including get_map_elements in a block would
+%% lead to unsafe code.
+
+repro(_Config) ->
+ [] = maps:to_list(repro([], #{}, #{})),
+ [{tmp1,n}] = maps:to_list(repro([{tmp1,0}], #{}, #{})),
+ [{tmp1,name}] = maps:to_list(repro([{tmp1,0}], #{}, #{0=>name})),
+ ok.
+
+repro([], TempNames, _Slots) ->
+ TempNames;
+repro([{Temp, Slot}|Xs], TempNames, Slots0) ->
+ {Name, Slots} =
+ case Slots0 of
+ #{Slot := Name0} -> {Name0, Slots0};
+ #{} -> {n, Slots0#{Slot => n}}
+ end,
+ repro(Xs, TempNames#{Temp => Name}, Slots).
+
+%%%
+%%% The only test of the following code is that it compiles.
+%%%
+
+%% Slightly simplifed from megaco_binary_term_id_gen.
+%% beam_block failed to note that the {gc_bif,'-'...} instruction could
+%% fail, and that therefore {y,0} need to be initialized.
+%% {allocate,8,6}.
+%% %% {init,{y,0}} needed here.
+%% {get_list,{x,1},{x,6},{x,7}}.
+%% {'catch',{y,7},{f,3}}.
+%% {move,{x,4},{y,1}}.
+%% {move,{x,3},{y,2}}.
+%% {move,{x,2},{y,3}}.
+%% {move,{x,5},{y,4}}.
+%% {move,{x,7},{y,5}}.
+%% {move,{x,6},{y,6}}.
+%% {gc_bif,'-',{f,0},8,[{x,3},{x,6}],{x,0}}.
+%% {move,{x,0},{y,0}}.
+
+encode_wildcards3([],[],_,_) -> [];
+encode_wildcards3([Level|Levels],[BitsInLevel|BitsRest],LevelNo,TotSize) ->
+ case (catch ?MODULE:encode_wildcard(Level,BitsInLevel,TotSize-BitsInLevel,
+ length(Levels))) of
+ {'EXIT',{Reason,Info}} ->
+ exit({Reason,{LevelNo,Info}});
+
+ no_wildcard ->
+ encode_wildcards3(Levels,BitsRest,LevelNo+1,TotSize-BitsInLevel);
+
+ {level,Wl} ->
+ [Wl|
+ encode_wildcards3(Levels,BitsRest,LevelNo+1,TotSize-BitsInLevel)];
+
+ {recursive,Wr} ->
+ [Wr]
+ end.
+
+%% Slightly simplified code from hipe_rtl_ssapre.
+%% beam_block used to do the following incorrect optimization:
+%%
+%% {gc_bif,length,{f,0},1,[{x,0}],{x,3}}.
+%% ^^^^^ Was {x,0} - changing to {x,3} is not safe.
+%% {gc_bif,'+',{f,0},0,[{y,2},{integer,1}],{x,0}}.
+%% ^^^ Only one register live
+%% . . .
+%% {call_last,4,{f,2},4}. %% beam_validator noted that {x,3} wasn't live.
+
+find_operands(Cfg,XsiGraph,[],_Count) ->
+ {Cfg,XsiGraph};
+find_operands(Cfg,XsiGraph,ActiveList,Count) ->
+ {NewCfg,TempActiveList}=?MODULE:find_operands_for_active_list(Cfg,XsiGraph,
+ ActiveList,[]),
+ NewActiveList=lists:reverse(TempActiveList),
+ [Count+1, length(NewActiveList), length(digraph:vertices(XsiGraph))],
+ find_operands(NewCfg,XsiGraph,NewActiveList,Count+1).
+
+%%%
+%%% Common functions.
+%%%
+
+id(I) -> I.
diff --git a/lib/compiler/test/beam_disasm_SUITE.erl b/lib/compiler/test/beam_disasm_SUITE.erl
index 4dd92e7ed9..e2ec030d31 100644
--- a/lib/compiler/test/beam_disasm_SUITE.erl
+++ b/lib/compiler/test/beam_disasm_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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.
@@ -19,7 +19,7 @@
%%
-module(beam_disasm_SUITE).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
@@ -46,21 +46,20 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-stripped(doc) ->
- ["Check that stripped beam files can be disassembled"];
+%% Check that stripped beam files can be disassembled.
stripped(Config) when is_list(Config) ->
- ?line PrivDir = ?config(priv_dir, Config),
- ?line SrcName = filename:join(PrivDir, "tmp.erl"),
- ?line BeamName = filename:join(PrivDir, "tmp.beam"),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ SrcName = filename:join(PrivDir, "tmp.erl"),
+ BeamName = filename:join(PrivDir, "tmp.beam"),
Prog = <<"-module(tmp).\n-export([tmp/0]).\ntmp()->ok.\n">>,
- ?line ok = file:write_file(SrcName, Prog),
- ?line {ok, tmp} =
+ ok = file:write_file(SrcName, Prog),
+ {ok, tmp} =
compile:file(SrcName, [{outdir, PrivDir}]),
- ?line {beam_file, tmp, _, Attr, CompileInfo, [_|_]} =
+ {beam_file, tmp, _, Attr, CompileInfo, [_|_]} =
beam_disasm:file(BeamName),
- ?line true = is_list(Attr),
- ?line true = is_list(CompileInfo),
- ?line {ok, {tmp, _}} = beam_lib:strip(BeamName),
- ?line {beam_file, tmp, _, [], [], [_|_]} =
+ true = is_list(Attr),
+ true = is_list(CompileInfo),
+ {ok, {tmp, _}} = beam_lib:strip(BeamName),
+ {beam_file, tmp, _, [], [], [_|_]} =
beam_disasm:file(BeamName),
ok.
diff --git a/lib/compiler/test/beam_except_SUITE.erl b/lib/compiler/test/beam_except_SUITE.erl
index afacb939d1..47367d6eab 100644
--- a/lib/compiler/test/beam_except_SUITE.erl
+++ b/lib/compiler/test/beam_except_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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.
@@ -21,15 +21,18 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- coverage/1]).
+ multiple_allocs/1,coverage/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [coverage].
+ test_lib:recompile(?MODULE),
+ [{group,p}].
groups() ->
- [].
+ [{p,[parallel],
+ [multiple_allocs,
+ coverage]}].
init_per_suite(Config) ->
Config.
@@ -43,6 +46,23 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+multiple_allocs(_Config) ->
+ {'EXIT',{{badmatch,#{true:=[p]}},_}} =
+ (catch could(pda, 0.0, {false,true}, {p})),
+ {'EXIT',{function_clause,_}} = (catch place(lee)),
+ {'EXIT',{{badmatch,wanted},_}} = (catch conditions()),
+
+ ok.
+
+could(Coupons = pda, Favorite = _pleasure = 0.0, {_, true}, {Presents}) ->
+ (0 = true) = #{true => [Presents]}.
+
+place(lee) ->
+ (pregnancy = presentations) = [hours | [purchase || _ <- 0]] + wine.
+
+conditions() ->
+ (talking = going) = storage + [large = wanted].
+
coverage(_) ->
File = {file,"fake.erl"},
ok = fc(a),
diff --git a/lib/compiler/test/beam_jump_SUITE.erl b/lib/compiler/test/beam_jump_SUITE.erl
new file mode 100644
index 0000000000..088f63606c
--- /dev/null
+++ b/lib/compiler/test/beam_jump_SUITE.erl
@@ -0,0 +1,74 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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(beam_jump_SUITE).
+
+-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ undefined_label/1,ambiguous_catch_try_state/1]).
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ test_lib:recompile(?MODULE),
+ [{group,p}].
+
+groups() ->
+ [{p,[parallel],
+ [undefined_label,
+ ambiguous_catch_try_state
+ ]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+undefined_label(_Config) ->
+ {'EXIT',{function_clause,_}} = (catch flights(0, [], [])),
+ ok.
+
+%% Would lose a label when compiled with no_copt.
+
+flights(0, [], []) when [], 0; 0.0, [], false ->
+ clark;
+flights(_, Reproduction, introduction) when false, Reproduction ->
+ responsible.
+
+%% [ERL-209] beam_jump would share 'catch' blocks, causing an
+%% ambiguous_catch_try_state error in beam_validator.
+
+ambiguous_catch_try_state(_Config) ->
+ {{'EXIT',{{case_clause,song},_}},{'EXIT',{{case_clause,song},_}}} =
+ checks(42),
+ ok.
+
+river() -> song.
+
+checks(Wanted) ->
+ %% Must be one line to cause the unsafe optimization.
+ {catch case river() of sheet -> begin +Wanted, if "da" -> Wanted end end end, catch case river() of sheet -> begin + Wanted, if "da" -> Wanted end end end}.
diff --git a/lib/compiler/test/beam_reorder_SUITE.erl b/lib/compiler/test/beam_reorder_SUITE.erl
new file mode 100644
index 0000000000..27ce51eec3
--- /dev/null
+++ b/lib/compiler/test/beam_reorder_SUITE.erl
@@ -0,0 +1,81 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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(beam_reorder_SUITE).
+
+-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ alloc/1,confused_beam_validator/1]).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ test_lib:recompile(?MODULE),
+ [{group,p}].
+
+groups() ->
+ [{p,[parallel],
+ [alloc,
+ confused_beam_validator
+ ]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+-record(alloc, {version}).
+
+alloc(_Config) ->
+ {ok,42} = alloc_a(1, 2, #alloc{version=42}),
+ {a,b,c} = alloc_b(1, 2, #alloc{version={a,b,c}}),
+ ok.
+
+alloc_a(_U1, _U2, R) ->
+ V = R#alloc.version,
+ Res = id({ok,V}),
+ _ = id(0),
+ Res.
+
+alloc_b(_U1, _U2, R) ->
+ V = R#alloc.version,
+ Res = id(V),
+ _ = id(0),
+ Res.
+
+confused_beam_validator(_Config) ->
+ {'EXIT',{{badmap,{any}},_}} = (catch efficient({any})),
+ ok.
+
+efficient({Var}=God) ->
+ id(God#{}),
+ catch
+ receive _ ->
+ Var
+ end.
+
+id(I) ->
+ I.
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
new file mode 100644
index 0000000000..86146c614f
--- /dev/null
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -0,0 +1,176 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015-2017. 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(beam_type_SUITE).
+
+-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ integers/1,coverage/1,booleans/1,setelement/1,cons/1,
+ tuple/1,record_float/1,binary_float/1,float_compare/1]).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ test_lib:recompile(?MODULE),
+ [{group,p}].
+
+groups() ->
+ [{p,[parallel],
+ [integers,
+ coverage,
+ booleans,
+ setelement,
+ cons,
+ tuple,
+ record_float,
+ binary_float,
+ float_compare
+ ]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+integers(_Config) ->
+ a = do_integers_1(2#11000),
+ b = do_integers_1(2#11001),
+
+ a = do_integers_2(<<0:1>>),
+ {'EXIT',{{case_clause,-1},_}} = (catch do_integers_2(<<1:1>>)),
+
+ college = do_integers_3(),
+
+ ok.
+
+do_integers_1(B0) ->
+ B = B0 band 1,
+ case B band 15 of
+ 0 -> a;
+ 1 -> b
+ end.
+
+do_integers_2(Bin) ->
+ <<B:1/signed>> = Bin,
+ case B of
+ 0 -> a;
+ 1 -> b
+ end.
+
+do_integers_3() ->
+ case try 0 after [] end of
+ 0 -> college;
+ 1 -> 0
+ end.
+
+coverage(_Config) ->
+ {'EXIT',{badarith,_}} = (catch id(1) bsl 0.5),
+ {'EXIT',{badarith,_}} = (catch id(2.0) bsl 2),
+ {'EXIT',{badarith,_}} = (catch a + 0.5),
+ {'EXIT',{badarith,_}} = (catch 2.0 * b),
+
+ {'EXIT',{badarith,_}} = (catch id(42.0) / (1 bsl 2000)),
+
+ id(id(42) band 387439739874298734983787934283479243879),
+ id(-1 band id(13)),
+
+ ok.
+
+booleans(_Config) ->
+ {'EXIT',{{case_clause,_},_}} = (catch do_booleans(42)),
+ ok.
+
+do_booleans(B) ->
+ case is_integer(B) of
+ yes -> yes;
+ no -> no
+ end.
+
+setelement(_Config) ->
+ T0 = id({a,42}),
+ {a,_} = T0,
+ {b,_} = setelement(1, T0, b),
+ ok.
+
+cons(_Config) ->
+ [did] = cons(assigned, did),
+ ok.
+
+cons(assigned, Instrument) ->
+ [Instrument] = [did].
+
+tuple(_Config) ->
+ {'EXIT',{{badmatch,{necessary}},_}} = (catch do_tuple()),
+ ok.
+
+do_tuple() ->
+ {0, _} = {necessary}.
+
+-record(x, {a}).
+
+record_float(_Config) ->
+ 17.0 = record_float(#x{a={0}}, 1700),
+ 23.0 = record_float(#x{a={0}}, 2300.0),
+ {'EXIT',{if_clause,_}} = (catch record_float(#x{a={1}}, 88)),
+ {'EXIT',{if_clause,_}} = (catch record_float(#x{a={}}, 88)),
+ {'EXIT',{if_clause,_}} = (catch record_float(#x{}, 88)),
+ ok.
+
+record_float(R, N0) ->
+ N = N0 / 100,
+ if element(1, R#x.a) =:= 0 ->
+ N
+ end.
+
+binary_float(_Config) ->
+ <<-1/float>> = binary_negate_float(<<1/float>>),
+ ok.
+
+binary_negate_float(<<Float/float>>) ->
+ <<-Float/float>>.
+
+float_compare(_Config) ->
+ false = do_float_compare(-42.0),
+ false = do_float_compare(-42),
+ false = do_float_compare(0),
+ false = do_float_compare(0.0),
+ true = do_float_compare(42),
+ true = do_float_compare(42.0),
+ ok.
+
+do_float_compare(X) ->
+ %% ERL-433: Used to fail before OTP 20. Was accidentally fixed
+ %% in OTP 20. Add a test case to ensure it stays fixed.
+
+ Y = X + 1.0,
+ case X > 0 of
+ T when (T =:= nil) or (T =:= false) -> T;
+ _T -> Y > 0
+ end.
+
+
+id(I) ->
+ I.
diff --git a/lib/compiler/test/beam_utils_SUITE.erl b/lib/compiler/test/beam_utils_SUITE.erl
index 70c00f163c..710cb050d4 100644
--- a/lib/compiler/test/beam_utils_SUITE.erl
+++ b/lib/compiler/test/beam_utils_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,7 +23,8 @@
init_per_group/2,end_per_group/2,
apply_fun/1,apply_mf/1,bs_init/1,bs_save/1,
is_not_killed/1,is_not_used_at/1,
- select/1,y_catch/1]).
+ select/1,y_catch/1,otp_8949_b/1,liveopt/1,coverage/1,
+ y_registers/1]).
-export([id/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -41,7 +42,11 @@ groups() ->
is_not_killed,
is_not_used_at,
select,
- y_catch
+ y_catch,
+ otp_8949_b,
+ liveopt,
+ coverage,
+ y_registers
]}].
init_per_suite(Config) ->
@@ -232,6 +237,144 @@ do_y_catch_1(<<_,_/binary>>, _) ->
do_y_catch_2(_) -> {a,b,c}.
+otp_8949_b(_Config) ->
+ self() ! something,
+ value = otp_8949_b([], false),
+ {'EXIT',_} = (catch otp_8949_b([], true)),
+ ok.
+
+%% Would cause an endless loop in beam_utils.
+otp_8949_b(A, B) ->
+ Var = id(value),
+ if
+ A == [], B == false ->
+ ok
+ end,
+ receive
+ something ->
+ id(Var)
+ end.
+
+-record(alarmInfo, {type,cause,origin}).
+
+liveopt(_Config) ->
+ F = liveopt_fun(42, pebkac, user),
+ void = F(42, #alarmInfo{type=sctp,cause=pebkac,origin=user}),
+
+
+ A = {#alarmInfo{cause = {abc, def}}, ghi},
+ A = liveopt_guard_bif(A),
+
+ B = {#alarmInfo{cause = {abc}}, def},
+ {#alarmInfo{cause = {{abc}}}, def} = liveopt_guard_bif(B),
+
+ ok.
+
+liveopt_fun(Peer, Cause, Origin) ->
+ fun(PeerNo, AlarmInfo)
+ when PeerNo == Peer andalso
+ AlarmInfo == #alarmInfo{type=sctp,
+ cause=Cause,
+ origin=Origin} ->
+ void
+ end.
+
+liveopt_guard_bif({#alarmInfo{cause=F}=R, X}=A) ->
+ %% ERIERL-48
+ if
+ is_tuple(F), tuple_size(F) == 2 -> A;
+ true ->
+ R2 = R#alarmInfo{cause={F}},
+ {R2,X}
+ end.
+
+%% Thanks to QuickCheck.
+coverage(_Config) ->
+ 42+7 = merchant([[],7,false]),
+
+ {'EXIT',{{try_clause,0},_}} = (catch resulting([0], stone)),
+ 0.0 = resulting([true], stone),
+
+ {'EXIT',{if_clause,_}} = (catch clinic(false)),
+ {'EXIT',{{try_clause,"trials"},_}} = (catch clinic(true)),
+
+ {'EXIT',{function_clause,_}} = (catch town(overall, {{abc},alcohol})),
+
+ self() ! junk_message,
+ {"url",#{true:="url"}} = appointment(#{"resolution" => "url"}),
+
+ ok.
+
+%% Cover check_liveness/3.
+merchant([Merchant, Laws, Electric]) ->
+ id(42),
+ oklahoma([[] || 0 <- Merchant],
+ if true; Electric -> Laws end) + 42.
+oklahoma([], Int) -> Int.
+
+town(overall, {{If}, Healing = alcohol})
+ when Healing#{[] => Healing}; include ->
+ [If || Healing <- awareness].
+
+%% Cover is_reg_used_at/3.
+resulting([Conservation], stone) ->
+ try 0 of
+ Conservation when Conservation -> Conservation;
+ _ when Conservation; 0 -> 0.0
+ after
+ Conservation
+ end.
+
+%% Cover is_reg_used_at_1/3.
+clinic(Damage) ->
+ if
+ Damage ->
+ try "trials" of Damage when Damage -> Damage catch true -> [] end
+ end,
+ carefully.
+
+y_registers(_Config) ->
+ {'EXIT',{{badfun,0},_}} = (catch economic(0.0, jim)),
+ {'EXIT',{{badmatch,apartments},_}} = (catch louisiana()),
+ {a,b} = (boxes(true))({a,b}),
+ {'EXIT',{{case_clause,webmaster},_}} = (catch yellow(true)),
+ ok.
+
+economic(0.0 = Serves, Existence) ->
+ case Serves of
+ Serves -> 0
+ end,
+ Existence = jim,
+ 0(),
+ Serves,
+ Existence.
+
+louisiana() ->
+ {catch necessarily,
+ try
+ [] == reg,
+ true = apartments
+ catch [] -> barbara
+ end}.
+
+boxes(Call) ->
+ case Call of
+ Call -> approval
+ end,
+ Call,
+ fun id/1.
+
+yellow(Hill) ->
+ case webmaster of
+ station -> eyes; Hill ->
+ "under"
+ end,
+ Hill,
+ id(42).
+
+do(A, B) -> {A,B}.
+appointment(#{"resolution" := Url}) ->
+ do(receive _ -> Url end, #{true => Url}).
%% The identity function.
id(I) -> I.
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index 69391b15eb..c23514b36b 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. 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.
@@ -32,20 +32,20 @@
bad_bin_match/1,bad_dsetel/1,
state_after_fault_in_catch/1,no_exception_in_catch/1,
undef_label/1,illegal_instruction/1,failing_gc_guard_bif/1,
- map_field_lists/1]).
+ map_field_lists/1,cover_bin_opt/1,
+ val_dsetel/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = test_server:timetrap(?t:minutes(10)),
- [{watchdog,Dog}|Config].
+ Config.
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
ok.
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,10}}].
all() ->
test_lib:recompile(?MODULE),
@@ -61,7 +61,7 @@ groups() ->
freg_state,bad_bin_match,bad_dsetel,
state_after_fault_in_catch,no_exception_in_catch,
undef_label,illegal_instruction,failing_gc_guard_bif,
- map_field_lists]}].
+ map_field_lists,cover_bin_opt,val_dsetel]}].
init_per_suite(Config) ->
Config.
@@ -78,7 +78,7 @@ end_per_group(_GroupName, Config) ->
compiler_bug(Config) when is_list(Config) ->
%% Check that the compiler returns an error if we try to
%% assemble one of the bad '.S' files.
- Data = ?config(data_dir, Config),
+ Data = proplists:get_value(data_dir, Config),
File = filename:join(Data, "compiler_bug"),
error = compile:file(File, [from_asm,report_errors,time]),
@@ -93,43 +93,41 @@ compiler_bug(Config) when is_list(Config) ->
%% The following code is stupid but it should compile.
stupid_but_valid(Config) when is_list(Config) ->
AnAtom = nisse,
- ?line try setelement(5, setelement(6, AnAtom, value), another_value) of
- Term -> ?line ?t:fail({what_happened,Term})
- catch
- error:badarg -> ok
- end,
+ try setelement(5, setelement(6, AnAtom, value), another_value) of
+ Term -> ct:fail({what_happened,Term})
+ catch
+ error:badarg -> ok
+ end,
ok.
xrange(Config) when is_list(Config) ->
Errors = do_val(xrange, Config),
- ?line
- [{{t,sum_1,2},
- {{bif,'+',{f,0},[{x,-1},{x,1}],{x,0}},4,
- {uninitialized_reg,{x,-1}}}},
- {{t,sum_2,2},
- {{bif,'+',{f,0},[{x,0},{x,1024}],{x,0}},4,
- {uninitialized_reg,{x,1024}}}},
- {{t,sum_3,2},
- {{bif,'+',{f,0},[{x,0},{x,1}],{x,-1}},4,
- {invalid_store,{x,-1},number}}},
- {{t,sum_4,2},
- {{bif,'+',{f,0},[{x,0},{x,1}],{x,1024}},4,limit}}] = Errors,
+ [{{t,sum_1,2},
+ {{bif,'+',{f,0},[{x,-1},{x,1}],{x,0}},4,
+ {uninitialized_reg,{x,-1}}}},
+ {{t,sum_2,2},
+ {{bif,'+',{f,0},[{x,0},{x,1023}],{x,0}},4,
+ {uninitialized_reg,{x,1023}}}},
+ {{t,sum_3,2},
+ {{bif,'+',{f,0},[{x,0},{x,1}],{x,-1}},4,
+ {invalid_store,{x,-1},number}}},
+ {{t,sum_4,2},
+ {{bif,'+',{f,0},[{x,0},{x,1}],{x,1023}},4,limit}}] = Errors,
ok.
yrange(Config) when is_list(Config) ->
Errors = do_val(yrange, Config),
- ?line
- [{{t,sum_1,2},
- {{move,{x,1},{y,-1}},5,
- {invalid_store,{y,-1},term}}},
- {{t,sum_2,2},
- {{bif,'+',{f,0},[{x,0},{y,1024}],{x,0}},7,
- {uninitialized_reg,{y,1024}}}},
- {{t,sum_3,2},
- {{move,{x,1},{y,1024}},5,limit}},
- {{t,sum_4,2},
- {{move,{x,1},{y,-1}},5,
- {invalid_store,{y,-1},term}}}] = Errors,
+ [{{t,sum_1,2},
+ {{move,{x,1},{y,-1}},5,
+ {invalid_store,{y,-1},term}}},
+ {{t,sum_2,2},
+ {{bif,'+',{f,0},[{x,0},{y,1024}],{x,0}},7,
+ {uninitialized_reg,{y,1024}}}},
+ {{t,sum_3,2},
+ {{move,{x,1},{y,1024}},5,limit}},
+ {{t,sum_4,2},
+ {{move,{x,1},{y,-1}},5,
+ {invalid_store,{y,-1},term}}}] = Errors,
ok.
stack(Config) when is_list(Config) ->
@@ -163,25 +161,23 @@ merge_undefined(Config) when is_list(Config) ->
uninit(Config) when is_list(Config) ->
Errors = do_val(uninit, Config),
- ?line
- [{{t,sum_1,2},
- {{move,{y,0},{x,0}},5,{uninitialized_reg,{y,0}}}},
- {{t,sum_2,2},
- {{call,1,{f,8}},5,{uninitialized_reg,{y,0}}}},
- {{t,sum_3,2},
- {{bif,'+',{f,0},[{x,0},{y,0}],{x,0}},
- 6,
- {unassigned,{y,0}}}}] = Errors,
+ [{{t,sum_1,2},
+ {{move,{y,0},{x,0}},5,{uninitialized_reg,{y,0}}}},
+ {{t,sum_2,2},
+ {{call,1,{f,8}},5,{uninitialized_reg,{y,0}}}},
+ {{t,sum_3,2},
+ {{bif,'+',{f,0},[{x,0},{y,0}],{x,0}},
+ 6,
+ {unassigned,{y,0}}}}] = Errors,
ok.
unsafe_catch(Config) when is_list(Config) ->
Errors = do_val(unsafe_catch, Config),
- ?line
- [{{t,small,2},
- {{bs_put_integer,{f,0},{integer,16},1,
- {field_flags,[unsigned,big]},{y,0}},
- 20,
- {unassigned,{y,0}}}}] = Errors,
+ [{{t,small,2},
+ {{bs_put_integer,{f,0},{integer,16},1,
+ {field_flags,[unsigned,big]},{y,0}},
+ 20,
+ {unassigned,{y,0}}}}] = Errors,
ok.
dead_code(Config) when is_list(Config) ->
@@ -190,16 +186,14 @@ dead_code(Config) when is_list(Config) ->
overwrite_catchtag(Config) when is_list(Config) ->
Errors = do_val(overwrite_catchtag, Config),
- ?line
- [{{overwrite_catchtag,foo,1},
- {{move,{x,0},{y,0}},6,{catchtag,_}}}] = Errors,
+ [{{overwrite_catchtag,foo,1},
+ {{move,{x,0},{y,0}},6,{catchtag,_}}}] = Errors,
ok.
overwrite_trytag(Config) when is_list(Config) ->
Errors = do_val(overwrite_trytag, Config),
- ?line
- [{{overwrite_trytag,foo,1},
- {{kill,{y,2}},8,{trytag,_}}}] = Errors,
+ [{{overwrite_trytag,foo,1},
+ {{kill,{y,2}},8,{trytag,_}}}] = Errors,
ok.
accessing_tags(Config) when is_list(Config) ->
@@ -231,82 +225,77 @@ bad_catch_try(Config) when is_list(Config) ->
cons_guard(Config) when is_list(Config) ->
Errors = do_val(cons, Config),
- ?line
- [{{cons,foo,1},
- {{get_list,{x,0},{x,1},{x,2}},
- 5,
- {bad_type,{needed,cons},{actual,term}}}}] = Errors,
+ [{{cons,foo,1},
+ {{get_list,{x,0},{x,1},{x,2}},
+ 5,
+ {bad_type,{needed,cons},{actual,term}}}}] = Errors,
ok.
freg_range(Config) when is_list(Config) ->
Errors = do_val(freg_range, Config),
- ?line
- [{{t,sum_1,2},
- {{bif,fadd,{f,0},[{fr,-1},{fr,1}],{fr,0}},
- 5,
- {bad_source,{fr,-1}}}},
- {{t,sum_2,2},
- {{bif,fadd,{f,0},[{fr,0},{fr,1024}],{fr,0}},
- 6,
- {uninitialized_reg,{fr,1024}}}},
- {{t,sum_3,2},
- {{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,-1}},
- 7,
- {bad_target,{fr,-1}}}},
- {{t,sum_4,2},
- {{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,1024}},
- 7,
- limit}}] = Errors,
+ [{{t,sum_1,2},
+ {{bif,fadd,{f,0},[{fr,-1},{fr,1}],{fr,0}},
+ 5,
+ {bad_source,{fr,-1}}}},
+ {{t,sum_2,2},
+ {{bif,fadd,{f,0},[{fr,0},{fr,1024}],{fr,0}},
+ 6,
+ {uninitialized_reg,{fr,1024}}}},
+ {{t,sum_3,2},
+ {{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,-1}},
+ 7,
+ {bad_target,{fr,-1}}}},
+ {{t,sum_4,2},
+ {{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,1024}},
+ 7,
+ limit}}] = Errors,
ok.
freg_uninit(Config) when is_list(Config) ->
Errors = do_val(freg_uninit, Config),
- ?line
- [{{t,sum_1,2},
- {{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,0}},
- 6,
- {uninitialized_reg,{fr,1}}}},
- {{t,sum_2,2},
- {{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,0}},
- 9,
- {uninitialized_reg,{fr,0}}}}] = Errors,
+ [{{t,sum_1,2},
+ {{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,0}},
+ 6,
+ {uninitialized_reg,{fr,1}}}},
+ {{t,sum_2,2},
+ {{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,0}},
+ 9,
+ {uninitialized_reg,{fr,0}}}}] = Errors,
ok.
freg_state(Config) when is_list(Config) ->
Errors = do_val(freg_state, Config),
- ?line
- [{{t,sum_1,2},
- {{bif,fmul,{f,0},[{fr,0},{fr,1}],{fr,0}},
- 6,
- {bad_floating_point_state,undefined}}},
- {{t,sum_2,2},
- {{fmove,{fr,0},{x,0}},
- 8,
- {bad_floating_point_state,cleared}}},
- {{t,sum_3,2},
- {{bif,'-',{f,0},[{x,1},{x,0}],{x,1}},
- 8,
- {unsafe_instruction,{float_error_state,cleared}}}},
- {{t,sum_4,2},
- {{fcheckerror,{f,0}},
- 4,
- {bad_floating_point_state,undefined}}},
- {{t,sum_5,2},
- {fclearerror,5,{bad_floating_point_state,cleared}}}] = Errors,
+ [{{t,sum_1,2},
+ {{bif,fmul,{f,0},[{fr,0},{fr,1}],{fr,0}},
+ 6,
+ {bad_floating_point_state,undefined}}},
+ {{t,sum_2,2},
+ {{fmove,{fr,0},{x,0}},
+ 8,
+ {bad_floating_point_state,cleared}}},
+ {{t,sum_3,2},
+ {{bif,'-',{f,0},[{x,1},{x,0}],{x,1}},
+ 8,
+ {unsafe_instruction,{float_error_state,cleared}}}},
+ {{t,sum_4,2},
+ {{fcheckerror,{f,0}},
+ 4,
+ {bad_floating_point_state,undefined}}},
+ {{t,sum_5,2},
+ {fclearerror,5,{bad_floating_point_state,cleared}}}] = Errors,
ok.
bad_bin_match(Config) when is_list(Config) ->
- [{{t,t,1},{return,5,{match_context,{x,0}}}}] =
- do_val(bad_bin_match, Config),
- ok.
+ [{{t,t,1},{return,5,{match_context,{x,0}}}}] =
+ do_val(bad_bin_match, Config),
+ ok.
bad_dsetel(Config) when is_list(Config) ->
Errors = do_val(bad_dsetel, Config),
- ?line
- [{{t,t,1},
- {{set_tuple_element,{x,1},{x,0},1},
- 17,
- illegal_context_for_set_tuple_element}}] = Errors,
+ [{{t,t,1},
+ {{set_tuple_element,{x,1},{x,0},1},
+ 17,
+ illegal_context_for_set_tuple_element}}] = Errors,
ok.
state_after_fault_in_catch(Config) when is_list(Config) ->
@@ -324,7 +313,7 @@ state_after_fault_in_catch(Config) when is_list(Config) ->
no_exception_in_catch(Config) when is_list(Config) ->
Errors = do_val(no_exception_in_catch, Config),
[{{no_exception_in_catch,nested_of_1,4},
- {{move,{x,3},{x,0}},88,{uninitialized_reg,{x,3}}}}] = Errors,
+ {{move,{x,3},{x,0}},87,{uninitialized_reg,{x,3}}}}] = Errors,
ok.
undef_label(Config) when is_list(Config) ->
@@ -382,9 +371,9 @@ illegal_instruction(Config) when is_list(Config) ->
%% (Thanks to Kiran Khaladkar.)
%%
failing_gc_guard_bif(Config) when is_list(Config) ->
- ?line ok = process_request(lists:seq(1, 36)),
- ?line error = process_request([]),
- ?line error = process_request(not_a_list),
+ ok = process_request(lists:seq(1, 36)),
+ error = process_request([]),
+ error = process_request(not_a_list),
ok.
process_request(ConfId) ->
@@ -418,10 +407,126 @@ map_field_lists(Config) ->
empty_field_list}}
] = Errors.
+%% Coverage and smoke test of beam_validator.
+cover_bin_opt(_Config) ->
+ Ms = [beam_utils_SUITE,
+ bs_match_SUITE,
+ bs_bincomp_SUITE,
+ bs_bit_binaries_SUITE,
+ bs_utf_SUITE],
+ test_lib:p_run(fun try_bin_opt/1, Ms),
+ ok.
+
+try_bin_opt(Mod) ->
+ try
+ do_bin_opt(Mod)
+ catch
+ Class:Error ->
+ io:format("~p: ~p ~p\n~p\n",
+ [Mod,Class,Error,erlang:get_stacktrace()]),
+ error
+ end.
+
+do_bin_opt(Mod) ->
+ Beam = code:which(Mod),
+ {ok,{Mod,[{abstract_code,
+ {raw_abstract_v1,Abstr}}]}} =
+ beam_lib:chunks(Beam, [abstract_code]),
+ {ok,Mod,Asm} = compile:forms(Abstr, ['S']),
+ do_bin_opt(Mod, Asm).
+
+do_bin_opt(Mod, Asm) ->
+ do_bin_opt(fun enable_bin_opt/1, Mod, Asm),
+ do_bin_opt(fun remove_bs_start_match/1, Mod, Asm),
+ do_bin_opt(fun remove_bs_save/1, Mod, Asm),
+ do_bin_opt(fun destroy_ctxt/1, Mod, Asm),
+ do_bin_opt(fun destroy_save_point/1, Mod, Asm),
+ ok.
+
+do_bin_opt(Transform, Mod, Asm0) ->
+ Asm = Transform(Asm0),
+ case compile:forms(Asm, [from_asm,no_postopt,return]) of
+ {ok,Mod,Code,_Warnings} when is_binary(Code) ->
+ ok;
+ {error,Errors0,_} ->
+ %% beam_validator must return errors, not simply crash,
+ %% when illegal code is found.
+ ModString = atom_to_list(Mod),
+ [{ModString,Errors}] = Errors0,
+ _ = [verify_bin_opt_error(E) || E <- Errors],
+ ok
+ end.
+
+verify_bin_opt_error({beam_validator,_}) ->
+ ok.
+
+enable_bin_opt(Module) ->
+ transform_is(fun enable_bin_opt_body/1, Module).
+
+enable_bin_opt_body([_,{'%',{no_bin_opt,_Reason,_Anno}}|Is]) ->
+ enable_bin_opt_body(Is);
+enable_bin_opt_body([I|Is]) ->
+ [I|enable_bin_opt_body(Is)];
+enable_bin_opt_body([]) ->
+ [].
+
+remove_bs_start_match(Module) ->
+ transform_remove(fun({test,bs_start_match2,_,_,_,_}) -> true;
+ (_) -> false
+ end, Module).
+
+remove_bs_save(Module) ->
+ transform_remove(fun({bs_save2,_,_}) -> true;
+ (_) -> false
+ end, Module).
+
+destroy_save_point(Module) ->
+ transform_i(fun do_destroy_save_point/1, Module).
+
+do_destroy_save_point({I,Ctx,_Point})
+ when I =:= bs_save2; I =:= bs_restore2 ->
+ {I,Ctx,42};
+do_destroy_save_point(I) ->
+ I.
+
+destroy_ctxt(Module) ->
+ transform_i(fun do_destroy_ctxt/1, Module).
+
+do_destroy_ctxt({bs_save2=I,Ctx,Point}) ->
+ {I,destroy_reg(Ctx),Point};
+do_destroy_ctxt({bs_restore2=I,Ctx,Point}) ->
+ {I,destroy_reg(Ctx),Point};
+do_destroy_ctxt({bs_context_to_binary=I,Ctx}) ->
+ {I,destroy_reg(Ctx)};
+do_destroy_ctxt(I) ->
+ I.
+
+destroy_reg({Tag,N}) ->
+ case rand:uniform() of
+ R when R < 0.6 ->
+ {Tag,N+1};
+ _ ->
+ {y,N+1}
+ end.
+
%%%-------------------------------------------------------------------------
+transform_remove(Remove, Module) ->
+ transform_is(fun(Is) -> [I || I <- Is, not Remove(I)] end, Module).
+
+transform_i(Transform, Module) ->
+ transform_is(fun(Is) -> [Transform(I) || I <- Is] end, Module).
+
+transform_is(Transform, {Mod,Exp,Imp,Fs0,Lc}) ->
+ Fs = [transform_is_1(Transform, F) || F <- Fs0],
+ {Mod,Exp,Imp,Fs,Lc}.
+
+transform_is_1(Transform, {function,N,A,E,Is0}) ->
+ Is = Transform(Is0),
+ {function,N,A,E,Is}.
+
do_val(Mod, Config) ->
- Data = ?config(data_dir, Config),
+ Data = proplists:get_value(data_dir, Config),
Base = atom_to_list(Mod),
File = filename:join(Data, Base),
case compile:file(File, [from_asm,no_postopt,return_errors]) of
@@ -442,3 +547,23 @@ beam_val(M) ->
_ = [io:put_chars(beam_validator:format_error(E)) ||
E <- Errors],
Errors.
+
+%%%-------------------------------------------------------------------------
+
+val_dsetel(_Config) ->
+ self() ! 13,
+ {'EXIT',{{try_clause,participating},_}} = (catch night(0)),
+ ok.
+
+night(Turned) ->
+ receive
+ 13 ->
+ try participating of engine -> 16 after false end
+ end,
+ %% The setelement/3 call is unreachable.
+ Turned(setelement(#{true => Turned},
+ participating(Turned, "suit", 40, []),
+ Turned < Turned)),
+ ok.
+
+participating(_, _, _, _) -> ok.
diff --git a/lib/compiler/test/beam_validator_SUITE_data/xrange.S b/lib/compiler/test/beam_validator_SUITE_data/xrange.S
index c6f20288f7..a76408dde3 100644
--- a/lib/compiler/test/beam_validator_SUITE_data/xrange.S
+++ b/lib/compiler/test/beam_validator_SUITE_data/xrange.S
@@ -20,7 +20,7 @@
{label,3}.
{func_info,{atom,t},{atom,sum_2},2}.
{label,4}.
- {bif,'+',{f,0},[{x,0},{x,1024}],{x,0}}.
+ {bif,'+',{f,0},[{x,0},{x,1023}],{x,0}}.
{'%live',1}.
return.
@@ -38,7 +38,7 @@
{label,7}.
{func_info,{atom,t},{atom,sum_4},2}.
{label,8}.
- {bif,'+',{f,0},[{x,0},{x,1}],{x,1024}}.
+ {bif,'+',{f,0},[{x,0},{x,1}],{x,1023}}.
{'%live',1}.
return.
diff --git a/lib/compiler/test/bif_SUITE.erl b/lib/compiler/test/bif_SUITE.erl
new file mode 100644
index 0000000000..bba2058f2f
--- /dev/null
+++ b/lib/compiler/test/bif_SUITE.erl
@@ -0,0 +1,122 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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(bif_SUITE).
+
+-include_lib("syntax_tools/include/merl.hrl").
+
+-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ beam_validator/1,trunc_and_friends/1,cover_safe_bifs/1]).
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ test_lib:recompile(?MODULE),
+ [{group,p}].
+
+groups() ->
+ [{p,[parallel],
+ [beam_validator,
+ trunc_and_friends,
+ cover_safe_bifs
+ ]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+%% Cover code in beam_validator.
+
+beam_validator(Config) ->
+ [false,Config] = food(Config),
+
+ true = is_number(42.0),
+ false = is_port(Config),
+
+ ok.
+
+food(Curriculum) ->
+ [try
+ is_bitstring(functions)
+ catch _ ->
+ 0
+ end, Curriculum].
+
+%% Test trunc/1, round/1, floor/1, ceil/1.
+trunc_and_friends(_Config) ->
+ Bifs = [trunc,round,floor,ceil],
+ Fs = trunc_and_friends_1(Bifs),
+ Mod = ?FUNCTION_NAME,
+ Calls = [begin
+ Atom = erl_syntax:function_name(N),
+ ?Q("'@Atom'()")
+ end || N <- Fs],
+ Tree = ?Q(["-module('@Mod@').",
+ "-export([test/0]).",
+ "test() -> _@Calls, ok.",
+ "id(I) -> I."]) ++ Fs,
+ merl:print(Tree),
+ Opts = test_lib:opt_opts(?MODULE),
+ {ok,_Bin} = merl:compile_and_load(Tree, Opts),
+ Mod:test(),
+ ok.
+
+trunc_and_friends_1([F|Fs]) ->
+ Func = list_to_atom("f"++integer_to_list(length(Fs))),
+ [trunc_template(Func, F)|trunc_and_friends_1(Fs)];
+trunc_and_friends_1([]) -> [].
+
+trunc_template(Func, Bif) ->
+ Val = 42.77,
+ Res = erlang:Bif(Val),
+ FloatRes = float(Res),
+ ?Q("'@Func@'() ->
+ Var = id(_@Val@),
+ if _@Bif@(Var) =:= _@Res@ -> ok end,
+ if _@Bif@(Var) == _@FloatRes@ -> ok end,
+ if _@Bif@(Var) == _@Res@ -> ok end,
+ _@Res@ = _@Bif@(Var),
+ try begin _@Bif@(a), ok end
+ catch error:badarg -> ok end,
+ ok.").
+
+cover_safe_bifs(Config) ->
+ _ = get(),
+ _ = get_keys(a),
+ _ = group_leader(),
+ _ = is_alive(),
+ _ = min(Config, []),
+ _ = nodes(),
+ _ = erlang:ports(),
+ _ = pre_loaded(),
+ _ = processes(),
+ _ = registered(),
+ _ = term_to_binary(Config),
+
+ ok.
diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl
index 1bf4e9d4a7..dd1d245f88 100644
--- a/lib/compiler/test/bs_bincomp_SUITE.erl
+++ b/lib/compiler/test/bs_bincomp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,9 +26,9 @@
init_per_group/2,end_per_group/2,
byte_aligned/1,bit_aligned/1,extended_byte_aligned/1,
extended_bit_aligned/1,mixed/1,filters/1,trim_coverage/1,
- nomatch/1,sizes/1]).
+ nomatch/1,sizes/1,general_expressions/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -36,7 +36,7 @@ all() ->
test_lib:recompile(?MODULE),
[byte_aligned, bit_aligned, extended_byte_aligned,
extended_bit_aligned, mixed, filters, trim_coverage,
- nomatch, sizes].
+ nomatch, sizes, general_expressions].
groups() ->
[].
@@ -55,110 +55,115 @@ end_per_group(_GroupName, Config) ->
byte_aligned(Config) when is_list(Config) ->
cs_init(),
- ?line <<"abcdefg">> = cs(<< <<(X+32)>> || <<X>> <= <<"ABCDEFG">> >>),
+ <<"abcdefg">> = cs(<< <<(X+32)>> || <<X>> <= <<"ABCDEFG">> >>),
+ <<"AxyzBxyzCxyz">> = cs(<< <<X, "xyz">> || <<X>> <= <<"ABC">> >>),
<<1:32/little,2:32/little,3:32/little,4:32/little>> =
cs(<< <<X:32/little>> || <<X:32>> <= <<1:32,2:32,3:32,4:32>> >>),
- ?line cs(<<1:32/little,2:32/little,3:32/little,4:32/little>> =
- << <<X:32/little>> || <<X:16>> <= <<1:16,2:16,3:16,4:16>> >>),
+ cs(<<1:32/little,2:32/little,3:32/little,4:32/little>> =
+ << <<X:32/little>> || <<X:16>> <= <<1:16,2:16,3:16,4:16>> >>),
cs_end().
bit_aligned(Config) when is_list(Config) ->
cs_init(),
- ?line <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> =
+ <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> =
cs(<< <<(X+32):7>> || <<X>> <= <<"ABCDEFG">> >>),
- ?line <<"ABCDEFG">> =
+ <<"ABCDEFG">> =
cs(<< <<(X-32)>> || <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> >>),
- ?line <<1:31/little,2:31/little,3:31/little,4:31/little>> =
+ <<1:31/little,2:31/little,3:31/little,4:31/little>> =
cs(<< <<X:31/little>> || <<X:31>> <= <<1:31,2:31,3:31,4:31>> >>),
- ?line <<1:31/little,2:31/little,3:31/little,4:31/little>> =
+ <<1:31/little,2:31/little,3:31/little,4:31/little>> =
cs(<< <<X:31/little>> || <<X:15>> <= <<1:15,2:15,3:15,4:15>> >>),
cs_end().
extended_byte_aligned(Config) when is_list(Config) ->
cs_init(),
- ?line <<"abcdefg">> = cs(<< <<(X+32)>> || X <- "ABCDEFG" >>),
- ?line "abcdefg" = [(X+32) || <<X>> <= <<"ABCDEFG">>],
- ?line <<1:32/little,2:32/little,3:32/little,4:32/little>> =
+ <<"abcdefg">> = cs(<< <<(X+32)>> || X <- "ABCDEFG" >>),
+ "abcdefg" = [(X+32) || <<X>> <= <<"ABCDEFG">>],
+ <<1:32/little,2:32/little,3:32/little,4:32/little>> =
cs(<< <<X:32/little>> || X <- [1,2,3,4] >>),
- ?line [256,512,768,1024] =
+ [256,512,768,1024] =
[X || <<X:16/little>> <= <<1:16,2:16,3:16,4:16>>],
cs_end().
extended_bit_aligned(Config) when is_list(Config) ->
cs_init(),
- ?line <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> =
+ <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> =
cs(<< <<(X+32):7>> || X <- "ABCDEFG" >>),
- ?line "ABCDEFG" = [(X-32) || <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>>],
- ?line <<1:31/little,2:31/little,3:31/little,4:31/little>> =
+ "ABCDEFG" = [(X-32) || <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>>],
+ <<1:31/little,2:31/little,3:31/little,4:31/little>> =
cs(<< <<X:31/little>> || X <- [1,2,3,4] >>),
- ?line [256,512,768,1024] =
+ [256,512,768,1024] =
[X || <<X:15/little>> <= <<1:15,2:15,3:15,4:15>>],
cs_end().
mixed(Config) when is_list(Config) ->
cs_init(),
- ?line <<2,3,3,4,4,5,5,6>> =
+ <<2,3,3,4,4,5,5,6>> =
cs(<< <<(X+Y)>> || <<X>> <= <<1,2,3,4>>, <<Y>> <= <<1,2>> >>),
- ?line <<2,3,3,4,4,5,5,6>> =
+ <<2,3,3,4,4,5,5,6>> =
<< <<(X+Y)>> || <<X>> <= <<1,2,3,4>>, Y <- [1,2] >>,
- ?line <<2,3,3,4,4,5,5,6>> =
+ <<2,3,3,4,4,5,5,6>> =
cs(<< <<(X+Y)>> || X <- [1,2,3,4], Y <- [1,2] >>),
One = id([1,2,3,4]),
Two = id([1,2]),
- ?line <<2,3,3,4,4,5,5,6>> =
+ <<2,3,3,4,4,5,5,6>> =
cs(<< <<(X+Y)>> || X <- One, Y <- Two >>),
- ?line [2,3,3,4,4,5,5,6] =
+ [2,3,3,4,4,5,5,6] =
[(X+Y) || <<X>> <= <<1,2,3,4>>, <<Y>> <= <<1,2>>],
- ?line [2,3,3,4,4,5,5,6] =
+ [2,3,3,4,4,5,5,6] =
[(X+Y) || <<X>> <= <<1,2,3,4>>, Y <- [1,2]],
- ?line <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
+ <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
cs(<< <<(X+Y):3>> || <<X:3>> <= <<1:3,2:3,3:3,4:3>>,
<<Y:3>> <= <<1:3,2:3>> >>),
- ?line <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
+ <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
cs(<< <<(X+Y):3>> || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, Y <- [1,2] >>),
- ?line <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
+ <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
cs(<< <<(X+Y):3>> || X <- [1,2,3,4], Y <- [1,2] >>),
- ?line <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
+ <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
cs_default(<< <<(X+Y):3>> || {X,Y} <- [{1,1},{1,2},{2,1},{2,2},
{3,1},{3,2},{4,1},{4,2}] >>),
- ?line [2,3,3,4,4,5,5,6] =
+ [2,3,3,4,4,5,5,6] =
[(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, <<Y:3>> <= <<1:3,2:3>>],
- ?line [2,3,3,4,4,5,5,6] =
+ [2,3,3,4,4,5,5,6] =
[(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, {_,Y} <- [{a,1},{b,2}]],
cs_end().
filters(Config) when is_list(Config) ->
cs_init(),
- ?line <<"BDF">> =
- cs_default(<< <<(X-32)>> || <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>>,
- X rem 2 == 0>>),
- ?line <<"abc">> = cs_default(<< <<(X+32)>> || X <- "ABCDEFG",
- is_less_than(X, $D)>>),
- ?line <<"efg">> = cs_default(<< <<(X+32)>> || X <- "ABCDEFG",
- not is_less_than(X, $E)>>),
- ?line <<"b">> = cs_default(<< <<(X+32)>> || X <- "ABCDEFG",
- is_less_than(X, $D),
- X rem 2 == 0>>),
- ?line <<"eg">> = cs_default(<< <<(X+32)>> || X <- "ABCDEFG",
- not is_less_than(X, $E),
- X rem 2 == 1>>),
+ <<"BDF">> =
+ cs_default(<< <<(X-32)>> ||
+ <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>>,
+ X rem 2 == 0>>),
+ <<"abc">> = cs_default(<< <<(X+32)>> ||
+ X <- "ABCDEFG",
+ is_less_than(X, $D)>>),
+ <<"efg">> = cs_default(<< <<(X+32)>> ||
+ X <- "ABCDEFG",
+ not is_less_than(X, $E)>>),
+ <<"b">> = cs_default(<< <<(X+32)>> ||
+ X <- "ABCDEFG",
+ is_less_than(X, $D),
+ X rem 2 == 0>>),
+ <<"eg">> = cs_default(<< <<(X+32)>> ||
+ X <- "ABCDEFG",
+ not is_less_than(X, $E),
+ X rem 2 == 1>>),
%% Filtering by a non-matching pattern.
- ?line <<"abd">> = cs_default(<< <<X:8>> ||
- <<0:1,X:7>> <= <<$a:8,$b:8,1:1,$c:7,$d:8,
- 1:1,$e:7,0:4>> >>),
+ <<"abd">> = cs_default(<< <<X:8>> ||
+ <<0:1,X:7>> <= <<$a:8,$b:8,1:1,$c:7,$d:8,
+ 1:1,$e:7,0:4>> >>),
- ?line <<42,42>> = cs_default(<< <<42:8>> ||
- 42 <- [1,2,3,42,43,42] >>),
+ <<42,42>> = cs_default(<< <<42:8>> || 42 <- [1,2,3,42,43,42] >>),
cs_end().
is_less_than(X, C) when X < C -> true;
is_less_than(_, _) -> false.
trim_coverage(Config) when is_list(Config) ->
- ?line <<0,0,0,2,0,0,5,48,0,11,219,174,0,0,0,0>> = coverage_materialiv(a, b, {1328,777134}),
- ?line <<67,40,0,0,66,152,0,0,69,66,64,0>> = coverage_trimmer([42,19,777]),
- ?line <<0,0,2,43,0,0,3,9,0,0,0,3,64,8,0,0,0,0,0,0,
+ <<0,0,0,2,0,0,5,48,0,11,219,174,0,0,0,0>> = coverage_materialiv(a, b, {1328,777134}),
+ <<67,40,0,0,66,152,0,0,69,66,64,0>> = coverage_trimmer([42,19,777]),
+ <<0,0,2,43,0,0,3,9,0,0,0,3,64,8,0,0,0,0,0,0,
64,68,0,0,0,0,0,0,192,171,198,0,0,0,0,0>> =
coverage_lightfv(555, 777, {3.0,40.0,-3555.0}),
ok.
@@ -186,111 +191,153 @@ coverage_trimmer(Params) ->
coverage_summer(A, B, C, D) -> A+B+C+D.
nomatch(Config) when is_list(Config) ->
- ?line <<>> = << <<X:8>> || X = {_,_} = [_|_] <- [1,2,3] >>,
+ <<>> = << <<X:8>> || X = {_,_} = [_|_] <- [1,2,3] >>,
ok.
sizes(Config) when is_list(Config) ->
- ?line cs_init(),
+ cs_init(),
Fun0 = fun(List) ->
cs(<< <<E:8>> || E <- List >>)
end,
- ?line <<>> = Fun0([]),
- ?line <<1>> = Fun0([1]),
- ?line <<1,2>> = Fun0([1,2]),
- ?line <<1,2,3>> = Fun0([1,2,3]),
+ <<>> = Fun0([]),
+ <<1>> = Fun0([1]),
+ <<1,2>> = Fun0([1,2]),
+ <<1,2,3>> = Fun0([1,2,3]),
Fun1 = fun(List) ->
cs(<< <<E:16>> || E <- List >>)
end,
- ?line <<>> = Fun1([]),
- ?line <<1:16>> = Fun1([1]),
- ?line <<1:16,2:16>> = Fun1([1,2]),
- ?line <<1:16,2:16,3:16>> = Fun1([1,2,3]),
+ <<>> = Fun1([]),
+ <<1:16>> = Fun1([1]),
+ <<1:16,2:16>> = Fun1([1,2]),
+ <<1:16,2:16,3:16>> = Fun1([1,2,3]),
Fun2 = fun(List) ->
cs(<< <<E:4>> || E <- List >>)
end,
- ?line <<>> = Fun2([]),
- ?line <<1:4>> = Fun2([1]),
- ?line <<1:4,13:4>> = Fun2([1,13]),
- ?line <<1:4,13:4,7:4>> = Fun2([1,13,7]),
- ?line <<0:1000/unit:8>> = Fun2(lists:duplicate(2000, 0)),
+ <<>> = Fun2([]),
+ <<1:4>> = Fun2([1]),
+ <<1:4,13:4>> = Fun2([1,13]),
+ <<1:4,13:4,7:4>> = Fun2([1,13,7]),
+ <<0:1000/unit:8>> = Fun2(lists:duplicate(2000, 0)),
Fun3 = fun(List) ->
cs(<< <<E:3>> || E <- List >>)
end,
- ?line <<>> = Fun3([]),
- ?line <<40,177,29:5>> = Fun3([1,2,1,3,0,7,5]),
- ?line <<0:512/unit:3>> = Fun3(lists:duplicate(512, 0)),
+ <<>> = Fun3([]),
+ <<40,177,29:5>> = Fun3([1,2,1,3,0,7,5]),
+ <<0:512/unit:3>> = Fun3(lists:duplicate(512, 0)),
Fun4 = fun(List, Size) ->
cs(<< <<E:Size>> || E <- List >>)
end,
- ?line <<>> = Fun4([], 8),
- ?line <<42:6>> = Fun4([42], 6),
- ?line <<42:16>> = Fun4([42], 16),
+ <<>> = Fun4([], 8),
+ <<42:6>> = Fun4([42], 6),
+ <<42:16>> = Fun4([42], 16),
Fun5 = fun(List, Sz1, Sz2, Sz3) ->
cs(<< <<E:Sz1,(E+1):Sz2/unit:8,(E+2):Sz3/unit:8>> || E <- List >>)
end,
- ?line <<>> = Fun5([], 1, 1, 1),
- ?line <<7:3,8:40,9:56>> = Fun5([7], 3, 5, 7),
+ <<>> = Fun5([], 1, 1, 1),
+ <<7:3,8:40,9:56>> = Fun5([7], 3, 5, 7),
Fun6 = fun(List, Size) ->
cs(<< <<E:8,(E+1):Size>> || E <- List >>)
end,
- ?line <<>> = Fun6([], 42),
- ?line <<42,43:20>> = Fun6([42], 20),
+ <<>> = Fun6([], 42),
+ <<42,43:20>> = Fun6([42], 20),
%% Binary generators.
Fun10 = fun(Bin) ->
cs(<< <<E:16>> || <<E:8>> <= Bin >>)
end,
- ?line <<>> = Fun10(<<>>),
- ?line <<1:16>> = Fun10(<<1>>),
- ?line <<1:16,2:16>> = Fun10(<<1,2>>),
+ <<>> = Fun10(<<>>),
+ <<1:16>> = Fun10(<<1>>),
+ <<1:16,2:16>> = Fun10(<<1,2>>),
Fun11 = fun(Bin) ->
cs(<< <<E:8>> || <<E:16>> <= Bin >>)
end,
- ?line <<>> = Fun11(<<>>),
- ?line <<1>> = Fun11(<<1:16>>),
- ?line <<1,2>> = Fun11(<<1:16,2:16>>),
- ?line <<1,2>> = Fun11(<<1:16,2:16,0:1>>),
- ?line <<1,2>> = Fun11(<<1:16,2:16,0:7>>),
- ?line <<1,2>> = Fun11(<<1:16,2:16,42:8>>),
- ?line <<1,2>> = Fun11(<<1:16,2:16,42:9>>),
- ?line <<1,2>> = Fun11(<<1:16,2:16,255:15>>),
+ <<>> = Fun11(<<>>),
+ <<1>> = Fun11(<<1:16>>),
+ <<1,2>> = Fun11(<<1:16,2:16>>),
+ <<1,2>> = Fun11(<<1:16,2:16,0:1>>),
+ <<1,2>> = Fun11(<<1:16,2:16,0:7>>),
+ <<1,2>> = Fun11(<<1:16,2:16,42:8>>),
+ <<1,2>> = Fun11(<<1:16,2:16,42:9>>),
+ <<1,2>> = Fun11(<<1:16,2:16,255:15>>),
Fun12 = fun(Bin, Sz1, Sz2) ->
cs(<< <<E:Sz1>> || <<E:Sz2>> <= Bin >>)
end,
- ?line <<>> = Fun12(<<>>, 1, 1),
- ?line Binary = list_to_binary(lists:seq(0, 255)),
- ?line Binary = Fun12(Binary, 1, 1),
- ?line Binary = Fun12(Binary, 4, 4),
- ?line Binary = Fun12(Binary, 8, 8),
- ?line <<17:9,19:9>> = Fun12(<<17:6,19:6>>, 9, 6),
+ <<>> = Fun12(<<>>, 1, 1),
+ Binary = list_to_binary(lists:seq(0, 255)),
+ Binary = Fun12(Binary, 1, 1),
+ Binary = Fun12(Binary, 4, 4),
+ Binary = Fun12(Binary, 8, 8),
+ <<17:9,19:9>> = Fun12(<<17:6,19:6>>, 9, 6),
Fun13 = fun(Sz) ->
cs_default(<< <<C:8>> || <<C:4>> <= <<1:4,2:4,3:4,0:Sz>> >>)
end,
- ?line <<1,2,3>> = Fun13(0),
- ?line <<1,2,3,0>> = Fun13(4),
- ?line <<1,2,3,0>> = Fun13(5),
- ?line <<1,2,3,0>> = Fun13(6),
- ?line <<1,2,3,0>> = Fun13(7),
- ?line <<1,2,3,0,0>> = Fun13(8),
+ <<1,2,3>> = Fun13(0),
+ <<1,2,3,0>> = Fun13(4),
+ <<1,2,3,0>> = Fun13(5),
+ <<1,2,3,0>> = Fun13(6),
+ <<1,2,3,0>> = Fun13(7),
+ <<1,2,3,0,0>> = Fun13(8),
<<0:3>> = cs_default(<< <<0:S>> || S <- [0,1,2] >>),
<<0:3>> = cs_default(<< <<0:S>> || <<S>> <= <<0,1,2>> >>),
- ?line {'EXIT',_} = (catch << <<C:4>> || <<C:8>> <= {1,2,3} >>),
+ {'EXIT',_} = (catch << <<C:4>> || <<C:8>> <= {1,2,3} >>),
+
+ cs_end(),
+ ok.
+
+-define(BAD(E), {'EXIT',{badarg,_}} = (catch << (E) || _ <- [1,2,3] >>)).
+-define(BAD_V(E), {'EXIT',{badarg,_}} = (catch << (E) || I <- [1,2,3] >>)).
+
+general_expressions(_) ->
+ <<1,2,3>> = << begin <<1,2,3>> end || _ <- [1] >>,
+ <<"abc">> = << begin <<"abc">> end || _ <- [1] >>,
+ <<1,2,3>> = << begin
+ I = <<(I0+1)>>,
+ id(I)
+ end || <<I0>> <= <<0,1,2>> >>,
+ <<1,2,3>> = << I || I <- [<<1,2>>,<<3>>] >>,
+ <<1,2,3>> = << (id(<<I>>)) || I <- [1,2,3] >>,
+ <<2,4>> = << case I rem 2 of
+ 0 -> <<I>>;
+ 1 -> <<>>
+ end || I <- [1,2,3,4,5] >>,
+ <<2,3,4,5,6,7>> = << << (id(<<J>>)) || J <- [2*I,2*I+1] >> ||
+ I <- [1,2,3] >>,
+ <<1,2,2,3,4,4>> = << if
+ I rem 2 =:= 0 -> <<I,I>>;
+ true -> <<I>>
+ end || I <- [1,2,3,4] >>,
+ self() ! <<42>>,
+ <<42>> = << receive B -> B end || _ <- [1] >>,
+ <<10,5,3>> = << try
+ <<(10 div I)>>
+ catch _:_ ->
+ <<>>
+ end || I <- [0,1,2,3] >>,
+
+ %% Failing expressions.
+ ?BAD(bad_atom),
+ ?BAD(42),
+ ?BAD(42.0),
+ ?BAD_V({ok,I}),
+ ?BAD_V([I]),
+ ?BAD_V(fun() -> I end),
- ?line cs_end(),
ok.
+-undef(BAD).
+
cs_init() ->
erts_debug:set_internal_state(available_internal_state, true),
ok.
diff --git a/lib/compiler/test/bs_bit_binaries_SUITE.erl b/lib/compiler/test/bs_bit_binaries_SUITE.erl
index afee52c9b9..208d8c5487 100644
--- a/lib/compiler/test/bs_bit_binaries_SUITE.erl
+++ b/lib/compiler/test/bs_bit_binaries_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
big_binary_to_and_from_list/1,send_and_receive/1,
send_and_receive_alot/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -59,9 +59,9 @@ end_per_group(_GroupName, Config) ->
misc(Config) when is_list(Config) ->
- ?line <<1:100>> = <<1:100>>,
- ?line {ok,ok} = {match(7),match(9)},
- ?line {ok,ok} = {match1(15),match1(31)},
+ <<1:100>> = <<1:100>>,
+ {ok,ok} = {match(7),match(9)},
+ {ok,ok} = {match1(15),match1(31)},
ok.
@@ -74,75 +74,75 @@ match1(N) ->
ok.
test_bit_size(Config) when is_list(Config) ->
- ?line 101 = erlang:bit_size(<<1:101>>),
- ?line 1001 = erlang:bit_size(<<1:1001>>),
- ?line 1001 = erlang:bit_size(<<-10:1001>>),
- ?line 80 = erlang:bit_size(<<1:80>>),
- ?line 800 = erlang:bit_size(<<1:800>>),
- ?line Bin = <<0:16#1000000>>,
- ?line BigBin = list_to_bitstring([Bin||_ <- lists:seq(1,16#10)]++[<<1:1>>]),
- ?line 16#10000001 = erlang:bit_size(BigBin),
+ 101 = erlang:bit_size(<<1:101>>),
+ 1001 = erlang:bit_size(<<1:1001>>),
+ 1001 = erlang:bit_size(<<-10:1001>>),
+ 80 = erlang:bit_size(<<1:80>>),
+ 800 = erlang:bit_size(<<1:800>>),
+ Bin = <<0:16#1000000>>,
+ BigBin = list_to_bitstring([Bin||_ <- lists:seq(1,16#10)]++[<<1:1>>]),
+ 16#10000001 = erlang:bit_size(BigBin),
%% Only run these on computers with lots of memory
%% HugeBin = list_to_bitstring([BigBin||_ <- lists:seq(1,16#10)]++[<<1:1>>]),
%% 16#100000011 = erlang:bit_size(HugeBin),
- ?line 0 = erlang:bit_size(<<>>),
+ 0 = erlang:bit_size(<<>>),
ok.
horrid_match(Config) when is_list(Config) ->
- ?line <<1:4,B:24/bitstring>> = <<1:4,42:24/little>>,
- ?line <<42:24/little>> = B,
+ <<1:4,B:24/bitstring>> = <<1:4,42:24/little>>,
+ <<42:24/little>> = B,
ok.
test_bitstr(Config) when is_list(Config) ->
- ?line <<1:7,B/bitstring>> = <<1:7,<<1:1,6>>/bitstring>>,
- ?line <<1:1,6>> = B,
- ?line B = <<1:1,6>>,
+ <<1:7,B/bitstring>> = <<1:7,<<1:1,6>>/bitstring>>,
+ <<1:1,6>> = B,
+ B = <<1:1,6>>,
ok.
asymmetric_tests(Config) when is_list(Config) ->
- ?line <<1:12>> = <<0,1:4>>,
- ?line <<0,1:4>> = <<1:12>>,
- ?line <<1:1,X/bitstring>> = <<128,255,0,0:2>>,
- ?line <<1,254,0,0:1>> = X,
- ?line X = <<1,254,0,0:1>>,
- ?line <<1:1,X1:25/bitstring>> = <<128,255,0,0:2>>,
- ?line <<1,254,0,0:1>> = X1,
- ?line X1 = <<1,254,0,0:1>>,
+ <<1:12>> = <<0,1:4>>,
+ <<0,1:4>> = <<1:12>>,
+ <<1:1,X/bitstring>> = <<128,255,0,0:2>>,
+ <<1,254,0,0:1>> = X,
+ X = <<1,254,0,0:1>>,
+ <<1:1,X1:25/bitstring>> = <<128,255,0,0:2>>,
+ <<1,254,0,0:1>> = X1,
+ X1 = <<1,254,0,0:1>>,
ok.
big_asymmetric_tests(Config) when is_list(Config) ->
- ?line <<1:875,1:12>> = <<1:875,0,1:4>>,
- ?line <<1:875,0,1:4>> = <<1:875,1:12>>,
- ?line <<1:1,X/bitstring>> = <<128,255,0,0:2,1:875>>,
- ?line <<1,254,0,0:1,1:875>> = X,
- ?line X = <<1,254,0,0:1,1:875>>,
- ?line <<1:1,X1:900/bitstring>> = <<128,255,0,0:2,1:875>>,
- ?line <<1,254,0,0:1,1:875>> = X1,
- ?line X1 = <<1,254,0,0:1,1:875>>,
+ <<1:875,1:12>> = <<1:875,0,1:4>>,
+ <<1:875,0,1:4>> = <<1:875,1:12>>,
+ <<1:1,X/bitstring>> = <<128,255,0,0:2,1:875>>,
+ <<1,254,0,0:1,1:875>> = X,
+ X = <<1,254,0,0:1,1:875>>,
+ <<1:1,X1:900/bitstring>> = <<128,255,0,0:2,1:875>>,
+ <<1,254,0,0:1,1:875>> = X1,
+ X1 = <<1,254,0,0:1,1:875>>,
ok.
binary_to_and_from_list(Config) when is_list(Config) ->
- ?line <<1,2,3,4,1:1>> = list_to_bitstring(bitstring_to_list(<<1,2,3,4,1:1>>)),
- ?line [1,2,3,4,<<1:1>>] = bitstring_to_list(<<1,2,3,4,1:1>>),
- ?line <<1:1,1,2,3,4>> = list_to_bitstring([<<1:1>>,1,2,3,4]),
- ?line [128,129,1,130,<<0:1>>] = bitstring_to_list(<<1:1,1,2,3,4>>),
+ <<1,2,3,4,1:1>> = list_to_bitstring(bitstring_to_list(<<1,2,3,4,1:1>>)),
+ [1,2,3,4,<<1:1>>] = bitstring_to_list(<<1,2,3,4,1:1>>),
+ <<1:1,1,2,3,4>> = list_to_bitstring([<<1:1>>,1,2,3,4]),
+ [128,129,1,130,<<0:1>>] = bitstring_to_list(<<1:1,1,2,3,4>>),
ok.
big_binary_to_and_from_list(Config) when is_list(Config) ->
- ?line <<1:800,2,3,4,1:1>> =
+ <<1:800,2,3,4,1:1>> =
list_to_bitstring(bitstring_to_list(<<1:800,2,3,4,1:1>>)),
- ?line [1,2,3,4|_Rest1] = bitstring_to_list(<<1,2,3,4,1:800,1:1>>),
- ?line <<1:801,1,2,3,4>> = list_to_bitstring([<<1:801>>,1,2,3,4]),
+ [1,2,3,4|_Rest1] = bitstring_to_list(<<1,2,3,4,1:800,1:1>>),
+ <<1:801,1,2,3,4>> = list_to_bitstring([<<1:801>>,1,2,3,4]),
ok.
send_and_receive(Config) when is_list(Config) ->
- ?line Bin = <<1,2:7>>,
+ Bin = <<1,2:7>>,
Pid = spawn_link(fun() -> receiver(Bin) end),
- ?line Pid ! {self(),<<1:7,8:5,Bin/bitstring>>},
- ?line receive
- ok ->
- ok
- end.
+ Pid ! {self(),<<1:7,8:5,Bin/bitstring>>},
+ receive
+ ok ->
+ ok
+ end.
receiver(Bin) ->
receive
diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl
index 87cfaaf73c..da99aba346 100644
--- a/lib/compiler/test/bs_construct_SUITE.erl
+++ b/lib/compiler/test/bs_construct_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. 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.
@@ -29,11 +29,14 @@
init_per_testcase/2,end_per_testcase/2,
two/1,test1/1,fail/1,float_bin/1,in_guard/1,in_catch/1,
nasty_literals/1,coerce_to_float/1,side_effect/1,
- opt/1,otp_7556/1,float_arith/1,otp_8054/1]).
+ opt/1,otp_7556/1,float_arith/1,otp_8054/1,
+ cover/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,1}}].
all() ->
test_lib:recompile(?MODULE),
@@ -43,7 +46,7 @@ groups() ->
[{p,[parallel],
[two,test1,fail,float_bin,in_guard,in_catch,
nasty_literals,side_effect,opt,otp_7556,float_arith,
- otp_8054]}].
+ otp_8054,cover]}].
init_per_suite(Config) ->
@@ -60,12 +63,9 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = test_server:timetrap(?t:minutes(1)),
- [{watchdog,Dog}|Config].
+ Config.
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
ok.
two(Config) when is_list(Config) ->
@@ -86,7 +86,7 @@ id(I) -> I.
-define(T(B, L), {B, ??B, L}).
-define(N(B), {B, ??B, unknown}).
--define(FAIL(Expr), ?line {'EXIT',{badarg,_}} = (catch Expr)).
+-define(FAIL(Expr), {'EXIT',{badarg,_}} = (catch Expr)).
l(I_13, I_big1, I_16, Bin) ->
[
@@ -200,7 +200,7 @@ one_test({C_bin, E_bin, Str, Bytes}) when is_list(Bytes) ->
true ->
io:format("ERROR: Compiled: ~p. Expected ~p. Got ~p.~n",
[Str, Bytes, bitstring_to_list(C_bin)]),
- test_server:fail(comp)
+ ct:fail(comp)
end,
if
E_bin == Bin ->
@@ -208,7 +208,7 @@ one_test({C_bin, E_bin, Str, Bytes}) when is_list(Bytes) ->
true ->
io:format("ERROR: Interpreted: ~p. Expected ~p. Got ~p.~n",
[Str, Bytes, bitstring_to_list(E_bin)]),
- test_server:fail(comp)
+ ct:fail(comp)
end;
one_test({C_bin, E_bin, Str, Result}) ->
io:format(" ~s ~p~n", [Str, C_bin]),
@@ -229,7 +229,7 @@ one_test({C_bin, E_bin, Str, Result}) ->
io:format("ERROR: Compiled not equal to interpreted:"
"~n ~p, ~p.~n",
[bitstring_to_list(C_bin), bitstring_to_list(E_bin)]),
- test_server:fail(comp);
+ ct:fail(comp);
0 ->
ok;
%% For situations where the final bits may not matter, like
@@ -261,15 +261,15 @@ equal_lists(A, B, R) ->
end.
test1(Config) when is_list(Config) ->
- ?line I_13 = i(13),
- ?line I_big1 = big(1),
- ?line I_16 = i(16),
- ?line Bin = i(<<16#A5,16#5A,16#C3>>),
- ?line Vars = lists:sort([{'I_13',I_13},
- {'I_big1',I_big1},
- {'I_16',I_16},
- {'Bin',Bin}]),
- ?line lists:foreach(fun one_test/1, eval_list(l(I_13, I_big1, I_16, Bin), Vars)).
+ I_13 = i(13),
+ I_big1 = big(1),
+ I_16 = i(16),
+ Bin = i(<<16#A5,16#5A,16#C3>>),
+ Vars = lists:sort([{'I_13',I_13},
+ {'I_big1',I_big1},
+ {'I_16',I_16},
+ {'Bin',Bin}]),
+ lists:foreach(fun one_test/1, eval_list(l(I_13, I_big1, I_16, Bin), Vars)).
fail(Config) when is_list(Config) ->
I_minus_777 = i(-777),
@@ -278,68 +278,68 @@ fail(Config) when is_list(Config) ->
%% One negative field size, but the sum of field sizes will be 1 byte.
%% Make sure that we reject that properly.
- ?line {'EXIT',{badarg,_}} = (catch <<I_minus_777:2048/unit:8,
- 57:I_minus_2047/unit:8>>),
+ {'EXIT',{badarg,_}} = (catch <<I_minus_777:2048/unit:8,
+ 57:I_minus_2047/unit:8>>),
%% Same thing, but use literals.
- ?line {'EXIT',{badarg,_}} = (catch <<I_minus_777:2048/unit:8,
- 57:(-2047)/unit:8>>),
+ {'EXIT',{badarg,_}} = (catch <<I_minus_777:2048/unit:8,
+ 57:(-2047)/unit:8>>),
%% Not numbers.
- ?line {'EXIT',{badarg,_}} = (catch <<45:(i(not_a_number))>>),
- ?line {'EXIT',{badarg,_}} = (catch <<13:8,45:(i(not_a_number))>>),
+ {'EXIT',{badarg,_}} = (catch <<45:(i(not_a_number))>>),
+ {'EXIT',{badarg,_}} = (catch <<13:8,45:(i(not_a_number))>>),
%% Unaligned sizes.
BadSz = i(7),
Bitstr = i(<<42:17>>),
- ?line {'EXIT',{badarg,_}} = (catch <<Bitstr:4/binary>>),
- ?line {'EXIT',{badarg,_}} = (catch <<Bitstr:BadSz/binary>>),
+ {'EXIT',{badarg,_}} = (catch <<Bitstr:4/binary>>),
+ {'EXIT',{badarg,_}} = (catch <<Bitstr:BadSz/binary>>),
- ?line [] = [X || {X} <- [], X == <<Bitstr:BadSz/binary>>],
- ?line [] = [X || {X} <- [], X == <<Bitstr:4/binary>>],
+ [] = [X || {X} <- [], X == <<Bitstr:BadSz/binary>>],
+ [] = [X || {X} <- [], X == <<Bitstr:4/binary>>],
%% Literals with incorrect type.
- ?line {'EXIT',{badarg,_}} = (catch <<42.0/integer>>),
- ?line {'EXIT',{badarg,_}} = (catch <<42/binary>>),
- ?line {'EXIT',{badarg,_}} = (catch <<an_atom/integer>>),
+ {'EXIT',{badarg,_}} = (catch <<42.0/integer>>),
+ {'EXIT',{badarg,_}} = (catch <<42/binary>>),
+ {'EXIT',{badarg,_}} = (catch <<an_atom/integer>>),
ok.
float_bin(Config) when is_list(Config) ->
%% Some more coverage.
- ?line {<<1,2,3>>,7.0} = float_bin_1(4),
+ {<<1,2,3>>,7.0} = float_bin_1(4),
F = 42.0,
- ?line <<42,0,0,0,0,0,0,69,64>> = <<(id(42)),F/little-float>>,
+ <<42,0,0,0,0,0,0,69,64>> = <<(id(42)),F/little-float>>,
ok.
float_bin_1(F) ->
{<<1,2,3>>,F+3.0}.
in_guard(Config) when is_list(Config) ->
- ?line 1 = in_guard_1(<<16#74ad:16>>, 16#e95, 5),
- ?line 2 = in_guard_1(<<16#3A,16#F7,"hello">>, 16#3AF7, <<"hello">>),
- ?line 3 = in_guard_1(<<16#FBCD:14,3.1415/float,3:2>>, 16#FBCD, 3.1415),
- ?line 3 = in_guard_1(<<16#FBCD:14,3/float,3:2>>, 16#FBCD, 3),
- ?line 3 = in_guard_1(<<16#FBCD:14,(2 bsl 226)/float,3:2>>, 16#FBCD, 2 bsl 226),
- ?line nope = in_guard_1(<<1>>, 42, b),
- ?line nope = in_guard_1(<<1>>, a, b),
- ?line nope = in_guard_1(<<1,2>>, 1, 1),
- ?line nope = in_guard_1(<<4,5>>, 1, 2.71),
- ?line nope = in_guard_1(<<4,5>>, 1, <<12,13>>),
-
- ?line 1 = in_guard_2(<<0,56>>, 7, blurf),
- ?line 2 = in_guard_2(<<1,255>>, 511, blurf),
- ?line 3 = in_guard_2(<<0,3>>, 0, blurf),
- ?line 4 = in_guard_2(<<>>, 1, {<<7:16>>}),
- ?line nope = in_guard_2(<<4,5>>, 1, blurf),
-
- ?line 42 = in_guard_3(<<1,2,3,42>>, <<1,2,3>>),
- ?line 42 = in_guard_3(<<1,2,3,42>>, <<1,2,3>>),
- ?line nope = in_guard_3(<<>>, <<>>),
-
- ?line ok = in_guard_4(<<15:4>>, 255),
- ?line nope = in_guard_4(<<15:8>>, 255),
+ 1 = in_guard_1(<<16#74ad:16>>, 16#e95, 5),
+ 2 = in_guard_1(<<16#3A,16#F7,"hello">>, 16#3AF7, <<"hello">>),
+ 3 = in_guard_1(<<16#FBCD:14,3.1415/float,3:2>>, 16#FBCD, 3.1415),
+ 3 = in_guard_1(<<16#FBCD:14,3/float,3:2>>, 16#FBCD, 3),
+ 3 = in_guard_1(<<16#FBCD:14,(2 bsl 226)/float,3:2>>, 16#FBCD, 2 bsl 226),
+ nope = in_guard_1(<<1>>, 42, b),
+ nope = in_guard_1(<<1>>, a, b),
+ nope = in_guard_1(<<1,2>>, 1, 1),
+ nope = in_guard_1(<<4,5>>, 1, 2.71),
+ nope = in_guard_1(<<4,5>>, 1, <<12,13>>),
+
+ 1 = in_guard_2(<<0,56>>, 7, blurf),
+ 2 = in_guard_2(<<1,255>>, 511, blurf),
+ 3 = in_guard_2(<<0,3>>, 0, blurf),
+ 4 = in_guard_2(<<>>, 1, {<<7:16>>}),
+ nope = in_guard_2(<<4,5>>, 1, blurf),
+
+ 42 = in_guard_3(<<1,2,3,42>>, <<1,2,3>>),
+ 42 = in_guard_3(<<1,2,3,42>>, <<1,2,3>>),
+ nope = in_guard_3(<<>>, <<>>),
+
+ ok = in_guard_4(<<15:4>>, 255),
+ nope = in_guard_4(<<15:8>>, 255),
ok.
in_guard_1(Bin, A, B) when <<A:13,B:3>> == Bin -> 1;
@@ -361,10 +361,10 @@ in_guard_4(Bin, A) when <<A:4>> =:= Bin -> ok;
in_guard_4(_, _) -> nope.
in_catch(Config) when is_list(Config) ->
- ?line <<42,0,5>> = small(42, 5),
- ?line <<255>> = small(255, <<1,2,3,4,5,6,7,8,9>>),
- ?line <<1,2>> = small(<<7,8,9,10>>, 258),
- ?line <<>> = small(<<1,2,3,4,5>>, <<7,8,9,10>>),
+ <<42,0,5>> = small(42, 5),
+ <<255>> = small(255, <<1,2,3,4,5,6,7,8,9>>),
+ <<1,2>> = small(<<7,8,9,10>>, 258),
+ <<>> = small(<<1,2,3,4,5>>, <<7,8,9,10>>),
<<15,240,0,42>> = small2(255, 42),
<<7:20>> = small2(<<1,2,3>>, 7),
@@ -413,20 +413,20 @@ small2(A, B) ->
nasty_literals(Config) when is_list(Config) ->
case erlang:system_info(endian) of
big ->
- ?line [0,42] = binary_to_list(id(<<42:16/native>>));
+ [0,42] = binary_to_list(id(<<42:16/native>>));
little ->
- ?line [42,0] = binary_to_list(id(<<42:16/native>>))
+ [42,0] = binary_to_list(id(<<42:16/native>>))
end,
- ?line Bin0 = id(<<1,2,3,0:10000000,4,5,6>>),
- ?line 1250006 = size(Bin0),
- ?line <<1,2,3,0:10000000,4,5,6>> = Bin0,
+ Bin0 = id(<<1,2,3,0:10000000,4,5,6>>),
+ 1250006 = size(Bin0),
+ <<1,2,3,0:10000000,4,5,6>> = Bin0,
- ?line Bin1 = id(<<0:10000000,7,8,-1:10000000,9,10,0:10000000>>),
- ?line 3750004 = size(Bin1),
- ?line <<0:10000000,7,8,-1:10000000/signed,9,10,0:10000000>> = Bin1,
+ Bin1 = id(<<0:10000000,7,8,-1:10000000,9,10,0:10000000>>),
+ 3750004 = size(Bin1),
+ <<0:10000000,7,8,-1:10000000/signed,9,10,0:10000000>> = Bin1,
- ?line <<255,255,0,0,0>> = id(<<255,255,0,0,0>>),
+ <<255,255,0,0,0>> = id(<<255,255,0,0,0>>),
%% Coverage.
I = 16#7777FFFF7777FFFF7777FFFF7777FFFF7777FFFF7777FFFF,
@@ -435,18 +435,18 @@ nasty_literals(Config) when is_list(Config) ->
ok.
-define(COF(Int0),
- ?line (fun(Int) ->
- true = <<Int:32/float>> =:= <<(float(Int)):32/float>>,
- true = <<Int:64/float>> =:= <<(float(Int)):64/float>>
- end)(nonliteral(Int0)),
- ?line true = <<Int0:32/float>> =:= <<(float(Int0)):32/float>>,
- ?line true = <<Int0:64/float>> =:= <<(float(Int0)):64/float>>).
+ (fun(Int) ->
+ true = <<Int:32/float>> =:= <<(float(Int)):32/float>>,
+ true = <<Int:64/float>> =:= <<(float(Int)):64/float>>
+ end)(nonliteral(Int0)),
+ true = <<Int0:32/float>> =:= <<(float(Int0)):32/float>>,
+ true = <<Int0:64/float>> =:= <<(float(Int0)):64/float>>).
-define(COF64(Int0),
- ?line (fun(Int) ->
- true = <<Int:64/float>> =:= <<(float(Int)):64/float>>
- end)(nonliteral(Int0)),
- ?line true = <<Int0:64/float>> =:= <<(float(Int0)):64/float>>).
+ (fun(Int) ->
+ true = <<Int:64/float>> =:= <<(float(Int)):64/float>>
+ end)(nonliteral(Int0)),
+ true = <<Int0:64/float>> =:= <<(float(Int0)):64/float>>).
nonliteral(X) -> X.
@@ -467,7 +467,7 @@ coerce_to_float(Config) when is_list(Config) ->
side_effect(Config) when is_list(Config) ->
{'EXIT',{badarg,_}} = (catch side_effect_1(a)),
{'EXIT',{badarg,_}} = (catch side_effect_1(<<>>)),
- ?line ok = side_effect_1(42),
+ ok = side_effect_1(42),
ok.
side_effect_1(A) ->
@@ -477,32 +477,32 @@ side_effect_1(A) ->
-record(otp_7029, {a,b}).
opt(Config) when is_list(Config) ->
- ?line 42 = otp_7029(#otp_7029{a = <<>>,b = 42}),
+ 42 = otp_7029(#otp_7029{a = <<>>,b = 42}),
N = 16,
- ?line <<1,3,65>> = id(<<1,833:N>>),
- ?line <<1,66,3>> = id(<<1,834:N/little>>),
- ?line <<1,65,136,0,0>> = id(<<1,17.0:32/float>>),
- ?line <<1,64,8,0,0,0,0,0,0>> = id(<<1,3.0:N/float-unit:4>>),
- ?line <<1,0,0,0,0,0,0,8,64>> = id(<<1,3.0:N/little-float-unit:4>>),
- ?line {'EXIT',{badarg,_}} = (catch id(<<3.1416:N/float>>)),
+ <<1,3,65>> = id(<<1,833:N>>),
+ <<1,66,3>> = id(<<1,834:N/little>>),
+ <<1,65,136,0,0>> = id(<<1,17.0:32/float>>),
+ <<1,64,8,0,0,0,0,0,0>> = id(<<1,3.0:N/float-unit:4>>),
+ <<1,0,0,0,0,0,0,8,64>> = id(<<1,3.0:N/little-float-unit:4>>),
+ {'EXIT',{badarg,_}} = (catch id(<<3.1416:N/float>>)),
B = <<1,2,3,4,5>>,
- ?line <<0,1,2,3,4,5>> = id(<<0,B/binary>>),
- ?line <<1,2,3,4,5,19>> = id(<<B:5/binary,19>>),
- ?line <<1,2,3,42>> = id(<<B:3/binary,42>>),
+ <<0,1,2,3,4,5>> = id(<<0,B/binary>>),
+ <<1,2,3,4,5,19>> = id(<<B:5/binary,19>>),
+ <<1,2,3,42>> = id(<<B:3/binary,42>>),
- ?line {'EXIT',_} = (catch <<<<23,56,0,2>>:(2.5)/binary>>),
- ?line {'EXIT',_} = (catch <<<<23,56,0,2>>:(-16)/binary>>),
- ?line {'EXIT',_} = (catch <<<<23,56,0,2>>:(anka)>>),
- ?line {'EXIT',_} = (catch <<<<23,56,0,2>>:64/float>>),
- ?line {'EXIT',_} = (catch <<<<23,56,0,2:7>>/binary>>),
+ {'EXIT',_} = (catch <<<<23,56,0,2>>:(2.5)/binary>>),
+ {'EXIT',_} = (catch <<<<23,56,0,2>>:(-16)/binary>>),
+ {'EXIT',_} = (catch <<<<23,56,0,2>>:(anka)>>),
+ {'EXIT',_} = (catch <<<<23,56,0,2>>:64/float>>),
+ {'EXIT',_} = (catch <<<<23,56,0,2:7>>/binary>>),
%% Test constant propagation - there should be a warning.
BadSz = 2.5,
{'EXIT',_} = (catch <<<<N,56,0,2>>:BadSz/binary>>),
case id(false) of
- true -> ?line opt_dont_call_me();
+ true -> opt_dont_call_me();
false -> ok
end,
@@ -530,7 +530,7 @@ otp_7556(Bin, A, B, C) ->
%% for a binary construction with a later allocation).
float_arith(Config) when is_list(Config) ->
- ?line {<<1,2,3,64,69,0,0,0,0,0,0>>,21.0} = do_float_arith(<<1,2,3>>, 42, 2),
+ {<<1,2,3,64,69,0,0,0,0,0,0>>,21.0} = do_float_arith(<<1,2,3>>, 42, 2),
ok.
do_float_arith(Bin0, X, Y) ->
@@ -538,7 +538,7 @@ do_float_arith(Bin0, X, Y) ->
{Bin,X / Y}.
otp_8054(Config) when is_list(Config) ->
- ?line <<"abc">> = otp_8054_1([null,1,2,3], <<"abc">>),
+ <<"abc">> = otp_8054_1([null,1,2,3], <<"abc">>),
ok.
otp_8054_1([H|T], Bin) ->
@@ -553,3 +553,19 @@ otp_8054_1([H|T], Bin) ->
end,
otp_8054_1(T, Bin);
otp_8054_1([], Bin) -> Bin.
+
+-define(LONG_STRING,
+ "3lz7Q4au2i3DJWNlNhWuzmvA7gYWGXG+LAPtgtlEO2VGSxRqL2WOoHW"
+ "QxORTQfJw17mNEU8i87UKvEPbo9YY8ppiM7vfaG88TTyfEzgUMTgY3I"
+ "vsikMBELPz2AayVz5aaMh9PBFTZ4DkBIFxURBUKHho4Vgt7IzYnWNgn"
+ "3ON5D9VS89TPANK5/PwSUoMQYZ2fk5VLbq7D1ExlnCScvTDnF/WHMQ3"
+ "m2GUcQWb+ajfOf3bnP7EX4f1Q3d/1Soe6lEpf1KN/5S7A/ugjMhy4+H"
+ "Zuo1J1J6CCwEVZ/wDc79OpDPPj/qOGhDK73F8DaMcynZ91El+01vfTn"
+ "uUxNFUHLpuoQ==").
+
+cover(Config) ->
+ %% Cover handling of a huge partially literal string.
+ L = length(Config),
+ Bin = id(<<L:32,?LONG_STRING>>),
+ <<L:32,?LONG_STRING>> = Bin,
+ ok.
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 7fb0a16540..2fe8cd0cff 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. 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.
@@ -24,11 +24,11 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
- fun_shadow/1,int_float/1,otp_5269/1,null_fields/1,wiger/1,
+ size_shadow/1,int_float/1,otp_5269/1,null_fields/1,wiger/1,
bin_tail/1,save_restore/1,
partitioned_bs_match/1,function_clause/1,
unit/1,shared_sub_bins/1,bin_and_float/1,
- dec_subidentifiers/1,skip_optional_tag/1,
+ dec_subidentifiers/1,skip_optional_tag/1,decode_integer/1,
wfbm/1,degenerated_match/1,bs_sum/1,coverage/1,
multiple_uses/1,zero_label/1,followed_by_catch/1,
matching_meets_construction/1,simon/1,matching_and_andalso/1,
@@ -36,15 +36,20 @@
match_string/1,zero_width/1,bad_size/1,haystack/1,
cover_beam_bool/1,matched_out_size/1,follow_fail_branch/1,
no_partition/1,calling_a_binary/1,binary_in_map/1,
- match_string_opt/1,map_and_binary/1,
- unsafe_branch_caching/1]).
+ match_string_opt/1,select_on_integer/1,
+ map_and_binary/1,unsafe_branch_caching/1,
+ bad_literals/1,good_literals/1,constant_propagation/1,
+ parse_xml/1,get_payload/1,num_slots_different/1]).
-export([coverage_id/1,coverage_external_ignore/2]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
+-include_lib("syntax_tools/include/merl.hrl").
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,1}}].
all() ->
test_lib:recompile(?MODULE),
@@ -52,19 +57,21 @@ all() ->
groups() ->
[{p,[parallel],
- [fun_shadow,int_float,otp_5269,null_fields,wiger,
+ [size_shadow,int_float,otp_5269,null_fields,wiger,
bin_tail,save_restore,
partitioned_bs_match,function_clause,unit,
shared_sub_bins,bin_and_float,dec_subidentifiers,
- skip_optional_tag,wfbm,degenerated_match,bs_sum,
+ skip_optional_tag,decode_integer,wfbm,degenerated_match,bs_sum,
coverage,multiple_uses,zero_label,followed_by_catch,
matching_meets_construction,simon,
matching_and_andalso,otp_7188,otp_7233,otp_7240,
otp_7498,match_string,zero_width,bad_size,haystack,
cover_beam_bool,matched_out_size,follow_fail_branch,
no_partition,calling_a_binary,binary_in_map,
- match_string_opt,map_and_binary,
- unsafe_branch_caching]}].
+ match_string_opt,select_on_integer,
+ map_and_binary,unsafe_branch_caching,
+ bad_literals,good_literals,constant_propagation,parse_xml,
+ get_payload,num_slots_different]}].
init_per_suite(Config) ->
@@ -81,108 +88,133 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = test_server:timetrap(?t:minutes(1)),
- [{watchdog,Dog}|Config].
+ Config.
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
ok.
-fun_shadow(Config) when is_list(Config) ->
- %% OTP-5270
- ?line 7 = fun_shadow_1(),
- ?line 7 = fun_shadow_2(8),
- ?line 7 = fun_shadow_3(),
- ?line no = fun_shadow_4(8),
+size_shadow(Config) when is_list(Config) ->
+ %% Originally OTP-5270.
+ 7 = size_shadow_1(),
+ 7 = size_shadow_2(8),
+ 7 = size_shadow_3(),
+ no = size_shadow_4(8),
+ Any = {any,term,goes},
+ {2577,Any,-175,whatever} =
+ (size_shadow_5(Any, 12))(<<2577:12>>, -175, whatever),
+ {7777,Any,42,whatever} =
+ (size_shadow_6(Any, 13))(42, <<7777:13>>, whatever),
+ {<<45>>,<<>>} = size_shadow_7({int,1}, <<1:16,45>>),
+ {'EXIT',{function_clause,_}} =
+ (catch size_shadow_7({int,42}, <<1:16,45>>)),
ok.
-fun_shadow_1() ->
+size_shadow_1() ->
L = 8,
F = fun(<<L:L,B:L>>) -> B end,
F(<<16:8, 7:16>>).
-fun_shadow_2(L) ->
+size_shadow_2(L) ->
F = fun(<<L:L,B:L>>) -> B end,
F(<<16:8, 7:16>>).
-fun_shadow_3() ->
+size_shadow_3() ->
L = 8,
F = fun(<<L:L,B:L,L:L>>) -> B end,
F(<<16:8, 7:16,16:16>>).
-fun_shadow_4(L) ->
+size_shadow_4(L) ->
F = fun(<<L:L,B:L,L:L>>) -> B;
(_) -> no end,
F(<<16:8, 7:16,15:16>>).
+size_shadow_5(X, Y) ->
+ fun (<< A:Y >>, Y, B) -> fum(A, X, Y, B) end.
+
+size_shadow_6(X, Y) ->
+ fun (Y, << A:Y >>, B) -> fum(A, X, Y, B) end.
+
+fum(A, B, C, D) ->
+ {A,B,C,D}.
+
+size_shadow_7({int,N}, <<N:16,B:N/binary,T/binary>>) ->
+ {B,T}.
+
+
int_float(Config) when is_list(Config) ->
%% OTP-5323
- ?line <<103133.0:64/float>> = <<103133:64/float>>,
- ?line <<103133:64/float>> = <<103133:64/float>>,
- ok.
+ <<103133.0:64/float>> = <<103133:64/float>>,
+ <<103133:64/float>> = <<103133:64/float>>,
+
+ %% Coverage of error cases in sys_pre_expand:coerce_to_float/2.
+ case id(default) of
+ <<(1 bsl 1024):64/float>> ->
+ ct:fail(should_not_match);
+ default ->
+ ok
+ end.
%% Stolen from erl_eval_SUITE and modified.
%% OTP-5269. Bugs in the bit syntax.
otp_5269(Config) when is_list(Config) ->
- ?line check(fun() -> L = 8,
- F = fun(<<A:L,B:A>>) -> B end,
- F(<<16:8, 7:16>>)
+ check(fun() -> L = 8,
+ F = fun(<<A:L,B:A>>) -> B end,
+ F(<<16:8, 7:16>>)
end,
7),
- ?line check(fun() -> L = 8, <<A:L,B:A>> = <<16:8, 7:16>>, B end,
- 7),
- ?line check(fun() -> U = 8, (fun(<<U:U>>) -> U end)(<<32:8>>) end,
- 32),
- ?line check(fun() -> U = 8, [U || <<U:U>> <- [<<32:8>>]] end,
- [32]),
- ?line check(fun() -> [X || <<A:8,
- B:A>> <- [<<16:8,19:16>>],
- <<X:8>> <- [<<B:8>>]] end,
- [19]),
- ?line check(fun() -> A = 4, B = 28, bit_size(<<13:(A+(X=B))>>), X end,
- 28),
- ?line check(fun() ->
- <<Size,B:Size/binary,Rest/binary>> = <<2,"AB","CD">>,
- {Size,B,Rest}
- end,
- {2,<<"AB">>,<<"CD">>}),
- ?line check(fun() -> X = 32,
- [X || <<X:X>> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end,
- %% "binsize variable" ^
- [1,2]),
- ?line check(fun() ->
- (fun (<<A:1/binary, B:8/integer, _C:B/binary>>) ->
- case A of
- B -> wrong;
- _ -> ok
- end
- end)(<<1,2,3,4>>) end,
- ok),
+ check(fun() -> L = 8, <<A:L,B:A>> = <<16:8, 7:16>>, B end,
+ 7),
+ check(fun() -> U = 8, (fun(<<U:U>>) -> U end)(<<32:8>>) end,
+ 32),
+ check(fun() -> U = 8, [U || <<U:U>> <- [<<32:8>>]] end,
+ [32]),
+ check(fun() -> [X || <<A:8,
+ B:A>> <- [<<16:8,19:16>>],
+ <<X:8>> <- [<<B:8>>]] end,
+ [19]),
+ check(fun() -> A = 4, B = 28, bit_size(<<13:(A+(X=B))>>), X end,
+ 28),
+ check(fun() ->
+ <<Size,B:Size/binary,Rest/binary>> = <<2,"AB","CD">>,
+ {Size,B,Rest}
+ end,
+ {2,<<"AB">>,<<"CD">>}),
+ check(fun() -> X = 32,
+ [X || <<X:X>> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end,
+ %% "binsize variable" ^
+ [1,2]),
+ check(fun() ->
+ (fun (<<A:1/binary, B:8/integer, _C:B/binary>>) ->
+ case A of
+ B -> wrong;
+ _ -> ok
+ end
+ end)(<<1,2,3,4>>) end,
+ ok),
ok.
null_fields(Config) when is_list(Config) ->
- ?line check(fun() ->
- W = id(0),
- F = fun(<<_:W>>) -> tail;
- (<<>>) -> empty
- end,
- F(<<>>)
- end, tail),
- ?line check(fun() ->
- F = fun(<<_/binary>>) -> tail;
- (<<>>) -> empty
- end,
- F(<<>>)
- end, tail),
+ check(fun() ->
+ W = id(0),
+ F = fun(<<_:W>>) -> tail;
+ (<<>>) -> empty
+ end,
+ F(<<>>)
+ end, tail),
+ check(fun() ->
+ F = fun(<<_/binary>>) -> tail;
+ (<<>>) -> empty
+ end,
+ F(<<>>)
+ end, tail),
ok.
wiger(Config) when is_list(Config) ->
- ?line ok1 = wcheck(<<3>>),
- ?line ok2 = wcheck(<<1,2,3>>),
- ?line ok3 = wcheck(<<4>>),
- ?line {error,<<1,2,3,4>>} = wcheck(<<1,2,3,4>>),
- ?line {error,<<>>} = wcheck(<<>>),
+ ok1 = wcheck(<<3>>),
+ ok2 = wcheck(<<1,2,3>>),
+ ok3 = wcheck(<<4>>),
+ {error,<<1,2,3,4>>} = wcheck(<<1,2,3,4>>),
+ {error,<<>>} = wcheck(<<>>),
ok.
wcheck(<<A>>) when A==3->
@@ -196,24 +228,24 @@ wcheck(Other) ->
bin_tail(Config) when is_list(Config) ->
S = <<"abcde">>,
- ?line $a = bin_tail_c(S, 0),
- ?line $c = bin_tail_c(S, 2),
- ?line $e = bin_tail_c(S, 4),
- ?line {'EXIT',_} = (catch bin_tail_c(S, 5)),
- ?line {'EXIT',_} = (catch bin_tail_c_var(S, 5)),
-
- ?line $a = bin_tail_d(S, 0),
- ?line $b = bin_tail_d(S, 8),
- ?line $d = bin_tail_d(S, 3*8),
- ?line {'EXIT',_} = (catch bin_tail_d_dead(S, 1)),
- ?line {'EXIT',_} = (catch bin_tail_d_dead(S, 9)),
- ?line {'EXIT',_} = (catch bin_tail_d_dead(S, 5*8)),
- ?line {'EXIT',_} = (catch bin_tail_d_var(S, 1)),
-
- ?line ok = bin_tail_e(<<2:2,0:1,1:5>>),
- ?line ok = bin_tail_e(<<2:2,1:1,1:5,42:64>>),
- ?line error = bin_tail_e(<<3:2,1:1,1:5,42:64>>),
- ?line error = bin_tail_e(<<>>),
+ $a = bin_tail_c(S, 0),
+ $c = bin_tail_c(S, 2),
+ $e = bin_tail_c(S, 4),
+ {'EXIT',_} = (catch bin_tail_c(S, 5)),
+ {'EXIT',_} = (catch bin_tail_c_var(S, 5)),
+
+ $a = bin_tail_d(S, 0),
+ $b = bin_tail_d(S, 8),
+ $d = bin_tail_d(S, 3*8),
+ {'EXIT',_} = (catch bin_tail_d_dead(S, 1)),
+ {'EXIT',_} = (catch bin_tail_d_dead(S, 9)),
+ {'EXIT',_} = (catch bin_tail_d_dead(S, 5*8)),
+ {'EXIT',_} = (catch bin_tail_d_var(S, 1)),
+
+ ok = bin_tail_e(<<2:2,0:1,1:5>>),
+ ok = bin_tail_e(<<2:2,1:1,1:5,42:64>>),
+ error = bin_tail_e(<<3:2,1:1,1:5,42:64>>),
+ error = bin_tail_e(<<>>),
ok.
bin_tail_c(Bin, Offset) ->
@@ -272,34 +304,34 @@ bin_tail_e_var(Bin) ->
end.
save_restore(Config) when is_list(Config) ->
- ?line 0 = save_restore_1(<<0:2,42:6>>),
- ?line {1,3456} = save_restore_1(<<1:2,3456:14>>),
- ?line {2,7981234} = save_restore_1(<<2:2,7981234:30>>),
- ?line {3,763967493838} = save_restore_1(<<0:2,763967493838:62>>),
+ 0 = save_restore_1(<<0:2,42:6>>),
+ {1,3456} = save_restore_1(<<1:2,3456:14>>),
+ {2,7981234} = save_restore_1(<<2:2,7981234:30>>),
+ {3,763967493838} = save_restore_1(<<0:2,763967493838:62>>),
A = <<" x">>,
B = <<".x">>,
C = <<"-x">>,
- ?line {" ",<<"x">>} = lll(A),
- ?line {" ",<<"x">>} = mmm(A),
- ?line {" ",<<"x">>} = nnn(A),
- ?line {" ",<<"x">>} = ooo(A),
+ {" ",<<"x">>} = lll(A),
+ {" ",<<"x">>} = mmm(A),
+ {" ",<<"x">>} = nnn(A),
+ {" ",<<"x">>} = ooo(A),
- ?line {".",<<"x">>} = lll(B),
- ?line {".",<<"x">>} = mmm(B),
- ?line {".",<<"x">>} = nnn(B),
- ?line {".",<<"x">>} = ooo(B),
+ {".",<<"x">>} = lll(B),
+ {".",<<"x">>} = mmm(B),
+ {".",<<"x">>} = nnn(B),
+ {".",<<"x">>} = ooo(B),
- ?line {"-",<<"x">>} = lll(C),
- ?line {"-",<<"x">>} = mmm(C),
- ?line {"-",<<"x">>} = nnn(C),
- ?line {"-",<<"x">>} = ooo(C),
+ {"-",<<"x">>} = lll(C),
+ {"-",<<"x">>} = mmm(C),
+ {"-",<<"x">>} = nnn(C),
+ {"-",<<"x">>} = ooo(C),
Bin = <<-1:64>>,
case bad_float_unpack_match(Bin) of
-1 -> ok;
- _Other -> ?line ?t:fail(bad_return_value_probably_NaN)
+ _Other -> ct:fail(bad_return_value_probably_NaN)
end.
save_restore_1(Bin) ->
@@ -328,18 +360,18 @@ bad_float_unpack_match(<<I:64/integer-signed>>) -> I.
partitioned_bs_match(Config) when is_list(Config) ->
- ?line <<1,2,3>> = partitioned_bs_match(blurf, <<42,1,2,3>>),
- ?line error = partitioned_bs_match(10, <<7,8,15,13>>),
- ?line error = partitioned_bs_match(100, {a,tuple,is,'not',a,binary}),
- ?line ok = partitioned_bs_match(0, <<>>),
- ?line fc(partitioned_bs_match, [-1,blurf],
+ <<1,2,3>> = partitioned_bs_match(blurf, <<42,1,2,3>>),
+ error = partitioned_bs_match(10, <<7,8,15,13>>),
+ error = partitioned_bs_match(100, {a,tuple,is,'not',a,binary}),
+ ok = partitioned_bs_match(0, <<>>),
+ fc(partitioned_bs_match, [-1,blurf],
catch partitioned_bs_match(-1, blurf)),
- ?line fc(partitioned_bs_match, [-1,<<1,2,3>>],
+ fc(partitioned_bs_match, [-1,<<1,2,3>>],
catch partitioned_bs_match(-1, <<1,2,3>>)),
- ?line {17,<<1,2,3>>} = partitioned_bs_match_2(1, <<17,1,2,3>>),
- ?line {7,<<1,2,3>>} = partitioned_bs_match_2(7, <<17,1,2,3>>),
+ {17,<<1,2,3>>} = partitioned_bs_match_2(1, <<17,1,2,3>>),
+ {7,<<1,2,3>>} = partitioned_bs_match_2(7, <<17,1,2,3>>),
- ?line fc(partitioned_bs_match_2, [4,<<0:17>>],
+ fc(partitioned_bs_match_2, [4,<<0:17>>],
catch partitioned_bs_match_2(4, <<0:17>>)),
anything = partitioned_bs_match_3(anything, <<42>>),
@@ -392,25 +424,25 @@ function_clause_2(<<_:4>>) ->
ok.
unit(Config) when is_list(Config) ->
- ?line 42 = peek1(<<42>>),
- ?line 43 = peek1(<<43,1,2>>),
- ?line 43 = peek1(<<43,1,2,(-1):1>>),
- ?line 43 = peek1(<<43,1,2,(-1):2>>),
- ?line 43 = peek1(<<43,1,2,(-1):7>>),
-
- ?line 99 = peek8(<<99>>),
- ?line 100 = peek8(<<100,101>>),
- ?line fc(peek8, [<<100,101,0:1>>], catch peek8(<<100,101,0:1>>)),
-
- ?line 37484 = peek16(<<37484:16>>),
- ?line 37489 = peek16(<<37489:16,5566:16>>),
- ?line fc(peek16, [<<8>>], catch peek16(<<8>>)),
- ?line fc(peek16, [<<42:15>>], catch peek16(<<42:15>>)),
- ?line fc(peek16, [<<1,2,3,4,5>>], catch peek16(<<1,2,3,4,5>>)),
-
- ?line 127 = peek7(<<127:7>>),
- ?line 100 = peek7(<<100:7,19:7>>),
- ?line fc(peek7, [<<1,2>>], catch peek7(<<1,2>>)),
+ 42 = peek1(<<42>>),
+ 43 = peek1(<<43,1,2>>),
+ 43 = peek1(<<43,1,2,(-1):1>>),
+ 43 = peek1(<<43,1,2,(-1):2>>),
+ 43 = peek1(<<43,1,2,(-1):7>>),
+
+ 99 = peek8(<<99>>),
+ 100 = peek8(<<100,101>>),
+ fc(peek8, [<<100,101,0:1>>], catch peek8(<<100,101,0:1>>)),
+
+ 37484 = peek16(<<37484:16>>),
+ 37489 = peek16(<<37489:16,5566:16>>),
+ fc(peek16, [<<8>>], catch peek16(<<8>>)),
+ fc(peek16, [<<42:15>>], catch peek16(<<42:15>>)),
+ fc(peek16, [<<1,2,3,4,5>>], catch peek16(<<1,2,3,4,5>>)),
+
+ 127 = peek7(<<127:7>>),
+ 100 = peek7(<<100:7,19:7>>),
+ fc(peek7, [<<1,2>>], catch peek7(<<1,2>>)),
ok.
peek1(<<B:8,_/bitstring>>) -> B.
@@ -422,7 +454,7 @@ peek8(<<B:8,_/binary>>) -> B.
peek16(<<B:16,_/binary-unit:16>>) -> B.
shared_sub_bins(Config) when is_list(Config) ->
- ?line {15,[<<>>,<<5>>,<<4,5>>,<<3,4,5>>,<<2,3,4,5>>]} = sum(<<1,2,3,4,5>>, [], 0),
+ {15,[<<>>,<<5>>,<<4,5>>,<<3,4,5>>,<<2,3,4,5>>]} = sum(<<1,2,3,4,5>>, [], 0),
ok.
sum(<<B,T/binary>>, Acc, Sum) ->
@@ -431,7 +463,7 @@ sum(<<>>, Last, Sum) -> {Sum,Last}.
bin_and_float(Config) when is_list(Config) ->
- ?line 14.0 = bin_and_float(<<1.0/float,2.0/float,3.0/float>>, 0.0),
+ 14.0 = bin_and_float(<<1.0/float,2.0/float,3.0/float>>, 0.0),
ok.
bin_and_float(<<X/float,Y/float,Z/float,T/binary>>, Sum) when is_float(X),
@@ -441,10 +473,10 @@ bin_and_float(<<X/float,Y/float,Z/float,T/binary>>, Sum) when is_float(X),
bin_and_float(<<>>, Sum) -> Sum.
dec_subidentifiers(Config) when is_list(Config) ->
- ?line {[],<<1,2,3>>} =
+ {[],<<1,2,3>>} =
do_dec_subidentifiers(<<1:1,42:7,1:1,99:7,1,2,3>>, 0, [], 2),
- ?line {[5389],<<1,2,3>>} = do_dec_subidentifiers(<<1:1,42:7,0:1,13:7,1,2,3>>, 0, [], 2),
- ?line {[3,2,1],not_a_binary} = dec_subidentifiers(not_a_binary, any, [1,2,3], 0),
+ {[5389],<<1,2,3>>} = do_dec_subidentifiers(<<1:1,42:7,0:1,13:7,1,2,3>>, 0, [], 2),
+ {[3,2,1],not_a_binary} = dec_subidentifiers(not_a_binary, any, [1,2,3], 0),
ok.
do_dec_subidentifiers(Buffer, Av, Al, Len) ->
@@ -495,23 +527,40 @@ skip_optional_tag(<<Tag,RestTag/binary>>, <<Tag,Rest/binary>>) ->
skip_optional_tag(RestTag, Rest);
skip_optional_tag(_, _) -> missing.
+decode_integer(_Config) ->
+ {10795,<<43>>,whatever} = decode_integer(1, <<42,43>>, whatever),
+ {-28909,<<19>>,whatever} = decode_integer(1, <<143,19>>, whatever),
+ ok.
+
+decode_integer(Len, <<B1:1,B2:7,Bs/binary>>, RemovedBytes) when B1 == 0 ->
+ Bin = <<_Skip:Len/unit:8, Buffer2/binary>> = <<B1:1,B2:7,Bs/binary>>,
+ Size = byte_size(Bin),
+ <<Int:Size/unit:8>> = Bin,
+ {Int,Buffer2,RemovedBytes};
+decode_integer(Len, <<B1:1,B2:7,Bs/binary>>, RemovedBytes) ->
+ Bin = <<_Skip:Len/unit:8,Buffer2/binary>> = <<B1:1,B2:7,Bs/binary>>,
+ Size = byte_size(Bin),
+ <<N:Size/unit:8>> = <<B2,Bs/binary>>,
+ Int = N - (1 bsl (8 * size(Bin) -1)),
+ {Int,Buffer2,RemovedBytes}.
+
-define(DATELEN, 16).
wfbm(Config) when is_list(Config) ->
%% check_for_dot_or_space and get_tail is from wfbm4 by Steve Vinoski,
%% with modifications.
- ?line {nomatch,0} = check_for_dot_or_space(<<" ">>),
- ?line {nomatch,0} = check_for_dot_or_space(<<" abc">>),
- ?line {ok,<<"abcde">>} = check_for_dot_or_space(<<"abcde 34555">>),
- ?line {nomatch,0} = check_for_dot_or_space(<<".gurka">>),
- ?line {nomatch,1} = check_for_dot_or_space(<<"g.urka">>),
-
- ?line nomatch = get_tail(<<>>),
- ?line {ok,<<"2007/10/23/blurf">>} = get_tail(<<"200x/2007/10/23/blurf ">>),
- ?line {skip,?DATELEN+5} = get_tail(<<"200x/2007/10/23/blurf.">>),
- ?line nomatch = get_tail(<<"200y.2007.10.23.blurf ">>),
- ?line {'EXIT',_} = (catch get_tail({no,binary,at,all})),
- ?line {'EXIT',_} = (catch get_tail(no_binary)),
+ {nomatch,0} = check_for_dot_or_space(<<" ">>),
+ {nomatch,0} = check_for_dot_or_space(<<" abc">>),
+ {ok,<<"abcde">>} = check_for_dot_or_space(<<"abcde 34555">>),
+ {nomatch,0} = check_for_dot_or_space(<<".gurka">>),
+ {nomatch,1} = check_for_dot_or_space(<<"g.urka">>),
+
+ nomatch = get_tail(<<>>),
+ {ok,<<"2007/10/23/blurf">>} = get_tail(<<"200x/2007/10/23/blurf ">>),
+ {skip,?DATELEN+5} = get_tail(<<"200x/2007/10/23/blurf.">>),
+ nomatch = get_tail(<<"200y.2007.10.23.blurf ">>),
+ {'EXIT',_} = (catch get_tail({no,binary,at,all})),
+ {'EXIT',_} = (catch get_tail(no_binary)),
ok.
check_for_dot_or_space(Bin) ->
@@ -544,13 +593,13 @@ get_tail(Bin) ->
end.
degenerated_match(Config) when is_list(Config) ->
- ?line error = degenerated_match_1(<<>>),
- ?line 1 = degenerated_match_1(<<1:1>>),
- ?line 2 = degenerated_match_1(<<42,43>>),
+ error = degenerated_match_1(<<>>),
+ 1 = degenerated_match_1(<<1:1>>),
+ 2 = degenerated_match_1(<<42,43>>),
- ?line error = degenerated_match_2(<<>>),
- ?line no_split = degenerated_match_2(<<1,2>>),
- ?line {<<1,2,3,4>>,<<5>>} = degenerated_match_2(<<1,2,3,4,5>>),
+ error = degenerated_match_2(<<>>),
+ no_split = degenerated_match_2(<<1,2>>),
+ {<<1,2,3,4>>,<<5>>} = degenerated_match_2(<<1,2,3,4,5>>),
ok.
@@ -567,25 +616,25 @@ degenerated_match_2(Bin) ->
end.
bs_sum(Config) when is_list(Config) ->
- ?line 0 = bs_sum_1([]),
- ?line 0 = bs_sum_1(<<>>),
- ?line 42 = bs_sum_1([42]),
- ?line 1 = bs_sum_1(<<1>>),
- ?line 10 = bs_sum_1([1,2,3,4]),
- ?line 15 = bs_sum_1(<<1,2,3,4,5>>),
- ?line 21 = bs_sum_1([1,2,3|<<4,5,6>>]),
- ?line 15 = bs_sum_1([1,2,3|{4,5}]),
- ?line 6 = bs_sum_1([1,2,3|zero]),
- ?line 6 = bs_sum_1([1,2,3|0]),
- ?line 7 = bs_sum_1([1,2,3|one]),
-
- ?line fc(catch bs_sum_1({too,big,tuple})),
- ?line fc(catch bs_sum_1([1,2,3|{too,big,tuple}])),
-
- ?line [] = sneaky_alias(<<>>),
- ?line [559,387655] = sneaky_alias(id(<<559:32,387655:32>>)),
- ?line fc(sneaky_alias, [<<1>>], catch sneaky_alias(id(<<1>>))),
- ?line fc(sneaky_alias, [[1,2,3,4]], catch sneaky_alias(lists:seq(1, 4))),
+ 0 = bs_sum_1([]),
+ 0 = bs_sum_1(<<>>),
+ 42 = bs_sum_1([42]),
+ 1 = bs_sum_1(<<1>>),
+ 10 = bs_sum_1([1,2,3,4]),
+ 15 = bs_sum_1(<<1,2,3,4,5>>),
+ 21 = bs_sum_1([1,2,3|<<4,5,6>>]),
+ 15 = bs_sum_1([1,2,3|{4,5}]),
+ 6 = bs_sum_1([1,2,3|zero]),
+ 6 = bs_sum_1([1,2,3|0]),
+ 7 = bs_sum_1([1,2,3|one]),
+
+ fc(catch bs_sum_1({too,big,tuple})),
+ fc(catch bs_sum_1([1,2,3|{too,big,tuple}])),
+
+ [] = sneaky_alias(<<>>),
+ [559,387655] = sneaky_alias(id(<<559:32,387655:32>>)),
+ fc(sneaky_alias, [<<1>>], catch sneaky_alias(id(<<1>>))),
+ fc(sneaky_alias, [[1,2,3,4]], catch sneaky_alias(lists:seq(1, 4))),
ok.
bs_sum_1(<<H,T/binary>>) -> H+bs_sum_1(T);
@@ -601,31 +650,31 @@ sneaky_alias(<<>>=L) -> binary_to_list(L);
sneaky_alias(<<From:32,L/binary>>) -> [From|sneaky_alias(L)].
coverage(Config) when is_list(Config) ->
- ?line 0 = coverage_fold(fun(B, A) -> A+B end, 0, <<>>),
- ?line 6 = coverage_fold(fun(B, A) -> A+B end, 0, <<1,2,3>>),
- ?line fc(catch coverage_fold(fun(B, A) ->
+ 0 = coverage_fold(fun(B, A) -> A+B end, 0, <<>>),
+ 6 = coverage_fold(fun(B, A) -> A+B end, 0, <<1,2,3>>),
+ fc(catch coverage_fold(fun(B, A) ->
A+B
end, 0, [a,b,c])),
- ?line {<<42.0:64/float>>,float} = coverage_build(<<>>, <<42>>, float),
- ?line {<<>>,not_a_tuple} = coverage_build(<<>>, <<>>, not_a_tuple),
- ?line {<<16#76,"abc",16#A9,"abc">>,{x,42,43}} =
+ {<<42.0:64/float>>,float} = coverage_build(<<>>, <<42>>, float),
+ {<<>>,not_a_tuple} = coverage_build(<<>>, <<>>, not_a_tuple),
+ {<<16#76,"abc",16#A9,"abc">>,{x,42,43}} =
coverage_build(<<>>, <<16#7,16#A>>, {x,y,z}),
- ?line [<<2>>,<<1>>] = coverage_bc(<<1,2>>, []),
+ [<<2>>,<<1>>] = coverage_bc(<<1,2>>, []),
- ?line {x,<<"abc">>,z} = coverage_setelement(<<2,"abc">>, {x,y,z}),
+ {x,<<"abc">>,z} = coverage_setelement(<<2,"abc">>, {x,y,z}),
- ?line [42] = coverage_apply(<<42>>, [coverage_id]),
- ?line 42 = coverage_external(<<42>>),
+ [42] = coverage_apply(<<42>>, [coverage_id]),
+ 42 = coverage_external(<<42>>),
- ?line do_coverage_bin_to_term_list([]),
- ?line do_coverage_bin_to_term_list([lists:seq(0, 10),{a,b,c},<<23:42>>]),
- ?line fc(coverage_bin_to_term_list, [<<0,0,0,7>>],
+ do_coverage_bin_to_term_list([]),
+ do_coverage_bin_to_term_list([lists:seq(0, 10),{a,b,c},<<23:42>>]),
+ fc(coverage_bin_to_term_list, [<<0,0,0,7>>],
catch do_coverage_bin_to_term_list_1(<<7:32>>)),
- ?line <<>> = coverage_per_key(<<4:32>>),
- ?line <<$a,$b,$c>> = coverage_per_key(<<7:32,"abc">>),
+ <<>> = coverage_per_key(<<4:32>>),
+ <<$a,$b,$c>> = coverage_per_key(<<7:32,"abc">>),
ok.
@@ -718,9 +767,14 @@ coverage_per_key(<<BinSize:32,Bin/binary>> = B) ->
Bin.
multiple_uses(Config) when is_list(Config) ->
- ?line {344,62879,345,<<245,159,1,89>>} = multiple_uses_1(<<1,88,245,159,1,89>>),
- ?line true = multiple_uses_2(<<0,0,197,18>>),
- ?line <<42,43>> = multiple_uses_3(<<0,0,42,43>>, fun id/1),
+ {344,62879,345,<<245,159,1,89>>} = multiple_uses_1(<<1,88,245,159,1,89>>),
+ true = multiple_uses_2(<<0,0,197,18>>),
+ <<42,43>> = multiple_uses_3(<<0,0,42,43>>, fun id/1),
+
+ ok = first_after(<<>>, 42),
+ <<1>> = first_after(<<1,2,3>>, 0),
+ <<2>> = first_after(<<1,2,3>>, 1),
+
ok.
multiple_uses_1(<<X:16,Tail/binary>>) ->
@@ -742,9 +796,27 @@ multiple_uses_match(<<Y:16,Z:16>>) ->
multiple_uses_cmp(<<Y:16>>, <<Y:16>>) -> true;
multiple_uses_cmp(<<_:16>>, <<_:16>>) -> false.
+first_after(Data, Offset) ->
+ case byte_size(Data) > Offset of
+ false ->
+ {First, Rest} = {ok, ok},
+ ok;
+ true ->
+ <<_:Offset/binary, Rest/binary>> = Data,
+ %% 'Rest' saved in y(0) before the call.
+ {First, _} = match_first(Data, Rest),
+ %% When beam_bsm sees the code, the following line
+ %% which uses y(0) has been optimized away.
+ {First, Rest} = {First, Rest},
+ First
+ end.
+
+match_first(_, <<First:1/binary, Rest/binary>>) ->
+ {First, Rest}.
+
zero_label(Config) when is_list(Config) ->
- ?line <<"nosemouth">> = read_pols(<<"FACE","nose","mouth">>),
- ?line <<"CE">> = read_pols(<<"noFACE">>),
+ <<"nosemouth">> = read_pols(<<"FACE","nose","mouth">>),
+ <<"CE">> = read_pols(<<"noFACE">>),
ok.
read_pols(Data) ->
@@ -772,14 +844,14 @@ matching_meets_construction(Config) when is_list(Config) ->
Bin = id(<<"abc">>),
Len = id(2),
Tail0 = id(<<1,2,3,4,5>>),
- ?line <<_:Len/binary,Tail/binary>> = Tail0,
- ?line Res = <<Tail/binary,Bin/binary>>,
- ?line <<3,4,5,"abc">> = Res,
- ?line {'EXIT',{badarg,_}} = (catch matching_meets_construction_1(<<"Abc">>)),
- ?line {'EXIT',{badarg,_}} = (catch matching_meets_construction_2(<<"Abc">>)),
- ?line <<"Bbc">> = matching_meets_construction_3(<<"Abc">>),
-
- ?line <<1,2>> = encode_octet_string(<<1,2,3>>, 2),
+ <<_:Len/binary,Tail/binary>> = Tail0,
+ Res = <<Tail/binary,Bin/binary>>,
+ <<3,4,5,"abc">> = Res,
+ {'EXIT',{badarg,_}} = (catch matching_meets_construction_1(<<"Abc">>)),
+ {'EXIT',{badarg,_}} = (catch matching_meets_construction_2(<<"Abc">>)),
+ <<"Bbc">> = matching_meets_construction_3(<<"Abc">>),
+
+ <<1,2>> = encode_octet_string(<<1,2,3>>, 2),
ok.
matching_meets_construction_1(<<"A",H/binary>>) -> <<"B",H>>.
@@ -792,14 +864,14 @@ encode_octet_string(<<OctetString/binary>>, Len) ->
<<OctetString:Len/binary-unit:8>>.
simon(Config) when is_list(Config) ->
- ?line one = simon(blurf, <<>>),
- ?line two = simon(0, <<42>>),
- ?line fc(simon, [17,<<1>>], catch simon(17, <<1>>)),
- ?line fc(simon, [0,<<1,2,3>>], catch simon(0, <<1,2,3>>)),
-
- ?line one = simon2(blurf, <<9>>),
- ?line two = simon2(0, <<9,1>>),
- ?line fc(simon2, [0,<<9,10,11>>], catch simon2(0, <<9,10,11>>)),
+ one = simon(blurf, <<>>),
+ two = simon(0, <<42>>),
+ fc(simon, [17,<<1>>], catch simon(17, <<1>>)),
+ fc(simon, [0,<<1,2,3>>], catch simon(0, <<1,2,3>>)),
+
+ one = simon2(blurf, <<9>>),
+ two = simon2(0, <<9,1>>),
+ fc(simon2, [0,<<9,10,11>>], catch simon2(0, <<9,10,11>>)),
ok.
simon(_, <<>>) -> one;
@@ -811,33 +883,46 @@ simon2(0, <<_:16>>) -> two.
%% OTP-7113: Crash in v3_codegen.
matching_and_andalso(Config) when is_list(Config) ->
- ?line ok = matching_and_andalso_1(<<1,2,3>>, 3),
- ?line {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, -8)),
- ?line {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, blurf)),
- ?line {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, 19)),
-
- {"abc",<<"xyz">>} = matching_and_andalso_2("abc", <<"-xyz">>),
- {"abc",<<"">>} = matching_and_andalso_2("abc", <<($a-1)>>),
- {"abc",<<"">>} = matching_and_andalso_2("abc", <<($z+1)>>),
- {"abc",<<"">>} = matching_and_andalso_2("abc", <<($A-1)>>),
- {"abc",<<"">>} = matching_and_andalso_2("abc", <<($Z+1)>>),
- error = matching_and_andalso_2([], <<>>),
- error = matching_and_andalso_2([], <<$A>>),
- error = matching_and_andalso_2([], <<$Z>>),
- error = matching_and_andalso_2([], <<$a>>),
- error = matching_and_andalso_2([], <<$z>>),
+ ok = matching_and_andalso_1(<<1,2,3>>, 3),
+ {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, -8)),
+ {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, blurf)),
+ {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, 19)),
+
+ {"abc",<<"xyz">>} = matching_and_andalso_23("abc", <<"-xyz">>),
+ {"abc",<<"">>} = matching_and_andalso_23("abc", <<($a-1)>>),
+ {"abc",<<"">>} = matching_and_andalso_23("abc", <<($z+1)>>),
+ {"abc",<<"">>} = matching_and_andalso_23("abc", <<($A-1)>>),
+ {"abc",<<"">>} = matching_and_andalso_23("abc", <<($Z+1)>>),
+ error = matching_and_andalso_23([], <<>>),
+ error = matching_and_andalso_23([], <<$A>>),
+ error = matching_and_andalso_23([], <<$Z>>),
+ error = matching_and_andalso_23([], <<$a>>),
+ error = matching_and_andalso_23([], <<$z>>),
ok.
matching_and_andalso_1(<<Bitmap/binary>>, K)
when is_integer(K) andalso size(Bitmap) >= K andalso 0 < K ->
ok.
+matching_and_andalso_23(Datetime, Bin) ->
+ Res = matching_and_andalso_2(Datetime, Bin),
+ Res = matching_and_andalso_3(Datetime, Bin),
+ Res.
+
matching_and_andalso_2(Datetime, <<H,T/binary>>)
when not ((H >= $a) andalso (H =< $z)) andalso
not ((H >= $A) andalso (H =< $Z)) ->
{Datetime,T};
matching_and_andalso_2(_, _) -> error.
+%% Contrived example to ensure we cover the handling of 'call' instructions
+%% in v3_codegen:bsm_rename_ctx/4.
+matching_and_andalso_3(Datetime, <<H,T/binary>>)
+ when not ((abs(H) >= $a) andalso (abs(H) =< $z)) andalso
+ not ((abs(H) >= $A) andalso (abs(H) =< $Z)) ->
+ {Datetime,T};
+matching_and_andalso_3(_, _) -> error.
+
%% Thanks to Tomas Stejskal.
otp_7188(Config) when is_list(Config) ->
MP3 = <<84,65,71,68,117,154,105,232,107,121,0,0,0,0,0,0,0,0,0,0,
@@ -847,7 +932,7 @@ otp_7188(Config) when is_list(Config) ->
0,0,0,0,0,0,50,48,48,48,50,48,48,48,32,45,32,66,101,115,
116,32,79,102,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
32,32,12>>,
- ?line {ok,{"ID3v1",
+ {ok,{"ID3v1",
[{title,<<68,117,154,105,232,107,121>>},
{artist,<<"Daniel Landa">>},
{album,<<"Best Of">>}]}} = parse_v1_or_v11_tag(MP3).
@@ -891,11 +976,11 @@ skip_blanks_and_zero(L) ->
-record(rec_otp_7233, {key, val}).
otp_7233(Config) when is_list(Config) ->
- ?line otp_7233_1(#rec_otp_7233{key = <<"XXabcde">>,val=[{"xxxxxxxx",42}]}),
- ?line [<<"XXabcde">>,{"xxxxxxxx",42}] = get(io_format),
+ otp_7233_1(#rec_otp_7233{key = <<"XXabcde">>,val=[{"xxxxxxxx",42}]}),
+ [<<"XXabcde">>,{"xxxxxxxx",42}] = get(io_format),
erase(io_format),
- ?line otp_7233_1(#rec_otp_7233{key = <<"XXabcde">>,val=[]}),
- ?line undefined = get(io_format),
+ otp_7233_1(#rec_otp_7233{key = <<"XXabcde">>,val=[]}),
+ undefined = get(io_format),
ok.
otp_7233_1(Rec) ->
@@ -903,32 +988,34 @@ otp_7233_1(Rec) ->
case K of
<<"XX">> ->
Value = Rec#rec_otp_7233.val,
- case lists:keysearch("xxxxxxxx", 1, Value) of
- {value,T} -> put(io_format, [Rec#rec_otp_7233.key,T]);
- false -> ok
+ case lists:keyfind("xxxxxxxx", 1, Value) of
+ false ->
+ ok;
+ T ->
+ put(io_format, [Rec#rec_otp_7233.key,T])
end;
_ -> ok
end.
otp_7240(Config) when is_list(Config) ->
- ?line a = otp_7240_a(0, <<>>),
- ?line b = otp_7240_a(1, 2),
+ a = otp_7240_a(0, <<>>),
+ b = otp_7240_a(1, 2),
- ?line a = otp_7240_b(anything, <<>>),
- ?line b = otp_7240_b(1, {x,y}),
+ a = otp_7240_b(anything, <<>>),
+ b = otp_7240_b(1, {x,y}),
- ?line a = otp_7240_c(anything, <<>>),
- ?line b = otp_7240_c(1, <<2>>),
+ a = otp_7240_c(anything, <<>>),
+ b = otp_7240_c(1, <<2>>),
- ?line a = otp_7240_d(anything, <<>>),
- ?line b = otp_7240_d(again, <<2>>),
+ a = otp_7240_d(anything, <<>>),
+ b = otp_7240_d(again, <<2>>),
- ?line a = otp_7240_e(anything, <<>>),
- ?line b = otp_7240_e(1, 41),
+ a = otp_7240_e(anything, <<>>),
+ b = otp_7240_e(1, 41),
- ?line a = otp_7240_f(anything, <<>>),
- ?line b = otp_7240_f(1, {}),
+ a = otp_7240_f(anything, <<>>),
+ b = otp_7240_f(1, {}),
ok.
@@ -951,15 +1038,15 @@ otp_7240_f(_, <<>>) -> a;
otp_7240_f(1, B) when is_tuple(B) -> b.
otp_7498(Config) when is_list(Config) ->
- ?line <<1,2,3>> = otp_7498_foo(<<1,2,3>>, 0),
- ?line <<2,3>> = otp_7498_foo(<<1,2,3>>, 1),
- ?line <<1,2,3>> = otp_7498_foo(<<1,2,3>>, 2),
+ <<1,2,3>> = otp_7498_foo(<<1,2,3>>, 0),
+ <<2,3>> = otp_7498_foo(<<1,2,3>>, 1),
+ <<1,2,3>> = otp_7498_foo(<<1,2,3>>, 2),
- ?line <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 0),
- ?line <<2,3>> = otp_7498_bar(<<1,2,3>>, 1),
- ?line <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 2),
- ?line <<>> = otp_7498_bar(<<>>, 2),
- ?line <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 3),
+ <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 0),
+ <<2,3>> = otp_7498_bar(<<1,2,3>>, 1),
+ <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 2),
+ <<>> = otp_7498_bar(<<>>, 2),
+ <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 3),
ok.
@@ -988,19 +1075,19 @@ match_string(Config) when is_list(Config) ->
%% check the coverage for the v3_kernel module.
case erlang:system_info(endian) of
little ->
- ?line do_match_string_native(<<$a,0,$b,0>>);
+ do_match_string_native(<<$a,0,$b,0>>);
big ->
- ?line do_match_string_native(<<0,$a,0,$b>>)
+ do_match_string_native(<<0,$a,0,$b>>)
end,
- ?line do_match_string_big(<<0,$a,0,$b>>),
- ?line do_match_string_little(<<$a,0,$b,0>>),
+ do_match_string_big(<<0,$a,0,$b>>),
+ do_match_string_little(<<$a,0,$b,0>>),
- ?line do_match_string_big_signed(<<255,255>>),
- ?line do_match_string_little_signed(<<255,255>>),
+ do_match_string_big_signed(<<255,255>>),
+ do_match_string_little_signed(<<255,255>>),
- ?line plain = no_match_string_opt(<<"abc">>),
- ?line strange = no_match_string_opt(<<$a:9,$b:9,$c:9>>),
+ plain = no_match_string_opt(<<"abc">>),
+ strange = no_match_string_opt(<<$a:9,$b:9,$c:9>>),
ok.
@@ -1021,13 +1108,13 @@ no_match_string_opt(<<$a:9,$b:9,$c:9>>) -> strange.
%% OTP-7591: A zero-width segment in matching would crash the compiler.
zero_width(Config) when is_list(Config) ->
- ?line <<Len:16/little, Str:Len/binary, 0:0>> = <<2, 0, $h, $i, 0:0>>,
- ?line 2 = Len,
- ?line Str = <<"hi">>,
+ <<Len:16/little, Str:Len/binary, 0:0>> = <<2, 0, $h, $i, 0:0>>,
+ 2 = Len,
+ Str = <<"hi">>,
%% Match sure that values that cannot fit in a segment will not match.
case id(<<0:8>>) of
- <<256:8>> -> ?line ?t:fail();
+ <<256:8>> -> ct:fail(should_not_match);
_ -> ok
end,
ok.
@@ -1036,14 +1123,14 @@ zero_width(Config) when is_list(Config) ->
%% OTP_7650: A invalid size for binary segments could crash the compiler.
bad_size(Config) when is_list(Config) ->
Tuple = {a,b,c},
- ?line {'EXIT',{{badmatch,<<>>},_}} = (catch <<32:Tuple>> = id(<<>>)),
+ {'EXIT',{{badmatch,<<>>},_}} = (catch <<32:Tuple>> = id(<<>>)),
Binary = <<1,2,3>>,
- ?line {'EXIT',{{badmatch,<<>>},_}} = (catch <<32:Binary>> = id(<<>>)),
+ {'EXIT',{{badmatch,<<>>},_}} = (catch <<32:Binary>> = id(<<>>)),
ok.
haystack(Config) when is_list(Config) ->
- ?line <<0:10/unit:8>> = haystack_1(<<0:10/unit:8>>),
- ?line [<<0:10/unit:8>>,
+ <<0:10/unit:8>> = haystack_1(<<0:10/unit:8>>),
+ [<<0:10/unit:8>>,
<<0:20/unit:8>>] = haystack_2(<<1:8192>>),
ok.
@@ -1078,10 +1165,10 @@ fc(_, Args, {'EXIT',{{case_clause,ActualArgs},_}})
%% Cover the clause handling bs_context to binary in
%% beam_block:initialized_regs/2.
cover_beam_bool(Config) when is_list(Config) ->
- ?line ok = do_cover_beam_bool(<<>>, 3),
- ?line <<19>> = do_cover_beam_bool(<<19>>, 2),
- ?line <<42>> = do_cover_beam_bool(<<42>>, 1),
- ?line <<17>> = do_cover_beam_bool(<<13,17>>, 0),
+ ok = do_cover_beam_bool(<<>>, 3),
+ <<19>> = do_cover_beam_bool(<<19>>, 2),
+ <<42>> = do_cover_beam_bool(<<42>>, 1),
+ <<17>> = do_cover_beam_bool(<<13,17>>, 0),
ok.
do_cover_beam_bool(Bin, X) when X > 0 ->
@@ -1227,6 +1314,21 @@ match_string_opt(Config) when is_list(Config) ->
do_match_string_opt({<<1>>,{v,V}}=T) ->
{x,V,T}.
+select_on_integer(Config) when is_list(Config) ->
+ 42 = do_select_on_integer(<<42>>),
+ <<"abc">> = do_select_on_integer(<<128,"abc">>),
+
+ {'EXIT',_} = (catch do_select_on_integer(<<0:1>>)),
+ {'EXIT',_} = (catch do_select_on_integer(<<1:1>>)),
+ {'EXIT',_} = (catch do_select_on_integer(<<0:1,0:15>>)),
+ ok.
+
+%% The ASN.1 compiler frequently generates code like this.
+do_select_on_integer(<<0:1,I:7>>) ->
+ I;
+do_select_on_integer(<<1:1,_:7,Bin/binary>>) ->
+ Bin.
+
%% If 'bin_opt_info' was given the warning would lack filename
%% and line number.
@@ -1271,6 +1373,190 @@ do_unsafe_branch_caching(<<Code/integer, Bin/binary>>) ->
_ -> Bin2
end.
+bad_literals(_Config) ->
+ Mod = list_to_atom(?MODULE_STRING ++ "_" ++
+ atom_to_list(?FUNCTION_NAME)),
+ S = [signed_lit_match(V, Sz) || V <- lists:seq(-8, 8),
+ Sz <- [0,1,2,3]] ++
+ [unsigned_lit_match(V, Sz) || V <- lists:seq(-2, 8),
+ Sz <- [0,1,2]] ++
+ [unicode_match(V) ||
+ V <- [-100,-1,0,1,2|lists:seq(16#10FFFC, 16#110004)]],
+ Code = ?Q(["-module('@Mod@').\n"
+ "-export([f/0]).\n"
+ "f() ->\n"
+ "_@S,\n"
+ "ok.\n"]),
+ merl:print(Code),
+ Opts = test_lib:opt_opts(?MODULE),
+ {ok,_} = merl:compile_and_load(Code, Opts),
+ Mod:f(),
+
+ {'EXIT',<<42>>} = (catch bad_literals_1()),
+
+ Sz = id(8),
+ {'EXIT',{{badmatch,_},_}} = (catch <<-1:Sz>> = <<-1>>),
+ ok.
+
+bad_literals_1() ->
+ BadSz = bad,
+ case case <<42>> of
+ <<42:BadSz>> -> ok;
+ Val -> exit(Val)
+ end of
+ ok -> ok;
+ error -> error
+ end.
+
+signed_lit_match(V, Sz) ->
+ case <<V:Sz>> of
+ <<V:Sz/signed>> ->
+ ?Q("<<_@V@:_@Sz@/signed>> = <<_@V@:_@Sz@>>");
+ _ ->
+ ?Q(["case <<_@V@:_@Sz@>> of\n",
+ " <<_@V@:_@Sz@/signed>> ->\n",
+ " ct:fail(should_not_match);\n",
+ " _ ->\n",
+ " ok\n",
+ "end\n"])
+ end.
+
+unsigned_lit_match(V, Sz) ->
+ case <<V:Sz>> of
+ <<V:Sz/unsigned>> ->
+ ?Q("<<_@V@:_@Sz@>> = <<_@V@:_@Sz@>>");
+ _ ->
+ ?Q(["case <<_@V@:_@Sz@>> of\n",
+ " <<_@V@:_@Sz@/unsigned>> ->\n",
+ " ct:fail(should_not_match);\n",
+ " _ ->\n",
+ " ok\n",
+ "end\n"])
+ end.
+
+unicode_match(V) ->
+ try <<V/utf8>> of
+ <<V/utf8>> ->
+ ?Q(["<<_@V@/utf8>> = <<_@V@/utf8>>,\n",
+ "<<_@V@/utf16>> = <<_@V@/utf16>>,\n",
+ "<<_@V@/utf32>> = <<_@V@/utf32>>\n"])
+ catch
+ error:badarg ->
+ ?Q(["case <<_@V@:32>> of\n",
+ " <<_@V@/utf32>> ->\n",
+ " ct:fail(should_not_match);\n",
+ " _ ->\n",
+ " ok\n",
+ "end\n"])
+ end.
+
+%% Test a few legal but rare cases.
+
+good_literals(_Config) ->
+ Sz = id(64),
+
+ %% Variable size.
+ <<42:Sz>> = id(<<42:Sz>>),
+ <<42.0:Sz/float>> = id(<<42:Sz/float>>),
+
+ %% unit > 1
+ <<16#cafebeef:4/unit:8>> = id(<<16#cafebeef:32>>),
+ ok.
+
+constant_propagation(_Config) ->
+ <<5>> = constant_propagation_a(a, <<5>>),
+ {'EXIT',{{case_clause,b},_}} = (catch constant_propagation_a(b, <<5>>)),
+ 258 = constant_propagation_b(<<1,2>>),
+ F = constant_propagation_c(),
+ 259 = F(<<1,3>>),
+ ok.
+
+constant_propagation_a(X, Y) ->
+ case X of
+ a -> Y2 = 8
+ end,
+ <<5:Y2>> = Y.
+
+constant_propagation_b(B) ->
+ Sz = 16,
+ <<X:Sz/integer>> = B,
+ X.
+
+constant_propagation_c() ->
+ Size = 16,
+ fun(Bin) ->
+ <<X:Size/integer>> = Bin,
+ X
+ end.
+
+parse_xml(_Config) ->
+ <<"<?xmlX">> = do_parse_xml(<<"<?xmlX">>),
+ <<" ">> = do_parse_xml(<<"<?xml ">>),
+ ok.
+
+do_parse_xml(<<"<?xml"/utf8,Rest/binary>> = Bytes) ->
+ %% Delayed sub-binary creation is not safe. A buggy (development)
+ %% version of check_liveness_everywhere() in beam_utils would turn
+ %% on the optimization.
+ Rest1 = case is_next_char_whitespace(Rest) of
+ false ->
+ Bytes;
+ true ->
+ id(Rest)
+ end,
+ id(Rest1).
+
+is_next_char_whitespace(<<C/utf8,_/binary>>) ->
+ C =:= $\s.
+
+-record(ext_header,
+ {this_hdr = 17,
+ ext_hdr_opts}).
+
+get_payload(Config) ->
+ <<3445:48>> = do_get_payload(#ext_header{ext_hdr_opts = <<3445:48>>}),
+ {'EXIT',_} = (catch do_get_payload(#ext_header{})),
+ ok.
+
+do_get_payload(ExtHdr) ->
+ _ = ExtHdr#ext_header.this_hdr,
+ ExtHdrOptions = ExtHdr#ext_header.ext_hdr_opts,
+ <<_:13,_:35>> = ExtHdr#ext_header.ext_hdr_opts,
+ ExtHdrOptions.
+
+%% ERL-490
+num_slots_different(_Config) ->
+ Ts = [{<<"de">>, <<"default">>, <<"Remove">>, <<"a">>},
+ {<<"de">>, <<"default">>, <<"Remove from list">>, <<"a">>},
+ {<<"de">>, <<"default">>, <<"Remove from the list">>, <<"a">>},
+ {<<"de">>, <<"default">>, <<"Results">>, <<"Ergebnisse">>},
+ {<<"de">>, <<"default">>, <<"Reservatio">>, <<"a">>},
+ {<<"de">>, <<"navigation">>, <<"Results">>, <<"Ergebnisse">>},
+ {<<"de">>, <<"navigation">>, <<"Resources">>, <<"Ressourcen">>}],
+ _ = [{ok,Res} = lgettext(A, B, C) || {A,B,C,Res} <- Ts],
+
+ {'EXIT',_} = (catch lgettext(<<"d">>, <<"default">>, <<"Remove">>)),
+ {'EXIT',_} = (catch lgettext("", <<"default">>, <<"Remove">>)),
+ {'EXIT',_} = (catch lgettext(<<"de">>, <<"def">>, <<"Remove">>)),
+ {'EXIT',_} = (catch lgettext(<<"de">>, <<"default">>, <<"Res">>)),
+ ok.
+
+
+lgettext(<<"de">>, <<"default">>, <<"Remove">>) ->
+ {ok, <<"a">>};
+lgettext(<<"de">>, <<"default">>, <<"Remove from list">>) ->
+ {ok, <<"a">>};
+lgettext(<<"de">>, <<"default">>, <<"Remove from the list">>) ->
+ {ok, <<"a">>};
+lgettext(<<"de">>, <<"default">>, <<"Results">>) ->
+ {ok, <<"Ergebnisse">>};
+lgettext(<<"de">>, <<"default">>, <<"Reservatio">>) ->
+ {ok, <<"a">>};
+lgettext(<<"de">>, <<"navigation">>, <<"Results">>) ->
+ {ok, <<"Ergebnisse">>};
+lgettext(<<"de">>, <<"navigation">>, <<"Resources">>) ->
+ {ok, <<"Ressourcen">>}.
+
check(F, R) ->
R = F().
diff --git a/lib/compiler/test/bs_utf_SUITE.erl b/lib/compiler/test/bs_utf_SUITE.erl
index e6d292d9e6..ef3fc54b37 100644
--- a/lib/compiler/test/bs_utf_SUITE.erl
+++ b/lib/compiler/test/bs_utf_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@
utf32_roundtrip/1,guard/1,extreme_tripping/1,
literals/1,coverage/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -53,14 +53,14 @@ end_per_group(_GroupName, Config) ->
utf8_roundtrip(Config) when is_list(Config) ->
- ?line [utf8_roundtrip_1(P) || P <- utf_data()],
+ [utf8_roundtrip_1(P) || P <- utf_data()],
ok.
utf8_roundtrip_1({Str,Bin,Bin}) ->
- ?line Str = utf8_to_list(Bin),
- ?line Bin = list_to_utf8(Str),
- ?line [ok = utf8_guard(C, <<42,C/utf8>>) || C <- Str],
- ?line [error = utf8_guard(C, <<C/utf8>>) || C <- Str],
+ Str = utf8_to_list(Bin),
+ Bin = list_to_utf8(Str),
+ [ok = utf8_guard(C, <<42,C/utf8>>) || C <- Str],
+ [error = utf8_guard(C, <<C/utf8>>) || C <- Str],
ok.
utf8_guard(C, Bin) when <<42,C/utf8>> =:= Bin -> ok;
@@ -90,14 +90,14 @@ utf8_len(<<_/utf8,T/binary>>, N) ->
utf8_len(<<>>, N) -> N.
utf16_roundtrip(Config) when is_list(Config) ->
- ?line {Str,Big,Big,Little,Little} = utf16_data(),
- ?line 4 = utf16_big_len(Big),
- ?line 4 = utf16_little_len(Little),
- ?line Str = big_utf16_to_list(Big),
- ?line Str = little_utf16_to_list(Little),
+ {Str,Big,Big,Little,Little} = utf16_data(),
+ 4 = utf16_big_len(Big),
+ 4 = utf16_little_len(Little),
+ Str = big_utf16_to_list(Big),
+ Str = little_utf16_to_list(Little),
- ?line Big = list_to_big_utf16(Str),
- ?line Little = list_to_little_utf16(Str),
+ Big = list_to_big_utf16(Str),
+ Little = list_to_little_utf16(Str),
ok.
@@ -138,14 +138,14 @@ little_utf16_to_list(<<H/little-utf16,T/binary>>) ->
little_utf16_to_list(<<>>) -> [].
utf32_roundtrip(Config) when is_list(Config) ->
- ?line {Str,Big,Big,Little,Little} = utf32_data(),
- ?line 4 = utf32_big_len(Big),
- ?line 4 = utf32_little_len(Little),
- ?line Str = big_utf32_to_list(Big),
- ?line Str = little_utf32_to_list(Little),
+ {Str,Big,Big,Little,Little} = utf32_data(),
+ 4 = utf32_big_len(Big),
+ 4 = utf32_little_len(Little),
+ Str = big_utf32_to_list(Big),
+ Str = little_utf32_to_list(Little),
- ?line Big = list_to_big_utf32(Str),
- ?line Little = list_to_little_utf32(Str),
+ Big = list_to_big_utf32(Str),
+ Little = list_to_little_utf32(Str),
ok.
@@ -187,7 +187,7 @@ little_utf32_to_list(<<>>) -> [].
guard(Config) when is_list(Config) ->
- ?line error = do_guard(16#D800),
+ error = do_guard(16#D800),
ok.
do_guard(C) when byte_size(<<C/utf8>>) =/= 42 -> ok;
@@ -199,13 +199,13 @@ do_guard(_) -> error.
%% the delayed creation of sub-binaries works.
extreme_tripping(Config) when is_list(Config) ->
- ?line Unicode = lists:seq(0, 1024),
- ?line Utf8 = unicode_to_utf8(Unicode, <<>>),
- ?line Utf16 = utf8_to_utf16(Utf8, <<>>),
- ?line Utf32 = utf8_to_utf32(Utf8, <<>>),
- ?line Utf32 = utf16_to_utf32(Utf16, <<>>),
- ?line Utf8 = utf32_to_utf8(Utf32, <<>>),
- ?line Unicode = utf32_to_unicode(Utf32),
+ Unicode = lists:seq(0, 1024),
+ Utf8 = unicode_to_utf8(Unicode, <<>>),
+ Utf16 = utf8_to_utf16(Utf8, <<>>),
+ Utf32 = utf8_to_utf32(Utf8, <<>>),
+ Utf32 = utf16_to_utf32(Utf16, <<>>),
+ Utf8 = utf32_to_utf8(Utf32, <<>>),
+ Unicode = utf32_to_unicode(Utf32),
ok.
unicode_to_utf8([C|T], Bin) ->
@@ -233,58 +233,59 @@ utf32_to_unicode(<<C/utf32,T/binary>>) ->
utf32_to_unicode(<<>>) -> [].
literals(Config) when is_list(Config) ->
- ?line abc_utf8 = match_literal(<<"abc"/utf8>>),
- ?line abc_utf8 = match_literal(<<$a,$b,$c>>),
-
- ?line abc_utf16be = match_literal(<<"abc"/utf16>>),
- ?line abc_utf16be = match_literal(<<$a:16,$b:16,$c:16>>),
- ?line abc_utf16le = match_literal(<<"abc"/little-utf16>>),
- ?line abc_utf16le = match_literal(<<$a:16/little,$b:16/little,$c:16/little>>),
-
- ?line abc_utf32be = match_literal(<<"abc"/utf32>>),
- ?line abc_utf32be = match_literal(<<$a:32,$b:32,$c:32>>),
- ?line abc_utf32le = match_literal(<<"abc"/little-utf32>>),
- ?line abc_utf32le = match_literal(<<$a:32/little,$b:32/little,$c:32/little>>),
-
- ?line bjorn_utf8 = match_literal(<<"bj\366rn"/utf8>>),
- ?line bjorn_utf8 = match_literal(<<$b,$j,195,182,$r,$n>>),
-
- ?line bjorn_utf16be = match_literal(<<"bj\366rn"/utf16>>),
- ?line bjorn_utf16be = match_literal(<<$b:16,$j:16,246:16,$r:16,$n:16>>),
- ?line bjorn_utf16le = match_literal(<<"bj\366rn"/little-utf16>>),
- ?line bjorn_utf16le = match_literal(<<$b:16/little,$j:16/little,
+ abc_utf8 = match_literal(<<"abc"/utf8>>),
+ abc_utf8 = match_literal(<<$a,$b,$c>>),
+ abc_utf8 = match_literal(<<$a/utf8,$b/utf8,$c/utf8>>),
+
+ abc_utf16be = match_literal(<<"abc"/utf16>>),
+ abc_utf16be = match_literal(<<$a:16,$b:16,$c:16>>),
+ abc_utf16le = match_literal(<<"abc"/little-utf16>>),
+ abc_utf16le = match_literal(<<$a:16/little,$b:16/little,$c:16/little>>),
+
+ abc_utf32be = match_literal(<<"abc"/utf32>>),
+ abc_utf32be = match_literal(<<$a:32,$b:32,$c:32>>),
+ abc_utf32le = match_literal(<<"abc"/little-utf32>>),
+ abc_utf32le = match_literal(<<$a:32/little,$b:32/little,$c:32/little>>),
+
+ bjorn_utf8 = match_literal(<<"bj\366rn"/utf8>>),
+ bjorn_utf8 = match_literal(<<$b,$j,195,182,$r,$n>>),
+
+ bjorn_utf16be = match_literal(<<"bj\366rn"/utf16>>),
+ bjorn_utf16be = match_literal(<<$b:16,$j:16,246:16,$r:16,$n:16>>),
+ bjorn_utf16le = match_literal(<<"bj\366rn"/little-utf16>>),
+ bjorn_utf16le = match_literal(<<$b:16/little,$j:16/little,
246:16/little,$r:16/little,
$n:16/little>>),
- ?line <<244,143,191,191>> = <<16#10ffff/utf8>>,
+ <<244,143,191,191>> = <<16#10ffff/utf8>>,
%% Invalid literals.
I = 0,
- ?line {'EXIT',{badarg,_}} = (catch <<(-1)/utf8,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<(-1)/utf16,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<(-1)/little-utf16,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<(-1)/utf32,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<(-1)/little-utf32,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#D800/utf8,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#D800/utf16,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#D800/little-utf16,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#D800/utf32,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#D800/little-utf32,I/utf8>>),
+ {'EXIT',{badarg,_}} = (catch <<(-1)/utf8,I/utf8>>),
+ {'EXIT',{badarg,_}} = (catch <<(-1)/utf16,I/utf8>>),
+ {'EXIT',{badarg,_}} = (catch <<(-1)/little-utf16,I/utf8>>),
+ {'EXIT',{badarg,_}} = (catch <<(-1)/utf32,I/utf8>>),
+ {'EXIT',{badarg,_}} = (catch <<(-1)/little-utf32,I/utf8>>),
+ {'EXIT',{badarg,_}} = (catch <<16#D800/utf8,I/utf8>>),
+ {'EXIT',{badarg,_}} = (catch <<16#D800/utf16,I/utf8>>),
+ {'EXIT',{badarg,_}} = (catch <<16#D800/little-utf16,I/utf8>>),
+ {'EXIT',{badarg,_}} = (catch <<16#D800/utf32,I/utf8>>),
+ {'EXIT',{badarg,_}} = (catch <<16#D800/little-utf32,I/utf8>>),
B = 16#10FFFF+1,
- ?line {'EXIT',{badarg,_}} = (catch <<B/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<B/utf16>>),
- ?line {'EXIT',{badarg,_}} = (catch <<B/little-utf16>>),
- ?line {'EXIT',{badarg,_}} = (catch <<B/utf32>>),
- ?line {'EXIT',{badarg,_}} = (catch <<B/little-utf32>>),
+ {'EXIT',{badarg,_}} = (catch <<B/utf8>>),
+ {'EXIT',{badarg,_}} = (catch <<B/utf16>>),
+ {'EXIT',{badarg,_}} = (catch <<B/little-utf16>>),
+ {'EXIT',{badarg,_}} = (catch <<B/utf32>>),
+ {'EXIT',{badarg,_}} = (catch <<B/little-utf32>>),
%% Matching of bad literals.
- ?line error = bad_literal_match(<<237,160,128>>), %16#D800 in UTF-8
- ?line error = bad_literal_match(<<244,144,128,128>>), %16#110000 in UTF-8
+ error = bad_literal_match(<<237,160,128>>), %16#D800 in UTF-8
+ error = bad_literal_match(<<244,144,128,128>>), %16#110000 in UTF-8
- ?line error = bad_literal_match(<<16#D800:32>>),
- ?line error = bad_literal_match(<<16#110000:32>>),
- ?line error = bad_literal_match(<<16#D800:32/little>>),
- ?line error = bad_literal_match(<<16#110000:32/little>>),
+ error = bad_literal_match(<<16#D800:32>>),
+ error = bad_literal_match(<<16#110000:32>>),
+ error = bad_literal_match(<<16#D800:32/little>>),
+ error = bad_literal_match(<<16#110000:32/little>>),
ok.
@@ -307,13 +308,13 @@ bad_literal_match(_) -> error.
coverage(Config) when is_list(Config) ->
%% Cover bit syntax matching optimizations in v3_kernel.
- ?line 0 = coverage_1(<<4096/utf8,65536/utf8,0>>),
- ?line 1 = coverage_1(<<4096/utf8,65536/utf8,1>>),
+ 0 = coverage_1(<<4096/utf8,65536/utf8,0>>),
+ 1 = coverage_1(<<4096/utf8,65536/utf8,1>>),
- ?line 0 = coverage_2(<<4096/utf8,65536/utf8,0>>),
- ?line 1 = coverage_2(<<1024/utf8,1025/utf8,1>>),
+ 0 = coverage_2(<<4096/utf8,65536/utf8,0>>),
+ 1 = coverage_2(<<1024/utf8,1025/utf8,1>>),
- ?line fc(catch coverage_3(1)),
+ fc(catch coverage_3(1)),
%% Cover beam_flatten (combining the heap allocation in
%% a subsequent test_heap instruction into the bs_init2
diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl
index 2715a3aec5..a4de125d32 100644
--- a/lib/compiler/test/compilation_SUITE.erl
+++ b/lib/compiler/test/compilation_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. 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.
@@ -19,12 +19,51 @@
%%% Purpose : Compiles various modules with tough code
-module(compilation_SUITE).
-
--include_lib("test_server/include/test_server.hrl").
-
--compile(export_all).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
+-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ beam_compiler_4/1,
+ beam_compiler_6/1,
+ beam_compiler_7/1,
+ beam_compiler_8/1,
+ beam_compiler_9/1,
+ beam_compiler_10/1,
+ beam_compiler_11/1,
+ compiler_1/1,
+ const_list_256/1,
+ convopts/1,
+ live_var/1,
+ on_load/1,
+ on_load_inline/1,
+ opt_crash/1,
+ otp_2330/1,
+ otp_2380/1,
+ otp_4790/1,
+ otp_5151/1,
+ otp_5235/1,
+ otp_5404/1,
+ otp_5436/1,
+ otp_5481/1,
+ otp_5553/1,
+ otp_5632/1,
+ otp_5714/1,
+ otp_5872/1,
+ otp_6121/1,
+ otp_7202/1,
+ otp_8949_a/1,
+ redundant_case/1,
+ self_compile/1,
+ self_compile_old_inliner/1,
+ split_cases/1,
+ string_table/1,
+ vsn_1/1,
+ vsn_2/1,
+ vsn_3/1]).
+
+-include_lib("common_test/include/ct.hrl").
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,10}}].
all() ->
test_lib:recompile(?MODULE),
@@ -35,23 +74,18 @@ groups() ->
[{vsn,[parallel],[vsn_1,vsn_2,vsn_3]},
{p,test_lib:parallel(),
[compiler_1,
- compiler_3,compiler_5,beam_compiler_1,
- beam_compiler_2,beam_compiler_3,beam_compiler_4,
- beam_compiler_5,beam_compiler_6,beam_compiler_7,
+ beam_compiler_4,beam_compiler_6,beam_compiler_7,
beam_compiler_8,beam_compiler_9,beam_compiler_10,
- beam_compiler_11,beam_compiler_12,
- nested_tuples_in_case_expr,otp_2330,guards,
- {group,vsn},otp_2380,otp_2141,otp_2173,otp_4790,
- const_list_256,bin_syntax_1,bin_syntax_2,
- bin_syntax_3,bin_syntax_4,bin_syntax_5,bin_syntax_6,
- live_var,convopts,
- catch_in_catch,redundant_case,long_string,otp_5076,
- complex_guard,otp_5092,otp_5151,otp_5235,otp_5244,
- trycatch_4,opt_crash,otp_5404,otp_5436,otp_5481,
+ beam_compiler_11,
+ otp_2330,
+ {group,vsn},otp_2380,otp_4790,
+ const_list_256,live_var,convopts,
+ redundant_case,
+ otp_5151,otp_5235,
+ opt_crash,otp_5404,otp_5436,otp_5481,
otp_5553,otp_5632,otp_5714,otp_5872,otp_6121,
- otp_6121a,otp_6121b,otp_7202,otp_7345,on_load,
- string_table,otp_8949_a,otp_8949_b,split_cases,
- beam_utils_liveopt]}].
+ otp_7202,on_load,on_load_inline,
+ string_table,otp_8949_a,split_cases]}].
init_per_suite(Config) ->
Config.
@@ -68,85 +102,25 @@ end_per_group(_GroupName, Config) ->
-define(comp(N),
N(Config) when is_list(Config) -> try_it(N, Config)).
--define(comp_fail(N),
- N(Config) when is_list(Config) -> failure(N, Config)).
-
?comp(compiler_1).
-?comp(compiler_3).
-?comp(compiler_4).
-?comp(compiler_5).
-?comp(beam_compiler_1).
-?comp(beam_compiler_2).
-?comp(beam_compiler_3).
?comp(beam_compiler_4).
-?comp(beam_compiler_5).
?comp(beam_compiler_6).
?comp(beam_compiler_8).
?comp(beam_compiler_9).
?comp(beam_compiler_10).
?comp(beam_compiler_11).
-?comp(beam_compiler_12).
-?comp(beam_compiler_13).
-
-?comp(nested_tuples_in_case_expr).
?comp(otp_2330).
?comp(otp_2380).
-?comp(otp_2141).
-?comp(otp_2173).
?comp(otp_4790).
?comp(otp_5235).
-?comp(otp_5244).
-
-?comp(guards).
-
-?comp(pattern_expr).
-
?comp(const_list_256).
-?comp(bin_syntax_1).
-?comp(bin_syntax_2).
-?comp(bin_syntax_3).
-?comp(bin_syntax_4).
-
-?comp(bin_syntax_6).
-
-?comp(otp_5076).
-
-?comp(complex_guard).
-
-?comp(otp_5092).
?comp(otp_5151).
-%%% By Per Gustafsson <[email protected]>
-
-bin_syntax_5(Config) when is_list(Config) ->
- {<<45>>,<<>>} = split({int, 1}, <<1:16,45>>).
-
-split({int, N}, <<N:16,B:N/binary,T/binary>>) ->
- {B,T}.
-
-%% This program works with the old version of the compiler
-%% but, the core erlang that it produces have the same variable appearing
-%% looks like this:
-%%
-%% split({int, N}, <<_core1:16, B:N/binary, T/binary>>) when _core1==N
-%%
-%% with my change it will look like this:
-%%
-%% split({int, N}, <<_core1:16, B:_core1/binary, T/binary>>) when _core1==N
-%%
-%% This means that everything worked fine as long as the pattern
-%% matching order was left-to-right but on core erlang any order should be possible
-
?comp(live_var).
-
-?comp(trycatch_4).
-
-?comp(catch_in_catch).
-
?comp(opt_crash).
?comp(otp_5404).
@@ -157,18 +131,14 @@ split({int, N}, <<N:16,B:N/binary,T/binary>>) ->
?comp(otp_5714).
?comp(otp_5872).
?comp(otp_6121).
-?comp(otp_6121a).
-?comp(otp_6121b).
?comp(convopts).
?comp(otp_7202).
?comp(on_load).
?comp(on_load_inline).
-beam_compiler_7(doc) ->
- "Code snippet submitted from Ulf Wiger which fails in R3 Beam.";
-beam_compiler_7(suite) -> [];
+%% Code snippet submitted from Ulf Wiger which fails in R3 Beam.
beam_compiler_7(Config) when is_list(Config) ->
- ?line done = empty(2, false).
+ done = empty(2, false).
empty(N, Toggle) when N > 0 ->
%% R3 Beam copies the second argument to the first before call.
@@ -193,121 +163,63 @@ redundant_case_1(3) -> d;
redundant_case_1(4) -> d;
redundant_case_1(_) -> d.
-failure(Module, Conf) ->
- ?line Src = filename:join(?config(data_dir, Conf), atom_to_list(Module)),
- ?line Out = ?config(priv_dir,Conf),
- ?line io:format("Compiling: ~ts\n", [Src]),
- ?line CompRc = compile:file(Src, [{outdir,Out},return,time]),
- ?line io:format("Result: ~p\n",[CompRc]),
- ?line case CompRc of
- error -> ok;
- {error,Errors,_} -> check_errors(Errors);
- _ -> test_server:fail({no_error, CompRc})
- end,
- ok.
-
-check_errors([{_,Eds}|T]) ->
- check_error(Eds),
- check_errors(T);
-check_errors([]) -> ok.
-
-check_error([{_,Mod,Error}|T]) ->
- check_error_1(Mod:format_error(Error)),
- check_error(T);
-check_error([{Mod,Error}|T]) ->
- check_error_1(Mod:format_error(Error)),
- check_error(T);
-check_error([]) -> ok.
-
-check_error_1(Str0) ->
- Str = lists:flatten(Str0),
- io:format("~s\n", [Str]),
- case Str of
- "internal"++_=Str ->
- ?t:fail(internal_compiler_error);
- _ ->
- ok
- end.
-
--define(TC(Body), tc(fun() -> Body end, ?LINE)).
-
try_it(Module, Conf) ->
- %% Change 'false' to 'true' to start a new node for every module.
- try_it(false, Module, Conf).
-
-try_it(StartNode, Module, Conf) ->
- ?line OtherOpts = [], %Can be changed to [time] if needed
- ?line Src = filename:join(?config(data_dir, Conf), atom_to_list(Module)),
- ?line Out = ?config(priv_dir,Conf),
- ?line io:format("Compiling: ~s\n", [Src]),
- ?line CompRc0 = compile:file(Src, [clint,{outdir,Out},report,
- bin_opt_info|OtherOpts]),
- ?line io:format("Result: ~p\n",[CompRc0]),
- ?line {ok,_Mod} = CompRc0,
-
- ?line Dog = test_server:timetrap(test_server:minutes(10)),
- Node = case StartNode of
- false ->
- node();
- true ->
- ?line Pa = "-pa " ++ filename:dirname(code:which(?MODULE)),
- ?line {ok,Node0} = start_node(compiler, Pa),
- Node0
- end,
-
- ?line ok = rpc:call(Node, ?MODULE, load_and_call, [Out, Module]),
- ?line load_and_call(Out, Module),
- ?line test_server:timetrap_cancel(Dog),
-
- ?line NewDog = test_server:timetrap(test_server:minutes(10)),
- ?line io:format("Compiling (without optimization): ~s\n", [Src]),
- ?line CompRc1 = compile:file(Src,
- [no_copt,no_postopt,{outdir,Out},report|OtherOpts]),
-
- ?line io:format("Result: ~p\n",[CompRc1]),
- ?line {ok,_Mod} = CompRc1,
- ?line ok = rpc:call(Node, ?MODULE, load_and_call, [Out, Module]),
- ?line test_server:timetrap_cancel(NewDog),
-
- ?line LastDog = test_server:timetrap(test_server:minutes(10)),
- ?line io:format("Compiling (with old inliner): ~s\n", [Src]),
- ?line CompRc2 = compile:file(Src, [{outdir,Out},report,bin_opt_info,
- {inline,1000}|OtherOpts]),
- ?line io:format("Result: ~p\n",[CompRc2]),
- ?line {ok,_Mod} = CompRc2,
- ?line ok = rpc:call(Node, ?MODULE, load_and_call, [Out, Module]),
- ?line test_server:timetrap_cancel(LastDog),
-
- AsmDog = test_server:timetrap(test_server:minutes(10)),
+ Timetrap = {minutes,10},
+ OtherOpts = [], %Can be changed to [time] if needed
+ Src = filename:join(proplists:get_value(data_dir, Conf),
+ atom_to_list(Module)),
+ Out = proplists:get_value(priv_dir,Conf),
+ io:format("Compiling: ~s\n", [Src]),
+ CompRc0 = compile:file(Src, [clint0,clint,{outdir,Out},report,
+ bin_opt_info|OtherOpts]),
+ io:format("Result: ~p\n",[CompRc0]),
+ {ok,_Mod} = CompRc0,
+
+ load_and_call(Out, Module),
+
+ ct:timetrap(Timetrap),
+ io:format("Compiling (without optimization): ~s\n", [Src]),
+ CompRc1 = compile:file(Src,
+ [no_copt,no_postopt,
+ {outdir,Out},report|OtherOpts]),
+
+ io:format("Result: ~p\n",[CompRc1]),
+ {ok,_Mod} = CompRc1,
+ load_and_call(Out, Module),
+
+ ct:timetrap(Timetrap),
+ io:format("Compiling (with old inliner): ~s\n", [Src]),
+ CompRc2 = compile:file(Src, [clint,
+ {outdir,Out},report,bin_opt_info,
+ {inline,1000}|OtherOpts]),
+ io:format("Result: ~p\n",[CompRc2]),
+ {ok,_Mod} = CompRc2,
+ load_and_call(Out, Module),
+
+ ct:timetrap(Timetrap),
io:format("Compiling (from assembly): ~s\n", [Src]),
{ok,_} = compile:file(Src, [to_asm,{outdir,Out},report|OtherOpts]),
Asm = filename:join(Out, lists:concat([Module, ".S"])),
CompRc3 = compile:file(Asm, [from_asm,{outdir,Out},report|OtherOpts]),
io:format("Result: ~p\n",[CompRc3]),
{ok,_} = CompRc3,
- ok = rpc:call(Node, ?MODULE, load_and_call, [Out, Module]),
- test_server:timetrap_cancel(AsmDog),
+ load_and_call(Out, Module),
- case StartNode of
- false -> ok;
- true -> ?line test_server:stop_node(Node)
- end,
- ?line test_server:timetrap_cancel(LastDog),
ok.
load_and_call(Out, Module) ->
- ?line io:format("Loading...\n",[]),
- ?line {module,Module} = code:load_abs(filename:join(Out, Module)),
+ io:format("Loading...\n",[]),
+ {module,Module} = code:load_abs(filename:join(Out, Module)),
- ?line io:format("Calling...\n",[]),
+ io:format("Calling...\n",[]),
%% Call M:M, and expect ok back, that's our interface
- ?line CallRc = Module:Module(),
- ?line io:format("Got value: ~p\n",[CallRc]),
+ CallRc = Module:Module(),
+ io:format("Got value: ~p\n",[CallRc]),
- ?line ok = CallRc,
+ ok = CallRc,
%% Smoke-test of beam disassembler.
- ?line test_lib:smoke_disasm(Module),
+ test_lib:smoke_disasm(Module),
_ = code:delete(Module),
_ = code:purge(Module),
@@ -320,102 +232,73 @@ load_and_call(Out, Module) ->
ok.
-tc(F, Line) ->
- {Diff,Value} = timer:tc(erlang, apply, [F,[]]),
- io:format("~p: ~p\n", [Line,Diff]),
- Value.
-
-start_node(Name, Args) ->
- case test_server:start_node(Name, slave, [{args, Args}]) of
- {ok, Node} ->
- {ok, Node};
- Error ->
- ?line test_server:fail(Error)
- end.
+%% Test generation of 'vsn' attribute.
+vsn_1(Conf) when is_list(Conf) ->
+ M = vsn_1,
-from(H, [H | T]) -> T;
-from(H, [_ | T]) -> from(H, T);
-from(_, []) -> [].
+ compile_load(M, proplists:get_value(data_dir, Conf), Conf),
+ Vsn1 = get_vsn(M),
+ timer:sleep(1000),
+ compile_load(M, proplists:get_value(data_dir, Conf), Conf),
+ Vsn2 = get_vsn(M),
-vsn_1(doc) ->
- "Test generation of 'vsn' attribute";
-vsn_1(suite) -> [];
-vsn_1(Conf) when is_list(Conf) ->
- ?line M = vsn_1,
-
- ?line compile_load(M, ?config(data_dir, Conf), Conf),
- ?line Vsn1 = get_vsn(M),
- ?line timer:sleep(1000),
-
- ?line compile_load(M, ?config(data_dir, Conf), Conf),
- ?line Vsn2 = get_vsn(M),
-
- ?line compile_load(M, filename:join(?config(data_dir, Conf), "other"),
- Conf),
- ?line Vsn3 = get_vsn(M),
- ?line if
- Vsn1 == Vsn2, Vsn2 == Vsn3 ->
- ok;
- true ->
- test_server:fail({vsn, Vsn1, Vsn2, Vsn3})
- end,
+ compile_load(M, filename:join(proplists:get_value(data_dir, Conf),
+ "other"),
+ Conf),
+ Vsn3 = get_vsn(M),
+ if
+ Vsn1 == Vsn2, Vsn2 == Vsn3 ->
+ ok;
+ true ->
+ ct:fail({vsn, Vsn1, Vsn2, Vsn3})
+ end,
ok.
-vsn_2(doc) ->
- "Test overriding of generation of 'vsn' attribute";
-vsn_2(suite) -> [];
+%% Test overriding of generation of 'vsn' attribute.
vsn_2(Conf) when is_list(Conf) ->
- ?line M = vsn_2,
-
- ?line compile_load(M, ?config(data_dir, Conf), Conf),
- ?line Vsn = get_vsn(M),
- ?line case Vsn of
- [34] ->
- ok;
- _ ->
- test_server:fail({vsn, Vsn})
- end,
+ M = vsn_2,
+
+ compile_load(M, proplists:get_value(data_dir, Conf), Conf),
+ Vsn = get_vsn(M),
+ case Vsn of
+ [34] ->
+ ok;
+ _ ->
+ ct:fail({vsn, Vsn})
+ end,
ok.
-vsn_3(doc) ->
- "Test that different code yields different generated 'vsn'";
-vsn_3(suite) -> [];
+%% Test that different code yields different generated 'vsn'.
vsn_3(Conf) when is_list(Conf) ->
- ?line M = vsn_3,
-
- ?line compile_load(M, ?config(data_dir, Conf), Conf),
- ?line Vsn1 = get_vsn(M),
-
- ?line compile_load(M, filename:join(?config(data_dir, Conf), "other"),
- Conf),
- ?line Vsn2 = get_vsn(M),
- ?line if
- Vsn1 /= Vsn2 ->
- ok;
- true ->
- test_server:fail({vsn, Vsn1, Vsn2})
- end,
+ M = vsn_3,
+
+ compile_load(M, proplists:get_value(data_dir, Conf), Conf),
+ Vsn1 = get_vsn(M),
+
+ compile_load(M, filename:join(proplists:get_value(data_dir, Conf),
+ "other"),
+ Conf),
+ Vsn2 = get_vsn(M),
+ if
+ Vsn1 /= Vsn2 ->
+ ok;
+ true ->
+ ct:fail({vsn, Vsn1, Vsn2})
+ end,
ok.
get_vsn(M) ->
- {value, {vsn, V}} = lists:keysearch(vsn, 1, M:module_info(attributes)),
+ {vsn,V} = lists:keyfind(vsn, 1, M:module_info(attributes)),
V.
-long_string(Config) when is_list(Config) ->
- %% The test must complete in one minute - it should be plenty of time.
- ?line Dog = test_server:timetrap(test_server:minutes(1)),
- ?line try_it(long_string, Config),
- ?line test_server:timetrap_cancel(Dog),
- ok.
-
compile_load(Module, Dir, Conf) ->
- ?line Src = filename:join(Dir, atom_to_list(Module)),
- ?line Out = ?config(priv_dir,Conf),
- ?line CompRc = compile:file(Src, [{outdir,Out}]),
- ?line {ok, Module} = CompRc,
- ?line code:purge(Module),
- ?line {module, Module} =
+ Src = filename:join(Dir, atom_to_list(Module)),
+ Out = proplists:get_value(priv_dir,Conf),
+ CompRc = compile:file(Src, [{outdir,Out}]),
+ {ok, Module} = CompRc,
+ code:purge(Module),
+ {module, Module} =
code:load_abs(filename:join(Out, atom_to_list(Module))),
ok.
@@ -428,15 +311,15 @@ self_compile_old_inliner(Config) when is_list(Config) ->
self_compile_1(Config, "old", [verbose,{inline,500}]).
self_compile_1(Config, Prefix, Opts) ->
- Dog = test_server:timetrap(test_server:minutes(40)),
+ ct:timetrap({minutes,40}),
- Priv = ?config(priv_dir,Config),
+ Priv = proplists:get_value(priv_dir,Config),
Version = compiler_version(),
%% Compile the compiler. (In this node to get better coverage.)
CompA = make_compiler_dir(Priv, Prefix++"compiler_a"),
VsnA = Version ++ ".0",
- compile_compiler(compiler_src(), CompA, VsnA, [clint0,clint|Opts]),
+ compile_compiler(compiler_src(), CompA, VsnA, Opts),
%% Compile the compiler again using the newly compiled compiler.
%% (In another node because reloading the compiler would disturb cover.)
@@ -449,11 +332,10 @@ self_compile_1(Config, Prefix, Opts) ->
%% be equal (except for beam_asm that contains the compiler version).
compare_compilers(CompA, CompB),
- test_server:timetrap_cancel(Dog),
ok.
self_compile_node(CompilerDir, OutDir, Version, Opts) ->
- Dog = test_server:timetrap(test_server:minutes(15)),
+ ct:timetrap({minutes,15}),
Pa = "-pa " ++ filename:dirname(code:which(?MODULE)) ++
" -pa " ++ CompilerDir,
Files = compiler_src(),
@@ -462,17 +344,18 @@ self_compile_node(CompilerDir, OutDir, Version, Opts) ->
%% because it will load the same cover-compiled code as on this
%% node. Use a shielded node to prevent the cover server from
%% being started.
- ?t:run_on_shielded_node(
- fun() ->
- compile_compiler(Files, OutDir, Version, Opts)
- end, Pa),
- test_server:timetrap_cancel(Dog),
+ test_server:run_on_shielded_node(
+ fun() ->
+ compile_compiler(Files, OutDir, Version, Opts)
+ end, Pa),
+
ok.
compile_compiler(Files, OutDir, Version, InlineOpts) ->
io:format("~ts", [code:which(compile)]),
io:format("Compiling ~s into ~ts", [Version,OutDir]),
Opts = [report,
+ clint0,clint,
bin_opt_info,
{outdir,OutDir},
{d,'COMPILER_VSN',"\""++Version++"\""},
@@ -488,10 +371,6 @@ compile_compiler(Files, OutDir, Version, InlineOpts) ->
compiler_src() ->
filelib:wildcard(filename:join([code:lib_dir(compiler), "src", "*.erl"])).
-compiler_modules(Dir) ->
- Files = filelib:wildcard(filename:join(Dir, "*.beam")),
- [list_to_atom(filename:rootname(filename:basename(F))) || F <- Files].
-
make_compiler_dir(Priv, Dir0) ->
Dir = filename:join(Priv, Dir0),
ok = file:make_dir(Dir),
@@ -510,120 +389,14 @@ compare_compilers(ADir, BDir) ->
["beam_asm.beam"] = [filename:basename(A) || {A,_} <- D],
ok.
-%%%
-%%% The only test of the following code is that it compiles.
-%%%
-
-%% Slightly simplifed from megaco_binary_term_id_gen.
-%% beam_block failed to note that the {gc_bif,'-'...} instruction could
-%% fail, and that therefore {y,0} need to be initialized.
-%% {allocate,8,6}.
-%% %% {init,{y,0}} needed here.
-%% {get_list,{x,1},{x,6},{x,7}}.
-%% {'catch',{y,7},{f,3}}.
-%% {move,{x,4},{y,1}}.
-%% {move,{x,3},{y,2}}.
-%% {move,{x,2},{y,3}}.
-%% {move,{x,5},{y,4}}.
-%% {move,{x,7},{y,5}}.
-%% {move,{x,6},{y,6}}.
-%% {gc_bif,'-',{f,0},8,[{x,3},{x,6}],{x,0}}.
-%% {move,{x,0},{y,0}}.
-
-encode_wildcards3([],[],_,_) -> [];
-encode_wildcards3([Level|Levels],[BitsInLevel|BitsRest],LevelNo,TotSize) ->
- case (catch ?MODULE:encode_wildcard(Level,BitsInLevel,TotSize-BitsInLevel,
- length(Levels))) of
- {'EXIT',{Reason,Info}} ->
- exit({Reason,{LevelNo,Info}});
-
- no_wildcard ->
- encode_wildcards3(Levels,BitsRest,LevelNo+1,TotSize-BitsInLevel);
-
- {level,Wl} ->
- [Wl|
- encode_wildcards3(Levels,BitsRest,LevelNo+1,TotSize-BitsInLevel)];
-
- {recursive,Wr} ->
- [Wr]
- end.
-
-%% Slightly simplified code from hipe_rtl_ssapre.
-%% beam_block used to do the following incorrect optimization:
-%%
-%% {gc_bif,length,{f,0},1,[{x,0}],{x,3}}.
-%% ^^^^^ Was {x,0} - changing to {x,3} is not safe.
-%% {gc_bif,'+',{f,0},0,[{y,2},{integer,1}],{x,0}}.
-%% ^^^ Only one register live
-%% . . .
-%% {call_last,4,{f,2},4}. %% beam_validator noted that {x,3} wasn't live.
-
-find_operands(Cfg,XsiGraph,[],_Count) ->
- {Cfg,XsiGraph};
-find_operands(Cfg,XsiGraph,ActiveList,Count) ->
- {NewCfg,TempActiveList}=?MODULE:find_operands_for_active_list(Cfg,XsiGraph,
- ActiveList,[]),
- NewActiveList=lists:reverse(TempActiveList),
- [Count+1, length(NewActiveList), length(digraph:vertices(XsiGraph))],
- find_operands(NewCfg,XsiGraph,NewActiveList,Count+1).
-
-
-%% The following code
-%%
-%% {get_list,{x,2},{x,0},{x,1}}.
-%% {gc_bif,length,{f,0},1,[{x,0}],{x,0}}.
-%% {move,{x,0},{x,1}}.
-%%
-%% was incorrectly optimized to
-%%
-%% {get_list,{x,2},{x,0},{y,0}}.
-%% {gc_bif,length,{f,0},3,[{x,0}],{x,1}}.
-%%
-%% because beam_block:is_transparent({x,1},
-%% {gc_bif,length,{f,0},3,[{x,0}],{x,1}}
-%% incorrectly returned true.
-
--record(contextId,{cid,device_type,contextRef}).
--record(dpRef,{cid,tlli,ms_device_context_id}).
--record(qosProfileBssgp,{peak_bit_rate_msb,
- peak_bit_rate_lsb,
- t_a_precedence}).
--record(llUnitdataReq,{sapi,
- l3_pdu_length,
- pdu_life}).
--record(ptmsi,{value}).
-
-otp_7345(Config) when is_list(Config) ->
- #llUnitdataReq{l3_pdu_length=3,pdu_life=4} =
- otp_7345(#contextId{}, 0, [[1,2,3],4,5]).
-
-
-otp_7345(ObjRef, _RdEnv, Args) ->
- Cid = ObjRef#contextId.cid,
- _ = #dpRef{cid = Cid,
- ms_device_context_id = cid_id,
- tlli = #ptmsi{value = 0}},
- _ = #qosProfileBssgp{peak_bit_rate_msb = 0,
- peak_bit_rate_lsb = 80,
- t_a_precedence = 49},
- [Cpdu|_] = Args,
- LlUnitdataReq =
- #llUnitdataReq{sapi = 7,
- l3_pdu_length = length(Cpdu),
- pdu_life =
- id(42)
- div
- 10},
- id(LlUnitdataReq).
-
%% Check the generation of the string table.
string_table(Config) when is_list(Config) ->
- ?line DataDir = ?config(data_dir, Config),
- ?line File = filename:join(DataDir, "string_table.erl"),
- ?line {ok,string_table,Beam,[]} = compile:file(File, [return, binary]),
- ?line {ok,{string_table,[StringTableChunk]}} = beam_lib:chunks(Beam, ["StrT"]),
- ?line {"StrT", <<"stringtable">>} = StringTableChunk,
+ DataDir = proplists:get_value(data_dir, Config),
+ File = filename:join(DataDir, "string_table.erl"),
+ {ok,string_table,Beam,[]} = compile:file(File, [return, binary]),
+ {ok,{string_table,[StringTableChunk]}} = beam_lib:chunks(Beam, ["StrT"]),
+ {"StrT", <<"stringtable">>} = StringTableChunk,
ok.
otp_8949_a(Config) when is_list(Config) ->
@@ -648,24 +421,6 @@ do_otp_8949_a() ->
end
end.
-otp_8949_b(Config) when is_list(Config) ->
- self() ! something,
- ?line value = otp_8949_b([], false),
- ?line {'EXIT',_} = (catch otp_8949_b([], true)),
- ok.
-
-%% Would cause an endless loop in beam_utils.
-otp_8949_b(A, B) ->
- Var = id(value),
- if
- A == [], B == false ->
- ok
- end,
- receive
- something ->
- id(Var)
- end.
-
split_cases(_) ->
dummy1 = do_split_cases(x),
{'EXIT',{{badmatch,b},_}} = (catch do_split_cases(y)),
@@ -681,21 +436,5 @@ do_split_cases(A) ->
end,
Z.
--record(alarmInfo, {type,cause,origin}).
-
-beam_utils_liveopt(Config) ->
- F = beam_utils_liveopt_fun(42, pebkac, user),
- void = F(42, #alarmInfo{type=sctp,cause=pebkac,origin=user}),
- ok.
-
-beam_utils_liveopt_fun(Peer, Cause, Origin) ->
- fun(PeerNo, AlarmInfo)
- when PeerNo == Peer andalso
- AlarmInfo == #alarmInfo{type=sctp,
- cause=Cause,
- origin=Origin} ->
- void
- end.
-
id(I) -> I.
diff --git a/lib/compiler/test/compilation_SUITE_data/beam_compiler_1.erl b/lib/compiler/test/compilation_SUITE_data/beam_compiler_1.erl
deleted file mode 100644
index ce72d0d0f2..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/beam_compiler_1.erl
+++ /dev/null
@@ -1,32 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. 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(beam_compiler_1).
--export([beam_compiler_1/0]).
-
-beam_compiler_1() ->
- ok.
-
--record(foo,{a,b}).
-
-try_me() ->
- X = #foo{},
- Y = #foo{},
- {X#foo.a == Y#foo.a,X#foo.b}.
-
diff --git a/lib/compiler/test/compilation_SUITE_data/beam_compiler_10.erl b/lib/compiler/test/compilation_SUITE_data/beam_compiler_10.erl
index 41c5e7b4d2..66f2f78b32 100644
--- a/lib/compiler/test/compilation_SUITE_data/beam_compiler_10.erl
+++ b/lib/compiler/test/compilation_SUITE_data/beam_compiler_10.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/beam_compiler_11.erl b/lib/compiler/test/compilation_SUITE_data/beam_compiler_11.erl
index 1b6cd66953..0339b2a488 100644
--- a/lib/compiler/test/compilation_SUITE_data/beam_compiler_11.erl
+++ b/lib/compiler/test/compilation_SUITE_data/beam_compiler_11.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/beam_compiler_12.erl b/lib/compiler/test/compilation_SUITE_data/beam_compiler_12.erl
deleted file mode 100644
index 8bb6ce9e4a..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/beam_compiler_12.erl
+++ /dev/null
@@ -1,30 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. 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(beam_compiler_12).
-
--export([?MODULE/0,t/1]).
-
-?MODULE() ->
- ok.
-
-t(Name) ->
- {ok = {file_info,_,regular,_,AccTime1,ModTime1,_,_,_,_,_,_,_,_}} =
- prim_file:read_file_info(Name).
-
diff --git a/lib/compiler/test/compilation_SUITE_data/beam_compiler_2.erl b/lib/compiler/test/compilation_SUITE_data/beam_compiler_2.erl
deleted file mode 100644
index 66fdcae4d0..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/beam_compiler_2.erl
+++ /dev/null
@@ -1,36 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. 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(beam_compiler_2).
--export([beam_compiler_2/0]).
-
-beam_compiler_2() ->
- ok.
-
--record(foo,{a,b}).
-
-try_me() ->
- try_me({foo,x,z},{foo,y,z}).
-
-try_me(X,Y) ->
- f(X#foo.a =/= Y#foo.a,X#foo.b =/= X#foo.b).
-
-f(A,B) ->
- A.
-
diff --git a/lib/compiler/test/compilation_SUITE_data/beam_compiler_3.erl b/lib/compiler/test/compilation_SUITE_data/beam_compiler_3.erl
deleted file mode 100644
index adf6fa2720..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/beam_compiler_3.erl
+++ /dev/null
@@ -1,30 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. 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(beam_compiler_3).
--export([beam_compiler_3/0, f/0]).
-
-%% From Ulf Wiger.
-
-beam_compiler_3() ->
- ok.
-
-f() ->
- [_|T] = lists:reverse("xxx"),
- T.
diff --git a/lib/compiler/test/compilation_SUITE_data/beam_compiler_4.erl b/lib/compiler/test/compilation_SUITE_data/beam_compiler_4.erl
index 5ecfed52df..0a394619de 100644
--- a/lib/compiler/test/compilation_SUITE_data/beam_compiler_4.erl
+++ b/lib/compiler/test/compilation_SUITE_data/beam_compiler_4.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/lib/compiler/test/compilation_SUITE_data/beam_compiler_5.erl b/lib/compiler/test/compilation_SUITE_data/beam_compiler_5.erl
deleted file mode 100644
index 21bab01c82..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/beam_compiler_5.erl
+++ /dev/null
@@ -1,29 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. 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(beam_compiler_5).
--export([beam_compiler_5/0]).
-
--compile(export_all).
-
-beam_compiler_5() ->
- ok.
-
-t() ->
- [_|_] = x.
diff --git a/lib/compiler/test/compilation_SUITE_data/beam_compiler_6.erl b/lib/compiler/test/compilation_SUITE_data/beam_compiler_6.erl
index a14c05de10..1fe1b2d693 100644
--- a/lib/compiler/test/compilation_SUITE_data/beam_compiler_6.erl
+++ b/lib/compiler/test/compilation_SUITE_data/beam_compiler_6.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/lib/compiler/test/compilation_SUITE_data/beam_compiler_8.erl b/lib/compiler/test/compilation_SUITE_data/beam_compiler_8.erl
index d8eebc07d1..de51c59aae 100644
--- a/lib/compiler/test/compilation_SUITE_data/beam_compiler_8.erl
+++ b/lib/compiler/test/compilation_SUITE_data/beam_compiler_8.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/beam_compiler_9.erl b/lib/compiler/test/compilation_SUITE_data/beam_compiler_9.erl
index fecc566a95..5d0097f0fd 100644
--- a/lib/compiler/test/compilation_SUITE_data/beam_compiler_9.erl
+++ b/lib/compiler/test/compilation_SUITE_data/beam_compiler_9.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/bin_syntax_1.erl b/lib/compiler/test/compilation_SUITE_data/bin_syntax_1.erl
deleted file mode 100644
index b381c539b7..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/bin_syntax_1.erl
+++ /dev/null
@@ -1,32 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. 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(bin_syntax_1).
-
--export([f/2,?MODULE/0]).
-
-?MODULE() ->
- ok.
-
-f(X, Y) ->
- case X of
- a ->
- Y2 = 8
- end,
- <<5:Y2>> = Y.
diff --git a/lib/compiler/test/compilation_SUITE_data/bin_syntax_2.erl b/lib/compiler/test/compilation_SUITE_data/bin_syntax_2.erl
deleted file mode 100644
index b3e3785249..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/bin_syntax_2.erl
+++ /dev/null
@@ -1,42 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. 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(bin_syntax_2).
-
--export([?MODULE/0]).
-
-%% This module tests that constant propagation is done properly.
-
-?MODULE() ->
- 258 = b(<<1,2>>),
- F = c(),
- 259 = F(<<1,3>>),
- ok.
-
-b(B) ->
- Sz = 16,
- <<X:Sz/integer>> = B,
- X.
-
-c() ->
- Size = 16,
- fun(Bin) ->
- <<X:Size/integer>> = Bin,
- X
- end.
diff --git a/lib/compiler/test/compilation_SUITE_data/bin_syntax_3.erl b/lib/compiler/test/compilation_SUITE_data/bin_syntax_3.erl
deleted file mode 100644
index b881d2769e..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/bin_syntax_3.erl
+++ /dev/null
@@ -1,36 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. 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(bin_syntax_3).
--export([?MODULE/0,decode_integer/3]).
-
-?MODULE() ->
- ok.
-
-decode_integer(Len, <<B1:1,B2:7,Bs/binary>>, RemovedBytes) when B1 == 0 ->
- Bin = <<Skip:Len/unit:8, Buffer2/binary>> = <<B1:1,B2:7,Bs/binary>>,
- Size = size(Bin),
- <<Int:Size/unit:8>> = Bin,
- {Int,Buffer2,RemovedBytes};
-decode_integer(Len,<<B1:1,B2:7,Bs/binary>>,RemovedBytes) ->
- Bin = <<Skip:Len/unit:8,Buffer2/binary>> = <<B1:1,B2:7,Bs/binary>>,
- Size = size(Bin),
- <<N:Size/unit:8>> = <<B2,Bs/binary>>,
- Int = N - (1 bsl (8 * size(Bin) -1)),
- {Int,Buffer2,RemovedBytes}.
diff --git a/lib/compiler/test/compilation_SUITE_data/bin_syntax_4.erl b/lib/compiler/test/compilation_SUITE_data/bin_syntax_4.erl
deleted file mode 100644
index f63eb34fb2..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/bin_syntax_4.erl
+++ /dev/null
@@ -1,33 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. 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(bin_syntax_4).
--export([?MODULE/0,f4b/2,f4c/2]).
-
-?MODULE() ->
- ok.
-
-f4b(X, Y) ->
- fun (<< A:Y >>, Y, B) -> fum(A, X, Y, B) end.
-
-f4c(X, Y) ->
- fun (Y, << A:Y >>, B) -> fum(A, X, Y, B) end.
-
-fum(A, B, C, D) ->
- {A,B,C,D}.
diff --git a/lib/compiler/test/compilation_SUITE_data/bin_syntax_6.erl b/lib/compiler/test/compilation_SUITE_data/bin_syntax_6.erl
deleted file mode 100644
index 13e4bb8707..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/bin_syntax_6.erl
+++ /dev/null
@@ -1,40 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2009. 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(bin_syntax_6).
--export([?MODULE/0,x/1,y/1]).
-
-?MODULE() ->
- ok.
-
-x(X) ->
- blurf(),
- B = {X,"OK",<<>>},
- catch b({a,B}).
-
-y(X) ->
- blurf(),
- B = {X,"OK",<<42>>},
- catch b({a,B}).
-
-blurf() ->
- ok.
-
-b(_) ->
- ok.
diff --git a/lib/compiler/test/compilation_SUITE_data/catch_in_catch.erl b/lib/compiler/test/compilation_SUITE_data/catch_in_catch.erl
deleted file mode 100644
index 0abde0ff5d..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/catch_in_catch.erl
+++ /dev/null
@@ -1,52 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2009. 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(catch_in_catch).
-
--export([?MODULE/0,do_start/1]).
-
-?MODULE() ->
- process_flag(trap_exit, true),
- Pid = spawn_link(?MODULE, do_start, [x]),
- receive
- {'EXIT',Pid,good_exit} -> ok;
- Other ->
- io:format("Unexpected: ~p\n", [Other]),
- error
- after 32000 ->
- io:format("No message received\n"),
- error
- end.
-
-do_start(Param) ->
- init(Param),
- exit(good_exit).
-
-init(Param) ->
- process_flag(trap_exit, true),
- %% The catches were improperly nested, causing a "No catch found" crash.
- (catch begin
- foo(Param),
- (catch exit(bar))
- end
- ),
- ignore.
-
-foo(_) ->
- ok.
diff --git a/lib/compiler/test/compilation_SUITE_data/compiler_1.erl b/lib/compiler/test/compilation_SUITE_data/compiler_1.erl
index 02858ec308..87985bdf80 100644
--- a/lib/compiler/test/compilation_SUITE_data/compiler_1.erl
+++ b/lib/compiler/test/compilation_SUITE_data/compiler_1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/lib/compiler/test/compilation_SUITE_data/compiler_3.erl b/lib/compiler/test/compilation_SUITE_data/compiler_3.erl
deleted file mode 100644
index 4b99eafc63..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/compiler_3.erl
+++ /dev/null
@@ -1,34 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. 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(compiler_3).
--export([compiler_3/0]).
--record(rec,{a}).
-
-compiler_3() ->
- guard_record().
-
-guard_record() ->
- 1=func(#rec{}),
- {'EXIT',_} = (catch func({rec})),
- ok.
-
-func(X) when record(X,
-rec) ->
- 1.
diff --git a/lib/compiler/test/compilation_SUITE_data/compiler_5.erl b/lib/compiler/test/compilation_SUITE_data/compiler_5.erl
deleted file mode 100644
index 63564ac938..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/compiler_5.erl
+++ /dev/null
@@ -1,50 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. 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(compiler_5).
--export([compiler_5/0]).
-
-compiler_5() ->
- f0(),
- f1(),
- f2(),
- ok.
-
-%% compiler treats records with 1 and 2 fields differently...
--record(nil, {}).
--record(foo, {hello=1}).
--record(bar, {hello=2,there=3}).
-
-f0() ->
- R1 = #nil{},
- R2 = R1#nil{}, %% stupid code, but compiler shouldn't crash
- R1 = R2,
- ok.
-
-f1() ->
- R1 = #foo{},
- R2 = R1#foo{}, %% stupid code, but compiler shouldn't crash
- R1 = R2,
- ok.
-
-f2() ->
- R1 = #bar{},
- R2 = R1#bar{}, %% stupid code, but compiler shouldn't crash
- R1 = R2,
- ok.
diff --git a/lib/compiler/test/compilation_SUITE_data/complex_guard.erl b/lib/compiler/test/compilation_SUITE_data/complex_guard.erl
deleted file mode 100644
index 37b861b0b5..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/complex_guard.erl
+++ /dev/null
@@ -1,32 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. 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(complex_guard).
-
--compile(export_all).
-
-?MODULE() ->
- ok.
-
-f(X1,Y1,Z1) ->
- if
- ((X1 =:= 4) or (X1 =:= 5)) and ((Y1 =:= 4) or (Y1 =:= 5)) and ((Z1 =:= 4) or (Z1 =:= 5)) or ((X1 =:= 1) or (X1 =:= 2) or (X1 =:= 3)) and ((Y1 =:= 1) or (Y1 =:= 2) or (Y1 =:= 3)) and ((Z1 =:= 1) or (Z1 =:= 2) or (Z1 =:= 3)) ->
- true
- end.
-
diff --git a/lib/compiler/test/compilation_SUITE_data/const_list_256.erl b/lib/compiler/test/compilation_SUITE_data/const_list_256.erl
index 18f4d52d7b..bdce438162 100644
--- a/lib/compiler/test/compilation_SUITE_data/const_list_256.erl
+++ b/lib/compiler/test/compilation_SUITE_data/const_list_256.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/convopts.erl b/lib/compiler/test/compilation_SUITE_data/convopts.erl
index 55b65d6763..8404eb82fd 100644
--- a/lib/compiler/test/compilation_SUITE_data/convopts.erl
+++ b/lib/compiler/test/compilation_SUITE_data/convopts.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/guards.erl b/lib/compiler/test/compilation_SUITE_data/guards.erl
deleted file mode 100644
index f0d11fc79a..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/guards.erl
+++ /dev/null
@@ -1,107 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. 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(guards).
-
--export([guards/0]).
-
-guards() ->
- ok = t(),
- ok = f(),
- ok = ct(1),
- ok = multi(1),
- ok = multi(2),
- ok = multi(3).
-
-%% The following tests are always true.
-t() when integer(42) ->
- ok;
-t() when float(2.0) ->
- ok;
-t() when number(7) ->
- ok;
-t() when number(3.14) ->
- ok;
-t() when atom(error) ->
- ok;
-t() when list([a]) ->
- ok;
-t() when tuple({}) ->
- ok;
-t() when tuple({1, 2}) ->
- ok.
-
-%% The following tests are always false.
-f() when integer(a) ->
- ok;
-f() when float(b) ->
- ok;
-f() when number(c) ->
- ok;
-f() when atom(42) ->
- ok;
-f() when list(33) ->
- ok;
-f() when list({}) ->
- ok;
-f() when list({1, 2}) ->
- ok;
-f() when tuple(33) ->
- ok;
-f() when tuple([a]) ->
- ok;
-f() when tuple([]) ->
- ok;
-f() when tuple(35) ->
- ok;
-f() ->
- ok.
-
-%% The following tests are always true.
-ct(X) ->
- case X of
- Y when integer(42) ->
- ok;
- Y when float(2.0) ->
- ok;
- Y when number(7) ->
- ok;
- Y when number(3.14) ->
- ok;
- Y when atom(error) ->
- ok;
- Y when list([a]) ->
- ok;
- Y when tuple({}) ->
- ok;
- Y when tuple({1, 2}) ->
- ok
- end.
-
-multi(X) ->
- case X of
- Y when float(Y) ; integer(Y) ->
- ok;
- Y when Y > 1, Y < 10 ; atom(Y) ->
- ok;
- Y when Y == 4, number(Y) ; list(Y) ->
- pannkaka;
- Y when Y==3 ; Y==5 ; Y==6 ->
- ok
- end.
diff --git a/lib/compiler/test/compilation_SUITE_data/live_var.erl b/lib/compiler/test/compilation_SUITE_data/live_var.erl
index be79041baf..b984d98c2b 100644
--- a/lib/compiler/test/compilation_SUITE_data/live_var.erl
+++ b/lib/compiler/test/compilation_SUITE_data/live_var.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/long_string.erl b/lib/compiler/test/compilation_SUITE_data/long_string.erl
deleted file mode 100644
index 1624e222ab..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/long_string.erl
+++ /dev/null
@@ -1,671 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. 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(long_string).
-
--export([?MODULE/0]).
-
-?MODULE() ->
- Options = "some stupid long string",
- 49252 = length(generate(Options, "348927432097sfkjfkljf329")),
- ok.
-
-generate(Options, Glurf) ->
- "asdhfaslfdjhhwleirsk e4kjhr430usduy fdk;///s llsjkf;laskjfsdfkjasdfkj
-sdkljflasdfkjasldkfjasd" ++ Options ++
-"CSAgICAgICBWZXJzaW9uIDIsIEp1bmUgMTk5MQoKIENvcHlyaWdodCAoQykgMTk4OSwgMTk5MSBG
-cmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIEluYy4KICAgICAgICAgICAgICAgICAgICAgICA1OSBU
-ZW1wbGUgUGxhY2UsIFN1aXRlIDMzMCwgQm9zdG9uLCBNQSAgMDIxMTEtMTMwNyAgVVNBCiBFdmVy
-eW9uZSBpcyBwZXJtaXR0ZWQgdG8gY29weSBhbmQgZGlzdHJpYnV0ZSB2ZXJiYXRpbSBjb3BpZXMK
-IG9mIHRoaXMgbGljZW5zZSBkb2N1bWVudCwgYnV0IGNoYW5naW5nIGl0IGlzIG5vdCBhbGxvd2Vk
-LgoKCQkJICAgIFByZWFtYmxlCgogIFRoZSBsaWNlbnNlcyBmb3IgbW9zdCBzb2Z0d2FyZSBhcmUg
-ZGVzaWduZWQgdG8gdGFrZSBhd2F5IHlvdXIKZnJlZWRvbSB0byBzaGFyZSBhbmQgY2hhbmdlIGl0
-LiAgQnkgY29udHJhc3QsIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMKTGljZW5zZSBpcyBpbnRlbmRl
-ZCB0byBndWFyYW50ZWUgeW91ciBmcmVlZG9tIHRvIHNoYXJlIGFuZCBjaGFuZ2UgZnJlZQpzb2Z0
-d2FyZS0tdG8gbWFrZSBzdXJlIHRoZSBzb2Z0d2FyZSBpcyBmcmVlIGZvciBhbGwgaXRzIHVzZXJz
-LiAgVGhpcwpHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFwcGxpZXMgdG8gbW9zdCBvZiB0aGUgRnJl
-ZSBTb2Z0d2FyZQpGb3VuZGF0aW9uJ3Mgc29mdHdhcmUgYW5kIHRvIGFueSBvdGhlciBwcm9ncmFt
-IHdob3NlIGF1dGhvcnMgY29tbWl0IHRvCnVzaW5nIGl0LiAgKFNvbWUgb3RoZXIgRnJlZSBTb2Z0
-d2FyZSBGb3VuZGF0aW9uIHNvZnR3YXJlIGlzIGNvdmVyZWQgYnkKdGhlIEdOVSBMaWJyYXJ5IEdl
-bmVyYWwgUHVibGljIExpY2Vuc2UgaW5zdGVhZC4pICBZb3UgY2FuIGFwcGx5IGl0IHRvCnlvdXIg
-cHJvZ3JhbXMsIHRvby4KCiAgV2hlbiB3ZSBzcGVhayBvZiBmcmVlIHNvZnR3YXJlLCB3ZSBhcmUg
-cmVmZXJyaW5nIHRvIGZyZWVkb20sIG5vdApwcmljZS4gIE91ciBHZW5lcmFsIFB1YmxpYyBMaWNl
-bnNlcyBhcmUgZGVzaWduZWQgdG8gbWFrZSBzdXJlIHRoYXQgeW91CmhhdmUgdGhlIGZyZWVkb20g
-dG8gZGlzdHJpYnV0ZSBjb3BpZXMgb2YgZnJlZSBzb2Z0d2FyZSAoYW5kIGNoYXJnZSBmb3IKdGhp
-cyBzZXJ2aWNlIGlmIHlvdSB3aXNoKSwgdGhhdCB5b3UgcmVjZWl2ZSBzb3VyY2UgY29kZSBvciBj
-YW4gZ2V0IGl0CmlmIHlvdSB3YW50IGl0LCB0aGF0IHlvdSBjYW4gY2hhbmdlIHRoZSBzb2Z0d2Fy
-ZSBvciB1c2UgcGllY2VzIG9mIGl0CmluIG5ldyBmcmVlIHByb2dyYW1zOyBhbmQgdGhhdCB5b3Ug
-a25vdyB5b3UgY2FuIGRvIHRoZXNlIHRoaW5ncy4KCiAgVG8gcHJvdGVjdCB5b3VyIHJpZ2h0cywg
-d2UgbmVlZCB0byBtYWtlIHJlc3RyaWN0aW9ucyB0aGF0IGZvcmJpZAphbnlvbmUgdG8gZGVueSB5
-b3UgdGhlc2UgcmlnaHRzIG9yIHRvIGFzayB5b3UgdG8gc3VycmVuZGVyIHRoZSByaWdodHMuClRo
-ZXNlIHJlc3RyaWN0aW9ucyB0cmFuc2xhdGUgdG8gY2VydGFpbiByZXNwb25zaWJpbGl0aWVzIGZv
-ciB5b3UgaWYgeW91CmRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZSBzb2Z0d2FyZSwgb3IgaWYgeW91
-IG1vZGlmeSBpdC4KCiAgRm9yIGV4YW1wbGUsIGlmIHlvdSBkaXN0cmlidXRlIGNvcGllcyBvZiBz
-dWNoIGEgcHJvZ3JhbSwgd2hldGhlcgpncmF0aXMgb3IgZm9yIGEgZmVlLCB5b3UgbXVzdCBnaXZl
-IHRoZSByZWNpcGllbnRzIGFsbCB0aGUgcmlnaHRzIHRoYXQKeW91IGhhdmUuICBZb3UgbXVzdCBt
-YWtlIHN1cmUgdGhhdCB0aGV5LCB0b28sIHJlY2VpdmUgb3IgY2FuIGdldCB0aGUKc291cmNlIGNv
-ZGUuICBBbmQgeW91IG11c3Qgc2hvdyB0aGVtIHRoZXNlIHRlcm1zIHNvIHRoZXkga25vdyB0aGVp
-cgpyaWdodHMuCgogIFdlIHByb3RlY3QgeW91ciByaWdodHMgd2l0aCB0d28gc3RlcHM6ICgxKSBj
-b3B5cmlnaHQgdGhlIHNvZnR3YXJlLCBhbmQKKDIpIG9mZmVyIHlvdSB0aGlzIGxpY2Vuc2Ugd2hp
-Y2ggZ2l2ZXMgeW91IGxlZ2FsIHBlcm1pc3Npb24gdG8gY29weSwKZGlzdHJpYnV0ZSBhbmQvb3Ig
-bW9kaWZ5IHRoZSBzb2Z0d2FyZS4KCiAgQWxzbywgZm9yIGVhY2ggYXV0aG9yJ3MgcHJvdGVjdGlv
-biBhbmQgb3Vycywgd2Ugd2FudCB0byBtYWtlIGNlcnRhaW4KdGhhdCBldmVyeW9uZSB1bmRlcnN0
-YW5kcyB0aGF0IHRoZXJlIGlzIG5vIHdhcnJhbnR5IGZvciB0aGlzIGZyZWUKc29mdHdhcmUuICBJ
-ZiB0aGUgc29mdHdhcmUgaXMgbW9kaWZpZWQgYnkgc29tZW9uZSBlbHNlIGFuZCBwYXNzZWQgb24s
-IHdlCndhbnQgaXRzIHJlY2lwaWVudHMgdG8ga25vdyB0aGF0IHdoYXQgdGhleSBoYXZlIGlzIG5v
-dCB0aGUgb3JpZ2luYWwsIHNvCnRoYXQgYW55IHByb2JsZW1zIGludHJvZHVjZWQgYnkgb3RoZXJz
-IHdpbGwgbm90IHJlZmxlY3Qgb24gdGhlIG9yaWdpbmFsCmF1dGhvcnMnIHJlcHV0YXRpb25zLgoK
-ICBGaW5hbGx5LCBhbnkgZnJlZSBwcm9ncmFtIGlzIHRocmVhdGVuZWQgY29uc3RhbnRseSBieSBz
-b2Z0d2FyZQpwYXRlbnRzLiAgV2Ugd2lzaCB0byBhdm9pZCB0aGUgZGFuZ2VyIHRoYXQgcmVkaXN0
-cmlidXRvcnMgb2YgYSBmcmVlCnByb2dyYW0gd2lsbCBpbmRpdmlkdWFsbHkgb2J0YWluIHBhdGVu
-dCBsaWNlbnNlcywgaW4gZWZmZWN0IG1ha2luZyB0aGUKcHJvZ3JhbSBwcm9wcmlldGFyeS4gIFRv
-IHByZXZlbnQgdGhpcywgd2UgaGF2ZSBtYWRlIGl0IGNsZWFyIHRoYXQgYW55CnBhdGVudCBtdXN0
-IGJlIGxpY2Vuc2VkIGZvciBldmVyeW9uZSdzIGZyZWUgdXNlIG9yIG5vdCBsaWNlbnNlZCBhdCBh
-bGwuCgogIFRoZSBwcmVjaXNlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciBjb3B5aW5nLCBkaXN0
-cmlidXRpb24gYW5kCm1vZGlmaWNhdGlvbiBmb2xsb3cuCgwKCQkgICAgR05VIEdFTkVSQUwgUFVC
-TElDIExJQ0VOU0UKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIENPUFlJTkcsIERJU1RSSUJV
-VElPTiBBTkQgTU9ESUZJQ0FUSU9OCgogIDAuIFRoaXMgTGljZW5zZSBhcHBsaWVzIHRvIGFueSBw
-cm9ncmFtIG9yIG90aGVyIHdvcmsgd2hpY2ggY29udGFpbnMKYSBub3RpY2UgcGxhY2VkIGJ5IHRo
-ZSBjb3B5cmlnaHQgaG9sZGVyIHNheWluZyBpdCBtYXkgYmUgZGlzdHJpYnV0ZWQKdW5kZXIgdGhl
-IHRlcm1zIG9mIHRoaXMgR2VuZXJhbCBQdWJsaWMgTGljZW5zZS4gIFRoZSAiUHJvZ3JhbSIsIGJl
-bG93LApyZWZlcnMgdG8gYW55IHN1Y2ggcHJvZ3JhbSBvciB3b3JrLCBhbmQgYSAid29yayBiYXNl
-ZCBvbiB0aGUgUHJvZ3JhbSIKbWVhbnMgZWl0aGVyIHRoZSBQcm9ncmFtIG9yIGFueSBkZXJpdmF0
-aXZlIHdvcmsgdW5kZXIgY29weXJpZ2h0IGxhdzoKdGhhdCBpcyB0byBzYXksIGEgd29yayBjb250
-YWluaW5nIHRoZSBQcm9ncmFtIG9yIGEgcG9ydGlvbiBvZiBpdCwKZWl0aGVyIHZlcmJhdGltIG9y
-IHdpdGggbW9kaWZpY2F0aW9ucyBhbmQvb3IgdHJhbnNsYXRlZCBpbnRvIGFub3RoZXIKbGFuZ3Vh
-Z2UuICAoSGVyZWluYWZ0ZXIsIHRyYW5zbGF0aW9uIGlzIGluY2x1ZGVkIHdpdGhvdXQgbGltaXRh
-dGlvbiBpbgp0aGUgdGVybSAibW9kaWZpY2F0aW9uIi4pICBFYWNoIGxpY2Vuc2VlIGlzIGFkZHJl
-c3NlZCBhcyAieW91Ii4KCkFjdGl2aXRpZXMgb3RoZXIgdGhhbiBjb3B5aW5nLCBkaXN0cmlidXRp
-b24gYW5kIG1vZGlmaWNhdGlvbiBhcmUgbm90CmNvdmVyZWQgYnkgdGhpcyBMaWNlbnNlOyB0aGV5
-IGFyZSBvdXRzaWRlIGl0cyBzY29wZS4gIFRoZSBhY3Qgb2YKcnVubmluZyB0aGUgUHJvZ3JhbSBp
-cyBub3QgcmVzdHJpY3RlZCwgYW5kIHRoZSBvdXRwdXQgZnJvbSB0aGUgUHJvZ3JhbQppcyBjb3Zl
-cmVkIG9ubHkgaWYgaXRzIGNvbnRlbnRzIGNvbnN0aXR1dGUgYSB3b3JrIGJhc2VkIG9uIHRoZQpQ
-cm9ncmFtIChpbmRlcGVuZGVudCBvZiBoYXZpbmcgYmVlbiBtYWRlIGJ5IHJ1bm5pbmcgdGhlIFBy
-b2dyYW0pLgpXaGV0aGVyIHRoYXQgaXMgdHJ1ZSBkZXBlbmRzIG9uIHdoYXQgdGhlIFByb2dyYW0g
-ZG9lcy4KCiAgMS4gWW91IG1heSBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNvcGllcyBv
-ZiB0aGUgUHJvZ3JhbSdzCnNvdXJjZSBjb2RlIGFzIHlvdSByZWNlaXZlIGl0LCBpbiBhbnkgbWVk
-aXVtLCBwcm92aWRlZCB0aGF0IHlvdQpjb25zcGljdW91c2x5IGFuZCBhcHByb3ByaWF0ZWx5IHB1
-Ymxpc2ggb24gZWFjaCBjb3B5IGFuIGFwcHJvcHJpYXRlCmNvcHlyaWdodCBub3RpY2UgYW5kIGRp
-c2NsYWltZXIgb2Ygd2FycmFudHk7IGtlZXAgaW50YWN0IGFsbCB0aGUKbm90aWNlcyB0aGF0IHJl
-ZmVyIHRvIHRoaXMgTGljZW5zZSBhbmQgdG8gdGhlIGFic2VuY2Ugb2YgYW55IHdhcnJhbnR5Owph
-bmQgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgUHJvZ3JhbSBhIGNvcHkgb2YgdGhp
-cyBMaWNlbnNlCmFsb25nIHdpdGggdGhlIFByb2dyYW0uCgpZb3UgbWF5IGNoYXJnZSBhIGZlZSBm
-b3IgdGhlIHBoeXNpY2FsIGFjdCBvZiB0cmFuc2ZlcnJpbmcgYSBjb3B5LCBhbmQKeW91IG1heSBh
-dCB5b3VyIG9wdGlvbiBvZmZlciB3YXJyYW50eSBwcm90ZWN0aW9uIGluIGV4Y2hhbmdlIGZvciBh
-IGZlZS4KCiAgMi4gWW91IG1heSBtb2RpZnkgeW91ciBjb3B5IG9yIGNvcGllcyBvZiB0aGUgUHJv
-Z3JhbSBvciBhbnkgcG9ydGlvbgpvZiBpdCwgdGh1cyBmb3JtaW5nIGEgd29yayBiYXNlZCBvbiB0
-aGUgUHJvZ3JhbSwgYW5kIGNvcHkgYW5kCmRpc3RyaWJ1dGUgc3VjaCBtb2RpZmljYXRpb25zIG9y
-IHdvcmsgdW5kZXIgdGhlIHRlcm1zIG9mIFNlY3Rpb24gMQphYm92ZSwgcHJvdmlkZWQgdGhhdCB5
-b3UgYWxzbyBtZWV0IGFsbCBvZiB0aGVzZSBjb25kaXRpb25zOgoKICAgIGEpIFlvdSBtdXN0IGNh
-dXNlIHRoZSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBwcm9taW5lbnQgbm90aWNlcwogICAgc3Rh
-dGluZyB0aGF0IHlvdSBjaGFuZ2VkIHRoZSBmaWxlcyBhbmQgdGhlIGRhdGUgb2YgYW55IGNoYW5n
-ZS4KCiAgICBiKSBZb3UgbXVzdCBjYXVzZSBhbnkgd29yayB0aGF0IHlvdSBkaXN0cmlidXRlIG9y
-IHB1Ymxpc2gsIHRoYXQgaW4KICAgIHdob2xlIG9yIGluIHBhcnQgY29udGFpbnMgb3IgaXMgZGVy
-aXZlZCBmcm9tIHRoZSBQcm9ncmFtIG9yIGFueQogICAgcGFydCB0aGVyZW9mLCB0byBiZSBsaWNl
-bnNlZCBhcyBhIHdob2xlIGF0IG5vIGNoYXJnZSB0byBhbGwgdGhpcmQKICAgIHBhcnRpZXMgdW5k
-ZXIgdGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZS4KCiAgICBjKSBJZiB0aGUgbW9kaWZpZWQgcHJv
-Z3JhbSBub3JtYWxseSByZWFkcyBjb21tYW5kcyBpbnRlcmFjdGl2ZWx5CiAgICB3aGVuIHJ1biwg
-eW91IG11c3QgY2F1c2UgaXQsIHdoZW4gc3RhcnRlZCBydW5uaW5nIGZvciBzdWNoCiAgICBpbnRl
-cmFjdGl2ZSB1c2UgaW4gdGhlIG1vc3Qgb3JkaW5hcnkgd2F5LCB0byBwcmludCBvciBkaXNwbGF5
-IGFuCiAgICBhbm5vdW5jZW1lbnQgaW5jbHVkaW5nIGFuIGFwcHJvcHJpYXRlIGNvcHlyaWdodCBu
-b3RpY2UgYW5kIGEKICAgIG5vdGljZSB0aGF0IHRoZXJlIGlzIG5vIHdhcnJhbnR5IChvciBlbHNl
-LCBzYXlpbmcgdGhhdCB5b3UgcHJvdmlkZQogICAgYSB3YXJyYW50eSkgYW5kIHRoYXQgdXNlcnMg
-bWF5IHJlZGlzdHJpYnV0ZSB0aGUgcHJvZ3JhbSB1bmRlcgogICAgdGhlc2UgY29uZGl0aW9ucywg
-YW5kIHRlbGxpbmcgdGhlIHVzZXIgaG93IHRvIHZpZXcgYSBjb3B5IG9mIHRoaXMKICAgIExpY2Vu
-c2UuICAoRXhjZXB0aW9uOiBpZiB0aGUgUHJvZ3JhbSBpdHNlbGYgaXMgaW50ZXJhY3RpdmUgYnV0
-CiAgICBkb2VzIG5vdCBub3JtYWxseSBwcmludCBzdWNoIGFuIGFubm91bmNlbWVudCwgeW91ciB3
-b3JrIGJhc2VkIG9uCiAgICB0aGUgUHJvZ3JhbSBpcyBub3QgcmVxdWlyZWQgdG8gcHJpbnQgYW4g
-YW5ub3VuY2VtZW50LikKDApUaGVzZSByZXF1aXJlbWVudHMgYXBwbHkgdG8gdGhlIG1vZGlmaWVk
-IHdvcmsgYXMgYSB3aG9sZS4gIElmCmlkZW50aWZpYWJsZSBzZWN0aW9ucyBvZiB0aGF0IHdvcmsg
-YXJlIG5vdCBkZXJpdmVkIGZyb20gdGhlIFByb2dyYW0sCmFuZCBjYW4gYmUgcmVhc29uYWJseSBj
-b25zaWRlcmVkIGluZGVwZW5kZW50IGFuZCBzZXBhcmF0ZSB3b3JrcyBpbgp0aGVtc2VsdmVzLCB0
-aGVuIHRoaXMgTGljZW5zZSwgYW5kIGl0cyB0ZXJtcywgZG8gbm90IGFwcGx5IHRvIHRob3NlCnNl
-Y3Rpb25zIHdoZW4geW91IGRpc3RyaWJ1dGUgdGhlbSBhcyBzZXBhcmF0ZSB3b3Jrcy4gIEJ1dCB3
-aGVuIHlvdQpkaXN0cmlidXRlIHRoZSBzYW1lIHNlY3Rpb25zIGFzIHBhcnQgb2YgYSB3aG9sZSB3
-aGljaCBpcyBhIHdvcmsgYmFzZWQKb24gdGhlIFByb2dyYW0sIHRoZSBkaXN0cmlidXRpb24gb2Yg
-dGhlIHdob2xlIG11c3QgYmUgb24gdGhlIHRlcm1zIG9mCnRoaXMgTGljZW5zZSwgd2hvc2UgcGVy
-bWlzc2lvbnMgZm9yIG90aGVyIGxpY2Vuc2VlcyBleHRlbmQgdG8gdGhlCmVudGlyZSB3aG9sZSwg
-YW5kIHRodXMgdG8gZWFjaCBhbmQgZXZlcnkgcGFydCByZWdhcmRsZXNzIG9mIHdobyB3cm90ZSBp
-dC4KClRodXMsIGl0IGlzIG5vdCB0aGUgaW50ZW50IG9mIHRoaXMgc2VjdGlvbiB0byBjbGFpbSBy
-aWdodHMgb3IgY29udGVzdAp5b3VyIHJpZ2h0cyB0byB3b3JrIHdyaXR0ZW4gZW50aXJlbHkgYnkg
-eW91OyByYXRoZXIsIHRoZSBpbnRlbnQgaXMgdG8KZXhlcmNpc2UgdGhlIHJpZ2h0IHRvIGNvbnRy
-b2wgdGhlIGRpc3RyaWJ1dGlvbiBvZiBkZXJpdmF0aXZlIG9yCmNvbGxlY3RpdmUgd29ya3MgYmFz
-ZWQgb24gdGhlIFByb2dyYW0uCgpJbiBhZGRpdGlvbiwgbWVyZSBhZ2dyZWdhdGlvbiBvZiBhbm90
-aGVyIHdvcmsgbm90IGJhc2VkIG9uIHRoZSBQcm9ncmFtCndpdGggdGhlIFByb2dyYW0gKG9yIHdp
-dGggYSB3b3JrIGJhc2VkIG9uIHRoZSBQcm9ncmFtKSBvbiBhIHZvbHVtZSBvZgphIHN0b3JhZ2Ug
-b3IgZGlzdHJpYnV0aW9uIG1lZGl1bSBkb2VzIG5vdCBicmluZyB0aGUgb3RoZXIgd29yayB1bmRl
-cgp0aGUgc2NvcGUgb2YgdGhpcyBMaWNlbnNlLgoKICAzLiBZb3UgbWF5IGNvcHkgYW5kIGRpc3Ry
-aWJ1dGUgdGhlIFByb2dyYW0gKG9yIGEgd29yayBiYXNlZCBvbiBpdCwKdW5kZXIgU2VjdGlvbiAy
-KSBpbiBvYmplY3QgY29kZSBvciBleGVjdXRhYmxlIGZvcm0gdW5kZXIgdGhlIHRlcm1zIG9mClNl
-Y3Rpb25zIDEgYW5kIDIgYWJvdmUgcHJvdmlkZWQgdGhhdCB5b3UgYWxzbyBkbyBvbmUgb2YgdGhl
-IGZvbGxvd2luZzoKCiAgICBhKSBBY2NvbXBhbnkgaXQgd2l0aCB0aGUgY29tcGxldGUgY29ycmVz
-cG9uZGluZyBtYWNoaW5lLXJlYWRhYmxlCiAgICBzb3VyY2UgY29kZSwgd2hpY2ggbXVzdCBiZSBk
-aXN0cmlidXRlZCB1bmRlciB0aGUgdGVybXMgb2YgU2VjdGlvbnMKICAgIDEgYW5kIDIgYWJvdmUg
-b24gYSBtZWRpdW0gY3VzdG9tYXJpbHkgdXNlZCBmb3Igc29mdHdhcmUgaW50ZXJjaGFuZ2U7IG9y
-LAoKICAgIGIpIEFjY29tcGFueSBpdCB3aXRoIGEgd3JpdHRlbiBvZmZlciwgdmFsaWQgZm9yIGF0
-IGxlYXN0IHRocmVlCiAgICB5ZWFycywgdG8gZ2l2ZSBhbnkgdGhpcmQgcGFydHksIGZvciBhIGNo
-YXJnZSBubyBtb3JlIHRoYW4geW91cgogICAgY29zdCBvZiBwaHlzaWNhbGx5IHBlcmZvcm1pbmcg
-c291cmNlIGRpc3RyaWJ1dGlvbiwgYSBjb21wbGV0ZQogICAgbWFjaGluZS1yZWFkYWJsZSBjb3B5
-IG9mIHRoZSBjb3JyZXNwb25kaW5nIHNvdXJjZSBjb2RlLCB0byBiZQogICAgZGlzdHJpYnV0ZWQg
-dW5kZXIgdGhlIHRlcm1zIG9mIFNlY3Rpb25zIDEgYW5kIDIgYWJvdmUgb24gYSBtZWRpdW0KICAg
-IGN1c3RvbWFyaWx5IHVzZWQgZm9yIHNvZnR3YXJlIGludGVyY2hhbmdlOyBvciwKCiAgICBjKSBB
-Y2NvbXBhbnkgaXQgd2l0aCB0aGUgaW5mb3JtYXRpb24geW91IHJlY2VpdmVkIGFzIHRvIHRoZSBv
-ZmZlcgogICAgdG8gZGlzdHJpYnV0ZSBjb3JyZXNwb25kaW5nIHNvdXJjZSBjb2RlLiAgKFRoaXMg
-YWx0ZXJuYXRpdmUgaXMKICAgIGFsbG93ZWQgb25seSBmb3Igbm9uY29tbWVyY2lhbCBkaXN0cmli
-dXRpb24gYW5kIG9ubHkgaWYgeW91CiAgICByZWNlaXZlZCB0aGUgcHJvZ3JhbSBpbiBvYmplY3Qg
-Y29kZSBvciBleGVjdXRhYmxlIGZvcm0gd2l0aCBzdWNoCiAgICBhbiBvZmZlciwgaW4gYWNjb3Jk
-IHdpdGggU3Vic2VjdGlvbiBiIGFib3ZlLikKClRoZSBzb3VyY2UgY29kZSBmb3IgYSB3b3JrIG1l
-YW5zIHRoZSBwcmVmZXJyZWQgZm9ybSBvZiB0aGUgd29yayBmb3IKbWFraW5nIG1vZGlmaWNhdGlv
-bnMgdG8gaXQuICBGb3IgYW4gZXhlY3V0YWJsZSB3b3JrLCBjb21wbGV0ZSBzb3VyY2UKY29kZSBt
-ZWFucyBhbGwgdGhlIHNvdXJjZSBjb2RlIGZvciBhbGwgbW9kdWxlcyBpdCBjb250YWlucywgcGx1
-cyBhbnkKYXNzb2NpYXRlZCBpbnRlcmZhY2UgZGVmaW5pdGlvbiBmaWxlcywgcGx1cyB0aGUgc2Ny
-aXB0cyB1c2VkIHRvCmNvbnRyb2wgY29tcGlsYXRpb24gYW5kIGluc3RhbGxhdGlvbiBvZiB0aGUg
-ZXhlY3V0YWJsZS4gIEhvd2V2ZXIsIGFzIGEKc3BlY2lhbCBleGNlcHRpb24sIHRoZSBzb3VyY2Ug
-Y29kZSBkaXN0cmlidXRlZCBuZWVkIG5vdCBpbmNsdWRlCmFueXRoaW5nIHRoYXQgaXMgbm9ybWFs
-bHkgZGlzdHJpYnV0ZWQgKGluIGVpdGhlciBzb3VyY2Ugb3IgYmluYXJ5CmZvcm0pIHdpdGggdGhl
-IG1ham9yIGNvbXBvbmVudHMgKGNvbXBpbGVyLCBrZXJuZWwsIGFuZCBzbyBvbikgb2YgdGhlCm9w
-ZXJhdGluZyBzeXN0ZW0gb24gd2hpY2ggdGhlIGV4ZWN1dGFibGUgcnVucywgdW5sZXNzIHRoYXQg
-Y29tcG9uZW50Cml0c2VsZiBhY2NvbXBhbmllcyB0aGUgZXhlY3V0YWJsZS4KCklmIGRpc3RyaWJ1
-dGlvbiBvZiBleGVjdXRhYmxlIG9yIG9iamVjdCBjb2RlIGlzIG1hZGUgYnkgb2ZmZXJpbmcKYWNj
-ZXNzIHRvIGNvcHkgZnJvbSBhIGRlc2lnbmF0ZWQgcGxhY2UsIHRoZW4gb2ZmZXJpbmcgZXF1aXZh
-bGVudAphY2Nlc3MgdG8gY29weSB0aGUgc291cmNlIGNvZGUgZnJvbSB0aGUgc2FtZSBwbGFjZSBj
-b3VudHMgYXMKZGlzdHJpYnV0aW9uIG9mIHRoZSBzb3VyY2UgY29kZSwgZXZlbiB0aG91Z2ggdGhp
-cmQgcGFydGllcyBhcmUgbm90CmNvbXBlbGxlZCB0byBjb3B5IHRoZSBzb3VyY2UgYWxvbmcgd2l0
-aCB0aGUgb2JqZWN0IGNvZGUuCgwKICA0LiBZb3UgbWF5IG5vdCBjb3B5LCBtb2RpZnksIHN1Ymxp
-Y2Vuc2UsIG9yIGRpc3RyaWJ1dGUgdGhlIFByb2dyYW0KZXhjZXB0IGFzIGV4cHJlc3NseSBwcm92
-aWRlZCB1bmRlciB0aGlzIExpY2Vuc2UuICBBbnkgYXR0ZW1wdApvdGhlcndpc2UgdG8gY29weSwg
-bW9kaWZ5LCBzdWJsaWNlbnNlIG9yIGRpc3RyaWJ1dGUgdGhlIFByb2dyYW0gaXMKdm9pZCwgYW5k
-IHdpbGwgYXV0b21hdGljYWxseSB0ZXJtaW5hdGUgeW91ciByaWdodHMgdW5kZXIgdGhpcyBMaWNl
-bnNlLgpIb3dldmVyLCBwYXJ0aWVzIHdobyBoYXZlIHJlY2VpdmVkIGNvcGllcywgb3IgcmlnaHRz
-LCBmcm9tIHlvdSB1bmRlcgp0aGlzIExpY2Vuc2Ugd2lsbCBub3QgaGF2ZSB0aGVpciBsaWNlbnNl
-cyB0ZXJtaW5hdGVkIHNvIGxvbmcgYXMgc3VjaApwYXJ0aWVzIHJlbWFpbiBpbiBmdWxsIGNvbXBs
-aWFuY2UuCgogIDUuIFlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIGFjY2VwdCB0aGlzIExpY2Vuc2Us
-IHNpbmNlIHlvdSBoYXZlIG5vdApzaWduZWQgaXQuICBIb3dldmVyLCBub3RoaW5nIGVsc2UgZ3Jh
-bnRzIHlvdSBwZXJtaXNzaW9uIHRvIG1vZGlmeSBvcgpkaXN0cmlidXRlIHRoZSBQcm9ncmFtIG9y
-IGl0cyBkZXJpdmF0aXZlIHdvcmtzLiAgVGhlc2UgYWN0aW9ucyBhcmUKcHJvaGliaXRlZCBieSBs
-YXcgaWYgeW91IGRvIG5vdCBhY2NlcHQgdGhpcyBMaWNlbnNlLiAgVGhlcmVmb3JlLCBieQptb2Rp
-Znlpbmcgb3IgZGlzdHJpYnV0aW5nIHRoZSBQcm9ncmFtIChvciBhbnkgd29yayBiYXNlZCBvbiB0
-aGUKUHJvZ3JhbSksIHlvdSBpbmRpY2F0ZSB5b3VyIGFjY2VwdGFuY2Ugb2YgdGhpcyBMaWNlbnNl
-IHRvIGRvIHNvLCBhbmQKYWxsIGl0cyB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgY29weWluZywg
-ZGlzdHJpYnV0aW5nIG9yIG1vZGlmeWluZwp0aGUgUHJvZ3JhbSBvciB3b3JrcyBiYXNlZCBvbiBp
-dC4KCiAgNi4gRWFjaCB0aW1lIHlvdSByZWRpc3RyaWJ1dGUgdGhlIFByb2dyYW0gKG9yIGFueSB3
-b3JrIGJhc2VkIG9uIHRoZQpQcm9ncmFtKSwgdGhlIHJlY2lwaWVudCBhdXRvbWF0aWNhbGx5IHJl
-Y2VpdmVzIGEgbGljZW5zZSBmcm9tIHRoZQpvcmlnaW5hbCBsaWNlbnNvciB0byBjb3B5LCBkaXN0
-cmlidXRlIG9yIG1vZGlmeSB0aGUgUHJvZ3JhbSBzdWJqZWN0IHRvCnRoZXNlIHRlcm1zIGFuZCBj
-b25kaXRpb25zLiAgWW91IG1heSBub3QgaW1wb3NlIGFueSBmdXJ0aGVyCnJlc3RyaWN0aW9ucyBv
-biB0aGUgcmVjaXBpZW50cycgZXhlcmNpc2Ugb2YgdGhlIHJpZ2h0cyBncmFudGVkIGhlcmVpbi4K
-WW91IGFyZSBub3QgcmVzcG9uc2libGUgZm9yIGVuZm9yY2luZyBjb21wbGlhbmNlIGJ5IHRoaXJk
-IHBhcnRpZXMgdG8KdGhpcyBMaWNlbnNlLgoKICA3LiBJZiwgYXMgYSBjb25zZXF1ZW5jZSBvZiBh
-IGNvdXJ0IGp1ZGdtZW50IG9yIGFsbGVnYXRpb24gb2YgcGF0ZW50CmluZnJpbmdlbWVudCBvciBm
-b3IgYW55IG90aGVyIHJlYXNvbiAobm90IGxpbWl0ZWQgdG8gcGF0ZW50IGlzc3VlcyksCmNvbmRp
-dGlvbnMgYXJlIGltcG9zZWQgb24geW91ICh3aGV0aGVyIGJ5IGNvdXJ0IG9yZGVyLCBhZ3JlZW1l
-bnQgb3IKb3RoZXJ3aXNlKSB0aGF0IGNvbnRyYWRpY3QgdGhlIGNvbmRpdGlvbnMgb2YgdGhpcyBM
-aWNlbnNlLCB0aGV5IGRvIG5vdApleGN1c2UgeW91IGZyb20gdGhlIGNvbmRpdGlvbnMgb2YgdGhp
-cyBMaWNlbnNlLiAgSWYgeW91IGNhbm5vdApkaXN0cmlidXRlIHNvIGFzIHRvIHNhdGlzZnkgc2lt
-dWx0YW5lb3VzbHkgeW91ciBvYmxpZ2F0aW9ucyB1bmRlciB0aGlzCkxpY2Vuc2UgYW5kIGFueSBv
-dGhlciBwZXJ0aW5lbnQgb2JsaWdhdGlvbnMsIHRoZW4gYXMgYSBjb25zZXF1ZW5jZSB5b3UKbWF5
-IG5vdCBkaXN0cmlidXRlIHRoZSBQcm9ncmFtIGF0IGFsbC4gIEZvciBleGFtcGxlLCBpZiBhIHBh
-dGVudApsaWNlbnNlIHdvdWxkIG5vdCBwZXJtaXQgcm95YWx0eS1mcmVlIHJlZGlzdHJpYnV0aW9u
-IG9mIHRoZSBQcm9ncmFtIGJ5CmFsbCB0aG9zZSB3aG8gcmVjZWl2ZSBjb3BpZXMgZGlyZWN0bHkg
-b3IgaW5kaXJlY3RseSB0aHJvdWdoIHlvdSwgdGhlbgp0aGUgb25seSB3YXkgeW91IGNvdWxkIHNh
-dGlzZnkgYm90aCBpdCBhbmQgdGhpcyBMaWNlbnNlIHdvdWxkIGJlIHRvCnJlZnJhaW4gZW50aXJl
-bHkgZnJvbSBkaXN0cmlidXRpb24gb2YgdGhlIFByb2dyYW0uCgpJZiBhbnkgcG9ydGlvbiBvZiB0
-aGlzIHNlY3Rpb24gaXMgaGVsZCBpbnZhbGlkIG9yIHVuZW5mb3JjZWFibGUgdW5kZXIKYW55IHBh
-cnRpY3VsYXIgY2lyY3Vtc3RhbmNlLCB0aGUgYmFsYW5jZSBvZiB0aGUgc2VjdGlvbiBpcyBpbnRl
-bmRlZCB0bwphcHBseSBhbmQgdGhlIHNlY3Rpb24gYXMgYSB3aG9sZSBpcyBpbnRlbmRlZCB0byBh
-cHBseSBpbiBvdGhlcgpjaXJjdW1zdGFuY2VzLgoKSXQgaXMgbm90IHRoZSBwdXJwb3NlIG9mIHRo
-aXMgc2VjdGlvbiB0byBpbmR1Y2UgeW91IHRvIGluZnJpbmdlIGFueQpwYXRlbnRzIG9yIG90aGVy
-IHByb3BlcnR5IHJpZ2h0IGNsYWltcyBvciB0byBjb250ZXN0IHZhbGlkaXR5IG9mIGFueQpzdWNo
-IGNsYWltczsgdGhpcyBzZWN0aW9uIGhhcyB0aGUgc29sZSBwdXJwb3NlIG9mIHByb3RlY3Rpbmcg
-dGhlCmludGVncml0eSBvZiB0aGUgZnJlZSBzb2Z0d2FyZSBkaXN0cmlidXRpb24gc3lzdGVtLCB3
-aGljaCBpcwppbXBsZW1lbnRlZCBieSBwdWJsaWMgbGljZW5zZSBwcmFjdGljZXMuICBNYW55IHBl
-b3BsZSBoYXZlIG1hZGUKZ2VuZXJvdXMgY29udHJpYnV0aW9ucyB0byB0aGUgd2lkZSByYW5nZSBv
-ZiBzb2Z0d2FyZSBkaXN0cmlidXRlZAp0aHJvdWdoIHRoYXQgc3lzdGVtIGluIHJlbGlhbmNlIG9u
-IGNvbnNpc3RlbnQgYXBwbGljYXRpb24gb2YgdGhhdApzeXN0ZW07IGl0IGlzIHVwIHRvIHRoZSBh
-dXRob3IvZG9ub3IgdG8gZGVjaWRlIGlmIGhlIG9yIHNoZSBpcyB3aWxsaW5nCnRvIGRpc3RyaWJ1
-dGUgc29mdHdhcmUgdGhyb3VnaCBhbnkgb3RoZXIgc3lzdGVtIGFuZCBhIGxpY2Vuc2VlIGNhbm5v
-dAppbXBvc2UgdGhhdCBjaG9pY2UuCgpUaGlzIHNlY3Rpb24gaXMgaW50ZW5kZWQgdG8gbWFrZSB0
-aG9yb3VnaGx5IGNsZWFyIHdoYXQgaXMgYmVsaWV2ZWQgdG8KYmUgYSBjb25zZXF1ZW5jZSBvZiB0
-aGUgcmVzdCBvZiB0aGlzIExpY2Vuc2UuCgwKICA4LiBJZiB0aGUgZGlzdHJpYnV0aW9uIGFuZC9v
-ciB1c2Ugb2YgdGhlIFByb2dyYW0gaXMgcmVzdHJpY3RlZCBpbgpjZXJ0YWluIGNvdW50cmllcyBl
-aXRoZXIgYnkgcGF0ZW50cyBvciBieSBjb3B5cmlnaHRlZCBpbnRlcmZhY2VzLCB0aGUKb3JpZ2lu
-YWwgY29weXJpZ2h0IGhvbGRlciB3aG8gcGxhY2VzIHRoZSBQcm9ncmFtIHVuZGVyIHRoaXMgTGlj
-ZW5zZQptYXkgYWRkIGFuIGV4cGxpY2l0IGdlb2dyYXBoaWNhbCBkaXN0cmlidXRpb24gbGltaXRh
-dGlvbiBleGNsdWRpbmcKdGhvc2UgY291bnRyaWVzLCBzbyB0aGF0IGRpc3RyaWJ1dGlvbiBpcyBw
-ZXJtaXR0ZWQgb25seSBpbiBvciBhbW9uZwpjb3VudHJpZXMgbm90IHRodXMgZXhjbHVkZWQuICBJ
-biBzdWNoIGNhc2UsIHRoaXMgTGljZW5zZSBpbmNvcnBvcmF0ZXMKdGhlIGxpbWl0YXRpb24gYXMg
-aWYgd3JpdHRlbiBpbiB0aGUgYm9keSBvZiB0aGlzIExpY2Vuc2UuCgogIDkuIFRoZSBGcmVlIFNv
-ZnR3YXJlIEZvdW5kYXRpb24gbWF5IHB1Ymxpc2ggcmV2aXNlZCBhbmQvb3IgbmV3IHZlcnNpb25z
-Cm9mIHRoZSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZyb20gdGltZSB0byB0aW1lLiAgU3VjaCBu
-ZXcgdmVyc2lvbnMgd2lsbApiZSBzaW1pbGFyIGluIHNwaXJpdCB0byB0aGUgcHJlc2VudCB2ZXJz
-aW9uLCBidXQgbWF5IGRpZmZlciBpbiBkZXRhaWwgdG8KYWRkcmVzcyBuZXcgcHJvYmxlbXMgb3Ig
-Y29uY2VybnMuCgpFYWNoIHZlcnNpb24gaXMgZ2l2ZW4gYSBkaXN0aW5ndWlzaGluZyB2ZXJzaW9u
-IG51bWJlci4gIElmIHRoZSBQcm9ncmFtCnNwZWNpZmllcyBhIHZlcnNpb24gbnVtYmVyIG9mIHRo
-aXMgTGljZW5zZSB3aGljaCBhcHBsaWVzIHRvIGl0IGFuZCAiYW55CmxhdGVyIHZlcnNpb24iLCB5
-b3UgaGF2ZSB0aGUgb3B0aW9uIG9mIGZvbGxvd2luZyB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMK
-ZWl0aGVyIG9mIHRoYXQgdmVyc2lvbiBvciBvZiBhbnkgbGF0ZXIgdmVyc2lvbiBwdWJsaXNoZWQg
-YnkgdGhlIEZyZWUKU29mdHdhcmUgRm91bmRhdGlvbi4gIElmIHRoZSBQcm9ncmFtIGRvZXMgbm90
-IHNwZWNpZnkgYSB2ZXJzaW9uIG51bWJlciBvZgp0aGlzIExpY2Vuc2UsIHlvdSBtYXkgY2hvb3Nl
-IGFueSB2ZXJzaW9uIGV2ZXIgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlCkZvdW5kYXRp
-b24uCgogIDEwLiBJZiB5b3Ugd2lzaCB0byBpbmNvcnBvcmF0ZSBwYXJ0cyBvZiB0aGUgUHJvZ3Jh
-bSBpbnRvIG90aGVyIGZyZWUKcHJvZ3JhbXMgd2hvc2UgZGlzdHJpYnV0aW9uIGNvbmRpdGlvbnMg
-YXJlIGRpZmZlcmVudCwgd3JpdGUgdG8gdGhlIGF1dGhvcgp0byBhc2sgZm9yIHBlcm1pc3Npb24u
-ICBGb3Igc29mdHdhcmUgd2hpY2ggaXMgY29weXJpZ2h0ZWQgYnkgdGhlIEZyZWUKU29mdHdhcmUg
-Rm91bmRhdGlvbiwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgd2Ugc29t
-ZXRpbWVzCm1ha2UgZXhjZXB0aW9ucyBmb3IgdGhpcy4gIE91ciBkZWNpc2lvbiB3aWxsIGJlIGd1
-aWRlZCBieSB0aGUgdHdvIGdvYWxzCm9mIHByZXNlcnZpbmcgdGhlIGZyZWUgc3RhdHVzIG9mIGFs
-bCBkZXJpdmF0aXZlcyBvZiBvdXIgZnJlZSBzb2Z0d2FyZSBhbmQKb2YgcHJvbW90aW5nIHRoZSBz
-aGFyaW5nIGFuZCByZXVzZSBvZiBzb2Z0d2FyZSBnZW5lcmFsbHkuCgoJCQkgICAgTk8gV0FSUkFO
-VFkKCiAgMTEuIEJFQ0FVU0UgVEhFIFBST0dSQU0gSVMgTElDRU5TRUQgRlJFRSBPRiBDSEFSR0Us
-IFRIRVJFIElTIE5PIFdBUlJBTlRZCkZPUiBUSEUgUFJPR1JBTSwgVE8gVEhFIEVYVEVOVCBQRVJN
-SVRURUQgQlkgQVBQTElDQUJMRSBMQVcuICBFWENFUFQgV0hFTgpPVEhFUldJU0UgU1RBVEVEIElO
-IFdSSVRJTkcgVEhFIENPUFlSSUdIVCBIT0xERVJTIEFORC9PUiBPVEhFUiBQQVJUSUVTClBST1ZJ
-REUgVEhFIFBST0dSQU0gIkFTIElTIiBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFSVRI
-RVIgRVhQUkVTU0VECk9SIElNUExJRUQsIElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBU
-SEUgSU1QTElFRCBXQVJSQU5USUVTIE9GCk1FUkNIQU5UQUJJTElUWSBBTkQgRklUTkVTUyBGT1Ig
-QSBQQVJUSUNVTEFSIFBVUlBPU0UuICBUSEUgRU5USVJFIFJJU0sgQVMKVE8gVEhFIFFVQUxJVFkg
-QU5EIFBFUkZPUk1BTkNFIE9GIFRIRSBQUk9HUkFNIElTIFdJVEggWU9VLiAgU0hPVUxEIFRIRQpQ
-Uk9HUkFNIFBST1ZFIERFRkVDVElWRSwgWU9VIEFTU1VNRSBUSEUgQ09TVCBPRiBBTEwgTkVDRVNT
-QVJZIFNFUlZJQ0lORywKUkVQQUlSIE9SIENPUlJFQ1RJT04uCgogIDEyLiBJTiBOTyBFVkVOVCBV
-TkxFU1MgUkVRVUlSRUQgQlkgQVBQTElDQUJMRSBMQVcgT1IgQUdSRUVEIFRPIElOIFdSSVRJTkcK
-V0lMTCBBTlkgQ09QWVJJR0hUIEhPTERFUiwgT1IgQU5ZIE9USEVSIFBBUlRZIFdITyBNQVkgTU9E
-SUZZIEFORC9PUgpSRURJU1RSSUJVVEUgVEhFIFBST0dSQU0gQVMgUEVSTUlUVEVEIEFCT1ZFLCBC
-RSBMSUFCTEUgVE8gWU9VIEZPUiBEQU1BR0VTLApJTkNMVURJTkcgQU5ZIEdFTkVSQUwsIFNQRUNJ
-QUwsIElOQ0lERU5UQUwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIEFSSVNJTkcKT1VUIE9GIFRI
-RSBVU0UgT1IgSU5BQklMSVRZIFRPIFVTRSBUSEUgUFJPR1JBTSAoSU5DTFVESU5HIEJVVCBOT1Qg
-TElNSVRFRApUTyBMT1NTIE9GIERBVEEgT1IgREFUQSBCRUlORyBSRU5ERVJFRCBJTkFDQ1VSQVRF
-IE9SIExPU1NFUyBTVVNUQUlORUQgQlkKWU9VIE9SIFRISVJEIFBBUlRJRVMgT1IgQSBGQUlMVVJF
-IE9GIFRIRSBQUk9HUkFNIFRPIE9QRVJBVEUgV0lUSCBBTlkgT1RIRVIKUFJPR1JBTVMpLCBFVkVO
-IElGIFNVQ0ggSE9MREVSIE9SIE9USEVSIFBBUlRZIEhBUyBCRUVOIEFEVklTRUQgT0YgVEhFClBP
-U1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFUy4KCgkJICAgICBFTkQgT0YgVEVSTVMgQU5EIENPTkRJ
-VElPTlMKDAoJICAgIEhvdyB0byBBcHBseSBUaGVzZSBUZXJtcyB0byBZb3VyIE5ldyBQcm9ncmFt
-cwoKICBJZiB5b3UgZGV2ZWxvcCBhIG5ldyBwcm9ncmFtLCBhbmQgeW91IHdhbnQgaXQgdG8gYmUg
-b2YgdGhlIGdyZWF0ZXN0CnBvc3NpYmxlIHVzZSB0byB0aGUgcHVibGljLCB0aGUgYmVzdCB3YXkg
-dG8gYWNoaWV2ZSB0aGlzIGlzIHRvIG1ha2UgaXQKZnJlZSBzb2Z0d2FyZSB3aGljaCBldmVyeW9u
-ZSBjYW4gcmVkaXN0cmlidXRlIGFuZCBjaGFuZ2UgdW5kZXIgdGhlc2UgdGVybXMuCgogIFRvIGRv
-IHNvLCBhdHRhY2ggdGhlIGZvbGxvd2luZyBub3RpY2VzIHRvIHRoZSBwcm9ncmFtLiAgSXQgaXMg
-c2FmZXN0CnRvIGF0dGFjaCB0aGVtIHRvIHRoZSBzdGFydCBvZiBlYWNoIHNvdXJjZSBmaWxlIHRv
-IG1vc3QgZWZmZWN0aXZlbHkKY29udmV5IHRoZSBleGNsdXNpb24gb2Ygd2FycmFudHk7IGFuZCBl
-YWNoIGZpbGUgc2hvdWxkIGhhdmUgYXQgbGVhc3QKdGhlICJjb3B5cmlnaHQiIGxpbmUgYW5kIGEg
-cG9pbnRlciB0byB3aGVyZSB0aGUgZnVsbCBub3RpY2UgaXMgZm91bmQuCgogICAgPG9uZSBsaW5l
-IHRvIGdpdmUgdGhlIHByb2dyYW0ncyBuYW1lIGFuZCBhIGJyaWVmIGlkZWEgb2Ygd2hhdCBpdCBk
-b2VzLj4KICAgIENvcHlyaWdodCAoQykgPHllYXI+ICA8bmFtZSBvZiBhdXRob3I+CgogICAgVGhp
-cyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9v
-ciBtb2RpZnkKICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGlj
-IExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5CiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9u
-OyBlaXRoZXIgdmVyc2lvbiAyIG9mIHRoZSBMaWNlbnNlLCBvcgogICAgKGF0IHlvdXIgb3B0aW9u
-KSBhbnkgbGF0ZXIgdmVyc2lvbi4KCiAgICBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4g
-dGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwKICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJS
-QU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mCiAgICBNRVJDSEFOVEFC
-SUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlCiAgICBH
-TlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLgoKICAgIFlvdSBzaG91
-bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNl
-CiAgICBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBT
-b2Z0d2FyZQogICAgRm91bmRhdGlvbiwgSW5jLiwgNTkgVGVtcGxlIFBsYWNlLCBTdWl0ZSAzMzAs
-IEJvc3RvbiwgTUEgIDAyMTExLTEzMDcgIFVTQQoKCkFsc28gYWRkIGluZm9ybWF0aW9uIG9uIGhv
-dyB0byBjb250YWN0IHlvdSBieSBlbGVjdHJvbmljIGFuZCBwYXBlciBtYWlsLgoKSWYgdGhlIHBy
-b2dyYW0gaXMgaW50ZXJhY3RpdmUsIG1ha2UgaXQgb3V0cHV0IGEgc2hvcnQgbm90aWNlIGxpa2Ug
-dGhpcwp3aGVuIGl0IHN0YXJ0cyBpbiBhbiBpbnRlcmFjdGl2ZSBtb2RlOgoKICAgIEdub21vdmlz
-aW9uIHZlcnNpb24gNjksIENvcHlyaWdodCAoQykgeWVhciBuYW1lIG9mIGF1dGhvcgogICAgR25v
-bW92aXNpb24gY29tZXMgd2l0aCBBQlNPTFVURUxZIE5PIFdBUlJBTlRZOyBmb3IgZGV0YWlscyB0
-eXBlIGBzaG93IHcnLgogICAgVGhpcyBpcyBmcmVlIHNvZnR3YXJlLCBhbmQgeW91IGFyZSB3ZWxj
-b21lIHRvIHJlZGlzdHJpYnV0ZSBpdAogICAgdW5kZXIgY2VydGFpbiBjb25kaXRpb25zOyB0eXBl
-IGBzaG93IGMnIGZvciBkZXRhaWxzLgoKVGhlIGh5cG90aGV0aWNhbCBjb21tYW5kcyBgc2hvdyB3
-JyBhbmQgYHNob3cgYycgc2hvdWxkIHNob3cgdGhlIGFwcHJvcHJpYXRlCnBhcnRzIG9mIHRoZSBH
-ZW5lcmFsIFB1YmxpYyBMaWNlbnNlLiAgT2YgY291cnNlLCB0aGUgY29tbWFuZHMgeW91IHVzZSBt
-YXkKYmUgY2FsbGVkIHNvbWV0aGluZyBvdGhlciB0aGFuIGBzaG93IHcnIGFuZCBgc2hvdyBjJzsg
-dGhleSBjb3VsZCBldmVuIGJlCm1vdXNlLWNsaWNrcyBvciBtZW51IGl0ZW1zLS13aGF0ZXZlciBz
-dWl0cyB5b3VyIHByb2dyYW0uCgpZb3Ugc2hvdWxkIGFsc28gZ2V0IHlvdXIgZW1wbG95ZXIgKGlm
-IHlvdSB3b3JrIGFzIGEgcHJvZ3JhbW1lcikgb3IgeW91cgpzY2hvb2wsIGlmIGFueSwgdG8gc2ln
-biBhICJjb3B5cmlnaHQgZGlzY2xhaW1lciIgZm9yIHRoZSBwcm9ncmFtLCBpZgpuZWNlc3Nhcnku
-ICBIZXJlIGlzIGEgc2FtcGxlOyBhbHRlciB0aGUgbmFtZXM6CgogIFlveW9keW5lLCBJbmMuLCBo
-ZXJlYnkgZGlzY2xhaW1zIGFsbCBjb3B5cmlnaHQgaW50ZXJlc3QgaW4gdGhlIHByb2dyYW0KICBg
-R25vbW92aXNpb24nICh3aGljaCBtYWtlcyBwYXNzZXMgYXQgY29tcGlsZXJzKSB3cml0dGVuIGJ5
-IEphbWVzIEhhY2tlci4KCiAgPHNpZ25hdHVyZSBvZiBUeSBDb29uPiwgMSBBcHJpbCAxOTg5CiAg
-VHkgQ29vbiwgUHJlc2lkZW50IG9mIFZpY2UKClRoaXMgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBk
-b2VzIG5vdCBwZXJtaXQgaW5jb3Jwb3JhdGluZyB5b3VyIHByb2dyYW0gaW50bwpwcm9wcmlldGFy
-eSBwcm9ncmFtcy4gIElmIHlvdXIgcHJvZ3JhbSBpcyBhIHN1YnJvdXRpbmUgbGlicmFyeSwgeW91
-IG1heQpjb25zaWRlciBpdCBtb3JlIHVzZWZ1bCB0byBwZXJtaXQgbGlua2luZyBwcm9wcmlldGFy
-eSBhcHBsaWNhdGlvbnMgd2l0aCB0aGUKbGlicmFyeS4gIElmIHRoaXMgaXMgd2hhdCB5b3Ugd2Fu
-dCB0byBkbywgdXNlIHRoZSBHTlUgTGlicmFyeSBHZW5lcmFsClB1YmxpYyBMaWNlbnNlIGluc3Rl
-YWQgb2YgdGhpcyBMaWNlbnNlLgo=
-ClxjaGFwdGVye1RoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZX0KClxiZWdpbntjZW50ZXJ9
-CntccGFyaW5kZW50IDBpbgoKVmVyc2lvbiAyLCBKdW5lIDE5OTEKCkNvcHlyaWdodCBcY29weXJp
-Z2h0XCAxOTg5LCAxOTkxIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLgoKXGJpZ3NraXAK
-CjU5IFRlbXBsZSBQbGFjZSAtIFN1aXRlIDMzMCwgQm9zdG9uLCBNQSAgMDIxMTEtMTMwNywgVVNB
-CgpcYmlnc2tpcAoKRXZlcnlvbmUgaXMgcGVybWl0dGVkIHRvIGNvcHkgYW5kIGRpc3RyaWJ1dGUg
-dmVyYmF0aW0gY29waWVzCm9mIHRoaXMgbGljZW5zZSBkb2N1bWVudCwgYnV0IGNoYW5naW5nIGl0
-IGlzIG5vdCBhbGxvd2VkLgp9ClxlbmR7Y2VudGVyfQoKXGJlZ2lue2NlbnRlcn0Ke1xiZlxsYXJn
-ZSBQcmVhbWJsZX0KXGVuZHtjZW50ZXJ9CgoKVGhlIGxpY2Vuc2VzIGZvciBtb3N0IHNvZnR3YXJl
-IGFyZSBkZXNpZ25lZCB0byB0YWtlIGF3YXkgeW91ciBmcmVlZG9tIHRvCnNoYXJlIGFuZCBjaGFu
-Z2UgaXQuICBCeSBjb250cmFzdCwgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGlzCmlu
-dGVuZGVkIHRvIGd1YXJhbnRlZSB5b3VyIGZyZWVkb20gdG8gc2hhcmUgYW5kIGNoYW5nZSBmcmVl
-IHNvZnR3YXJlLS0tdG8KbWFrZSBzdXJlIHRoZSBzb2Z0d2FyZSBpcyBmcmVlIGZvciBhbGwgaXRz
-IHVzZXJzLiAgVGhpcyBHZW5lcmFsIFB1YmxpYwpMaWNlbnNlIGFwcGxpZXMgdG8gbW9zdCBvZiB0
-aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uJ3Mgc29mdHdhcmUgYW5kIHRvCmFueSBvdGhlciBw
-cm9ncmFtIHdob3NlIGF1dGhvcnMgY29tbWl0IHRvIHVzaW5nIGl0LiAgKFNvbWUgb3RoZXIgRnJl
-ZQpTb2Z0d2FyZSBGb3VuZGF0aW9uIHNvZnR3YXJlIGlzIGNvdmVyZWQgYnkgdGhlIEdOVSBMaWJy
-YXJ5IEdlbmVyYWwgUHVibGljCkxpY2Vuc2UgaW5zdGVhZC4pICBZb3UgY2FuIGFwcGx5IGl0IHRv
-IHlvdXIgcHJvZ3JhbXMsIHRvby4KCldoZW4gd2Ugc3BlYWsgb2YgZnJlZSBzb2Z0d2FyZSwgd2Ug
-YXJlIHJlZmVycmluZyB0byBmcmVlZG9tLCBub3QgcHJpY2UuCk91ciBHZW5lcmFsIFB1YmxpYyBM
-aWNlbnNlcyBhcmUgZGVzaWduZWQgdG8gbWFrZSBzdXJlIHRoYXQgeW91IGhhdmUgdGhlCmZyZWVk
-b20gdG8gZGlzdHJpYnV0ZSBjb3BpZXMgb2YgZnJlZSBzb2Z0d2FyZSAoYW5kIGNoYXJnZSBmb3Ig
-dGhpcyBzZXJ2aWNlCmlmIHlvdSB3aXNoKSwgdGhhdCB5b3UgcmVjZWl2ZSBzb3VyY2UgY29kZSBv
-ciBjYW4gZ2V0IGl0IGlmIHlvdSB3YW50IGl0LAp0aGF0IHlvdSBjYW4gY2hhbmdlIHRoZSBzb2Z0
-d2FyZSBvciB1c2UgcGllY2VzIG9mIGl0IGluIG5ldyBmcmVlIHByb2dyYW1zOwphbmQgdGhhdCB5
-b3Uga25vdyB5b3UgY2FuIGRvIHRoZXNlIHRoaW5ncy4KClRvIHByb3RlY3QgeW91ciByaWdodHMs
-IHdlIG5lZWQgdG8gbWFrZSByZXN0cmljdGlvbnMgdGhhdCBmb3JiaWQgYW55b25lIHRvCmRlbnkg
-eW91IHRoZXNlIHJpZ2h0cyBvciB0byBhc2sgeW91IHRvIHN1cnJlbmRlciB0aGUgcmlnaHRzLiAg
-VGhlc2UKcmVzdHJpY3Rpb25zIHRyYW5zbGF0ZSB0byBjZXJ0YWluIHJlc3BvbnNpYmlsaXRpZXMg
-Zm9yIHlvdSBpZiB5b3UKZGlzdHJpYnV0ZSBjb3BpZXMgb2YgdGhlIHNvZnR3YXJlLCBvciBpZiB5
-b3UgbW9kaWZ5IGl0LgoKRm9yIGV4YW1wbGUsIGlmIHlvdSBkaXN0cmlidXRlIGNvcGllcyBvZiBz
-dWNoIGEgcHJvZ3JhbSwgd2hldGhlciBncmF0aXMgb3IKZm9yIGEgZmVlLCB5b3UgbXVzdCBnaXZl
-IHRoZSByZWNpcGllbnRzIGFsbCB0aGUgcmlnaHRzIHRoYXQgeW91IGhhdmUuICBZb3UKbXVzdCBt
-YWtlIHN1cmUgdGhhdCB0aGV5LCB0b28sIHJlY2VpdmUgb3IgY2FuIGdldCB0aGUgc291cmNlIGNv
-ZGUuICBBbmQKeW91IG11c3Qgc2hvdyB0aGVtIHRoZXNlIHRlcm1zIHNvIHRoZXkga25vdyB0aGVp
-ciByaWdodHMuCgpXZSBwcm90ZWN0IHlvdXIgcmlnaHRzIHdpdGggdHdvIHN0ZXBzOiAoMSkgY29w
-eXJpZ2h0IHRoZSBzb2Z0d2FyZSwgYW5kICgyKQpvZmZlciB5b3UgdGhpcyBsaWNlbnNlIHdoaWNo
-IGdpdmVzIHlvdSBsZWdhbCBwZXJtaXNzaW9uIHRvIGNvcHksCmRpc3RyaWJ1dGUgYW5kL29yIG1v
-ZGlmeSB0aGUgc29mdHdhcmUuCgpBbHNvLCBmb3IgZWFjaCBhdXRob3IncyBwcm90ZWN0aW9uIGFu
-ZCBvdXJzLCB3ZSB3YW50IHRvIG1ha2UgY2VydGFpbiB0aGF0CmV2ZXJ5b25lIHVuZGVyc3RhbmRz
-IHRoYXQgdGhlcmUgaXMgbm8gd2FycmFudHkgZm9yIHRoaXMgZnJlZSBzb2Z0d2FyZS4gIElmCnRo
-ZSBzb2Z0d2FyZSBpcyBtb2RpZmllZCBieSBzb21lb25lIGVsc2UgYW5kIHBhc3NlZCBvbiwgd2Ug
-d2FudCBpdHMKcmVjaXBpZW50cyB0byBrbm93IHRoYXQgd2hhdCB0aGV5IGhhdmUgaXMgbm90IHRo
-ZSBvcmlnaW5hbCwgc28gdGhhdCBhbnkKcHJvYmxlbXMgaW50cm9kdWNlZCBieSBvdGhlcnMgd2ls
-bCBub3QgcmVmbGVjdCBvbiB0aGUgb3JpZ2luYWwgYXV0aG9ycycKcmVwdXRhdGlvbnMuCgpGaW5h
-bGx5LCBhbnkgZnJlZSBwcm9ncmFtIGlzIHRocmVhdGVuZWQgY29uc3RhbnRseSBieSBzb2Z0d2Fy
-ZSBwYXRlbnRzLgpXZSB3aXNoIHRvIGF2b2lkIHRoZSBkYW5nZXIgdGhhdCByZWRpc3RyaWJ1dG9y
-cyBvZiBhIGZyZWUgcHJvZ3JhbSB3aWxsCmluZGl2aWR1YWxseSBvYnRhaW4gcGF0ZW50IGxpY2Vu
-c2VzLCBpbiBlZmZlY3QgbWFraW5nIHRoZSBwcm9ncmFtCnByb3ByaWV0YXJ5LiAgVG8gcHJldmVu
-dCB0aGlzLCB3ZSBoYXZlIG1hZGUgaXQgY2xlYXIgdGhhdCBhbnkgcGF0ZW50IG11c3QKYmUgbGlj
-ZW5zZWQgZm9yIGV2ZXJ5b25lJ3MgZnJlZSB1c2Ugb3Igbm90IGxpY2Vuc2VkIGF0IGFsbC4KClRo
-ZSBwcmVjaXNlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciBjb3B5aW5nLCBkaXN0cmlidXRpb24g
-YW5kCm1vZGlmaWNhdGlvbiBmb2xsb3cuCgpcYmVnaW57Y2VudGVyfQp7XExhcmdlIFxzYyBUZXJt
-cyBhbmQgQ29uZGl0aW9ucyBGb3IgQ29weWluZywgRGlzdHJpYnV0aW9uIGFuZAogIE1vZGlmaWNh
-dGlvbn0KXGVuZHtjZW50ZXJ9CgoKJVxyZW5ld2NvbW1hbmR7XHRoZWVudW1pfXtcYWxwaGF7ZW51
-bWl9fQpcYmVnaW57ZW51bWVyYXRlfQoKXGFkZHRvY291bnRlcntlbnVtaX17LTF9CgpcaXRlbSAK
-ClRoaXMgTGljZW5zZSBhcHBsaWVzIHRvIGFueSBwcm9ncmFtIG9yIG90aGVyIHdvcmsgd2hpY2gg
-Y29udGFpbnMgYSBub3RpY2UKcGxhY2VkIGJ5IHRoZSBjb3B5cmlnaHQgaG9sZGVyIHNheWluZyBp
-dCBtYXkgYmUgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlCnRlcm1zIG9mIHRoaXMgR2VuZXJhbCBQdWJs
-aWMgTGljZW5zZS4gIFRoZSBgYFByb2dyYW0nJywgYmVsb3csIHJlZmVycyB0bwphbnkgc3VjaCBw
-cm9ncmFtIG9yIHdvcmssIGFuZCBhIGBgd29yayBiYXNlZCBvbiB0aGUgUHJvZ3JhbScnIG1lYW5z
-IGVpdGhlcgp0aGUgUHJvZ3JhbSBvciBhbnkgZGVyaXZhdGl2ZSB3b3JrIHVuZGVyIGNvcHlyaWdo
-dCBsYXc6IHRoYXQgaXMgdG8gc2F5LCBhCndvcmsgY29udGFpbmluZyB0aGUgUHJvZ3JhbSBvciBh
-IHBvcnRpb24gb2YgaXQsIGVpdGhlciB2ZXJiYXRpbSBvciB3aXRoCm1vZGlmaWNhdGlvbnMgYW5k
-L29yIHRyYW5zbGF0ZWQgaW50byBhbm90aGVyIGxhbmd1YWdlLiAgKEhlcmVpbmFmdGVyLAp0cmFu
-c2xhdGlvbiBpcyBpbmNsdWRlZCB3aXRob3V0IGxpbWl0YXRpb24gaW4gdGhlIHRlcm0gYGBtb2Rp
-ZmljYXRpb24nJy4pCkVhY2ggbGljZW5zZWUgaXMgYWRkcmVzc2VkIGFzIGBgeW91JycuCgpBY3Rp
-dml0aWVzIG90aGVyIHRoYW4gY29weWluZywgZGlzdHJpYnV0aW9uIGFuZCBtb2RpZmljYXRpb24g
-YXJlIG5vdApjb3ZlcmVkIGJ5IHRoaXMgTGljZW5zZTsgdGhleSBhcmUgb3V0c2lkZSBpdHMgc2Nv
-cGUuICBUaGUgYWN0IG9mCnJ1bm5pbmcgdGhlIFByb2dyYW0gaXMgbm90IHJlc3RyaWN0ZWQsIGFu
-ZCB0aGUgb3V0cHV0IGZyb20gdGhlIFByb2dyYW0KaXMgY292ZXJlZCBvbmx5IGlmIGl0cyBjb250
-ZW50cyBjb25zdGl0dXRlIGEgd29yayBiYXNlZCBvbiB0aGUKUHJvZ3JhbSAoaW5kZXBlbmRlbnQg
-b2YgaGF2aW5nIGJlZW4gbWFkZSBieSBydW5uaW5nIHRoZSBQcm9ncmFtKS4KV2hldGhlciB0aGF0
-IGlzIHRydWUgZGVwZW5kcyBvbiB3aGF0IHRoZSBQcm9ncmFtIGRvZXMuCgpcaXRlbSBZb3UgbWF5
-IGNvcHkgYW5kIGRpc3RyaWJ1dGUgdmVyYmF0aW0gY29waWVzIG9mIHRoZSBQcm9ncmFtJ3Mgc291
-cmNlCiAgY29kZSBhcyB5b3UgcmVjZWl2ZSBpdCwgaW4gYW55IG1lZGl1bSwgcHJvdmlkZWQgdGhh
-dCB5b3UgY29uc3BpY3VvdXNseQogIGFuZCBhcHByb3ByaWF0ZWx5IHB1Ymxpc2ggb24gZWFjaCBj
-b3B5IGFuIGFwcHJvcHJpYXRlIGNvcHlyaWdodCBub3RpY2UKICBhbmQgZGlzY2xhaW1lciBvZiB3
-YXJyYW50eTsga2VlcCBpbnRhY3QgYWxsIHRoZSBub3RpY2VzIHRoYXQgcmVmZXIgdG8KICB0aGlz
-IExpY2Vuc2UgYW5kIHRvIHRoZSBhYnNlbmNlIG9mIGFueSB3YXJyYW50eTsgYW5kIGdpdmUgYW55
-IG90aGVyCiAgcmVjaXBpZW50cyBvZiB0aGUgUHJvZ3JhbSBhIGNvcHkgb2YgdGhpcyBMaWNlbnNl
-IGFsb25nIHdpdGggdGhlIFByb2dyYW0uCgpZb3UgbWF5IGNoYXJnZSBhIGZlZSBmb3IgdGhlIHBo
-eXNpY2FsIGFjdCBvZiB0cmFuc2ZlcnJpbmcgYSBjb3B5LCBhbmQgeW91Cm1heSBhdCB5b3VyIG9w
-dGlvbiBvZmZlciB3YXJyYW50eSBwcm90ZWN0aW9uIGluIGV4Y2hhbmdlIGZvciBhIGZlZS4KClxp
-dGVtCgpZb3UgbWF5IG1vZGlmeSB5b3VyIGNvcHkgb3IgY29waWVzIG9mIHRoZSBQcm9ncmFtIG9y
-IGFueSBwb3J0aW9uCm9mIGl0LCB0aHVzIGZvcm1pbmcgYSB3b3JrIGJhc2VkIG9uIHRoZSBQcm9n
-cmFtLCBhbmQgY29weSBhbmQKZGlzdHJpYnV0ZSBzdWNoIG1vZGlmaWNhdGlvbnMgb3Igd29yayB1
-bmRlciB0aGUgdGVybXMgb2YgU2VjdGlvbiAxCmFib3ZlLCBwcm92aWRlZCB0aGF0IHlvdSBhbHNv
-IG1lZXQgYWxsIG9mIHRoZXNlIGNvbmRpdGlvbnM6CgpcYmVnaW57ZW51bWVyYXRlfQoKXGl0ZW0g
-CgpZb3UgbXVzdCBjYXVzZSB0aGUgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5v
-dGljZXMgc3RhdGluZyB0aGF0CnlvdSBjaGFuZ2VkIHRoZSBmaWxlcyBhbmQgdGhlIGRhdGUgb2Yg
-YW55IGNoYW5nZS4KClxpdGVtCgpZb3UgbXVzdCBjYXVzZSBhbnkgd29yayB0aGF0IHlvdSBkaXN0
-cmlidXRlIG9yIHB1Ymxpc2gsIHRoYXQgaW4Kd2hvbGUgb3IgaW4gcGFydCBjb250YWlucyBvciBp
-cyBkZXJpdmVkIGZyb20gdGhlIFByb2dyYW0gb3IgYW55CnBhcnQgdGhlcmVvZiwgdG8gYmUgbGlj
-ZW5zZWQgYXMgYSB3aG9sZSBhdCBubyBjaGFyZ2UgdG8gYWxsIHRoaXJkCnBhcnRpZXMgdW5kZXIg
-dGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZS4KClxpdGVtCklmIHRoZSBtb2RpZmllZCBwcm9ncmFt
-IG5vcm1hbGx5IHJlYWRzIGNvbW1hbmRzIGludGVyYWN0aXZlbHkKd2hlbiBydW4sIHlvdSBtdXN0
-IGNhdXNlIGl0LCB3aGVuIHN0YXJ0ZWQgcnVubmluZyBmb3Igc3VjaAppbnRlcmFjdGl2ZSB1c2Ug
-aW4gdGhlIG1vc3Qgb3JkaW5hcnkgd2F5LCB0byBwcmludCBvciBkaXNwbGF5IGFuCmFubm91bmNl
-bWVudCBpbmNsdWRpbmcgYW4gYXBwcm9wcmlhdGUgY29weXJpZ2h0IG5vdGljZSBhbmQgYQpub3Rp
-Y2UgdGhhdCB0aGVyZSBpcyBubyB3YXJyYW50eSAob3IgZWxzZSwgc2F5aW5nIHRoYXQgeW91IHBy
-b3ZpZGUKYSB3YXJyYW50eSkgYW5kIHRoYXQgdXNlcnMgbWF5IHJlZGlzdHJpYnV0ZSB0aGUgcHJv
-Z3JhbSB1bmRlcgp0aGVzZSBjb25kaXRpb25zLCBhbmQgdGVsbGluZyB0aGUgdXNlciBob3cgdG8g
-dmlldyBhIGNvcHkgb2YgdGhpcwpMaWNlbnNlLiAgKEV4Y2VwdGlvbjogaWYgdGhlIFByb2dyYW0g
-aXRzZWxmIGlzIGludGVyYWN0aXZlIGJ1dApkb2VzIG5vdCBub3JtYWxseSBwcmludCBzdWNoIGFu
-IGFubm91bmNlbWVudCwgeW91ciB3b3JrIGJhc2VkIG9uCnRoZSBQcm9ncmFtIGlzIG5vdCByZXF1
-aXJlZCB0byBwcmludCBhbiBhbm5vdW5jZW1lbnQuKQoKXGVuZHtlbnVtZXJhdGV9CgoKVGhlc2Ug
-cmVxdWlyZW1lbnRzIGFwcGx5IHRvIHRoZSBtb2RpZmllZCB3b3JrIGFzIGEgd2hvbGUuICBJZgpp
-ZGVudGlmaWFibGUgc2VjdGlvbnMgb2YgdGhhdCB3b3JrIGFyZSBub3QgZGVyaXZlZCBmcm9tIHRo
-ZSBQcm9ncmFtLAphbmQgY2FuIGJlIHJlYXNvbmFibHkgY29uc2lkZXJlZCBpbmRlcGVuZGVudCBh
-bmQgc2VwYXJhdGUgd29ya3MgaW4KdGhlbXNlbHZlcywgdGhlbiB0aGlzIExpY2Vuc2UsIGFuZCBp
-dHMgdGVybXMsIGRvIG5vdCBhcHBseSB0byB0aG9zZQpzZWN0aW9ucyB3aGVuIHlvdSBkaXN0cmli
-dXRlIHRoZW0gYXMgc2VwYXJhdGUgd29ya3MuICBCdXQgd2hlbiB5b3UKZGlzdHJpYnV0ZSB0aGUg
-c2FtZSBzZWN0aW9ucyBhcyBwYXJ0IG9mIGEgd2hvbGUgd2hpY2ggaXMgYSB3b3JrIGJhc2VkCm9u
-IHRoZSBQcm9ncmFtLCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSB3aG9sZSBtdXN0IGJlIG9uIHRo
-ZSB0ZXJtcyBvZgp0aGlzIExpY2Vuc2UsIHdob3NlIHBlcm1pc3Npb25zIGZvciBvdGhlciBsaWNl
-bnNlZXMgZXh0ZW5kIHRvIHRoZQplbnRpcmUgd2hvbGUsIGFuZCB0aHVzIHRvIGVhY2ggYW5kIGV2
-ZXJ5IHBhcnQgcmVnYXJkbGVzcyBvZiB3aG8gd3JvdGUgaXQuCgpUaHVzLCBpdCBpcyBub3QgdGhl
-IGludGVudCBvZiB0aGlzIHNlY3Rpb24gdG8gY2xhaW0gcmlnaHRzIG9yIGNvbnRlc3QKeW91ciBy
-aWdodHMgdG8gd29yayB3cml0dGVuIGVudGlyZWx5IGJ5IHlvdTsgcmF0aGVyLCB0aGUgaW50ZW50
-IGlzIHRvCmV4ZXJjaXNlIHRoZSByaWdodCB0byBjb250cm9sIHRoZSBkaXN0cmlidXRpb24gb2Yg
-ZGVyaXZhdGl2ZSBvcgpjb2xsZWN0aXZlIHdvcmtzIGJhc2VkIG9uIHRoZSBQcm9ncmFtLgoKSW4g
-YWRkaXRpb24sIG1lcmUgYWdncmVnYXRpb24gb2YgYW5vdGhlciB3b3JrIG5vdCBiYXNlZCBvbiB0
-aGUgUHJvZ3JhbQp3aXRoIHRoZSBQcm9ncmFtIChvciB3aXRoIGEgd29yayBiYXNlZCBvbiB0aGUg
-UHJvZ3JhbSkgb24gYSB2b2x1bWUgb2YKYSBzdG9yYWdlIG9yIGRpc3RyaWJ1dGlvbiBtZWRpdW0g
-ZG9lcyBub3QgYnJpbmcgdGhlIG90aGVyIHdvcmsgdW5kZXIKdGhlIHNjb3BlIG9mIHRoaXMgTGlj
-ZW5zZS4KClxpdGVtCllvdSBtYXkgY29weSBhbmQgZGlzdHJpYnV0ZSB0aGUgUHJvZ3JhbSAob3Ig
-YSB3b3JrIGJhc2VkIG9uIGl0LAp1bmRlciBTZWN0aW9uIDIpIGluIG9iamVjdCBjb2RlIG9yIGV4
-ZWN1dGFibGUgZm9ybSB1bmRlciB0aGUgdGVybXMgb2YKU2VjdGlvbnMgMSBhbmQgMiBhYm92ZSBw
-cm92aWRlZCB0aGF0IHlvdSBhbHNvIGRvIG9uZSBvZiB0aGUgZm9sbG93aW5nOgoKXGJlZ2lue2Vu
-dW1lcmF0ZX0KClxpdGVtCgpBY2NvbXBhbnkgaXQgd2l0aCB0aGUgY29tcGxldGUgY29ycmVzcG9u
-ZGluZyBtYWNoaW5lLXJlYWRhYmxlCnNvdXJjZSBjb2RlLCB3aGljaCBtdXN0IGJlIGRpc3RyaWJ1
-dGVkIHVuZGVyIHRoZSB0ZXJtcyBvZiBTZWN0aW9ucwoxIGFuZCAyIGFib3ZlIG9uIGEgbWVkaXVt
-IGN1c3RvbWFyaWx5IHVzZWQgZm9yIHNvZnR3YXJlIGludGVyY2hhbmdlOyBvciwKClxpdGVtCgpB
-Y2NvbXBhbnkgaXQgd2l0aCBhIHdyaXR0ZW4gb2ZmZXIsIHZhbGlkIGZvciBhdCBsZWFzdCB0aHJl
-ZQp5ZWFycywgdG8gZ2l2ZSBhbnkgdGhpcmQgcGFydHksIGZvciBhIGNoYXJnZSBubyBtb3JlIHRo
-YW4geW91cgpjb3N0IG9mIHBoeXNpY2FsbHkgcGVyZm9ybWluZyBzb3VyY2UgZGlzdHJpYnV0aW9u
-LCBhIGNvbXBsZXRlCm1hY2hpbmUtcmVhZGFibGUgY29weSBvZiB0aGUgY29ycmVzcG9uZGluZyBz
-b3VyY2UgY29kZSwgdG8gYmUKZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIHRlcm1zIG9mIFNlY3Rpb25z
-IDEgYW5kIDIgYWJvdmUgb24gYSBtZWRpdW0KY3VzdG9tYXJpbHkgdXNlZCBmb3Igc29mdHdhcmUg
-aW50ZXJjaGFuZ2U7IG9yLAoKXGl0ZW0KCkFjY29tcGFueSBpdCB3aXRoIHRoZSBpbmZvcm1hdGlv
-biB5b3UgcmVjZWl2ZWQgYXMgdG8gdGhlIG9mZmVyCnRvIGRpc3RyaWJ1dGUgY29ycmVzcG9uZGlu
-ZyBzb3VyY2UgY29kZS4gIChUaGlzIGFsdGVybmF0aXZlIGlzCmFsbG93ZWQgb25seSBmb3Igbm9u
-Y29tbWVyY2lhbCBkaXN0cmlidXRpb24gYW5kIG9ubHkgaWYgeW91CnJlY2VpdmVkIHRoZSBwcm9n
-cmFtIGluIG9iamVjdCBjb2RlIG9yIGV4ZWN1dGFibGUgZm9ybSB3aXRoIHN1Y2gKYW4gb2ZmZXIs
-IGluIGFjY29yZCB3aXRoIFN1YnNlY3Rpb24gYiBhYm92ZS4pCgpcZW5ke2VudW1lcmF0ZX0KCgpU
-aGUgc291cmNlIGNvZGUgZm9yIGEgd29yayBtZWFucyB0aGUgcHJlZmVycmVkIGZvcm0gb2YgdGhl
-IHdvcmsgZm9yCm1ha2luZyBtb2RpZmljYXRpb25zIHRvIGl0LiAgRm9yIGFuIGV4ZWN1dGFibGUg
-d29yaywgY29tcGxldGUgc291cmNlCmNvZGUgbWVhbnMgYWxsIHRoZSBzb3VyY2UgY29kZSBmb3Ig
-YWxsIG1vZHVsZXMgaXQgY29udGFpbnMsIHBsdXMgYW55CmFzc29jaWF0ZWQgaW50ZXJmYWNlIGRl
-ZmluaXRpb24gZmlsZXMsIHBsdXMgdGhlIHNjcmlwdHMgdXNlZCB0bwpjb250cm9sIGNvbXBpbGF0
-aW9uIGFuZCBpbnN0YWxsYXRpb24gb2YgdGhlIGV4ZWN1dGFibGUuICBIb3dldmVyLCBhcyBhCnNw
-ZWNpYWwgZXhjZXB0aW9uLCB0aGUgc291cmNlIGNvZGUgZGlzdHJpYnV0ZWQgbmVlZCBub3QgaW5j
-bHVkZQphbnl0aGluZyB0aGF0IGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIChpbiBlaXRoZXIgc291
-cmNlIG9yIGJpbmFyeQpmb3JtKSB3aXRoIHRoZSBtYWpvciBjb21wb25lbnRzIChjb21waWxlciwg
-a2VybmVsLCBhbmQgc28gb24pIG9mIHRoZQpvcGVyYXRpbmcgc3lzdGVtIG9uIHdoaWNoIHRoZSBl
-eGVjdXRhYmxlIHJ1bnMsIHVubGVzcyB0aGF0IGNvbXBvbmVudAppdHNlbGYgYWNjb21wYW5pZXMg
-dGhlIGV4ZWN1dGFibGUuCgpJZiBkaXN0cmlidXRpb24gb2YgZXhlY3V0YWJsZSBvciBvYmplY3Qg
-Y29kZSBpcyBtYWRlIGJ5IG9mZmVyaW5nCmFjY2VzcyB0byBjb3B5IGZyb20gYSBkZXNpZ25hdGVk
-IHBsYWNlLCB0aGVuIG9mZmVyaW5nIGVxdWl2YWxlbnQKYWNjZXNzIHRvIGNvcHkgdGhlIHNvdXJj
-ZSBjb2RlIGZyb20gdGhlIHNhbWUgcGxhY2UgY291bnRzIGFzCmRpc3RyaWJ1dGlvbiBvZiB0aGUg
-c291cmNlIGNvZGUsIGV2ZW4gdGhvdWdoIHRoaXJkIHBhcnRpZXMgYXJlIG5vdApjb21wZWxsZWQg
-dG8gY29weSB0aGUgc291cmNlIGFsb25nIHdpdGggdGhlIG9iamVjdCBjb2RlLgoKXGl0ZW0KWW91
-IG1heSBub3QgY29weSwgbW9kaWZ5LCBzdWJsaWNlbnNlLCBvciBkaXN0cmlidXRlIHRoZSBQcm9n
-cmFtCmV4Y2VwdCBhcyBleHByZXNzbHkgcHJvdmlkZWQgdW5kZXIgdGhpcyBMaWNlbnNlLiAgQW55
-IGF0dGVtcHQKb3RoZXJ3aXNlIHRvIGNvcHksIG1vZGlmeSwgc3VibGljZW5zZSBvciBkaXN0cmli
-dXRlIHRoZSBQcm9ncmFtIGlzCnZvaWQsIGFuZCB3aWxsIGF1dG9tYXRpY2FsbHkgdGVybWluYXRl
-IHlvdXIgcmlnaHRzIHVuZGVyIHRoaXMgTGljZW5zZS4KSG93ZXZlciwgcGFydGllcyB3aG8gaGF2
-ZSByZWNlaXZlZCBjb3BpZXMsIG9yIHJpZ2h0cywgZnJvbSB5b3UgdW5kZXIKdGhpcyBMaWNlbnNl
-IHdpbGwgbm90IGhhdmUgdGhlaXIgbGljZW5zZXMgdGVybWluYXRlZCBzbyBsb25nIGFzIHN1Y2gK
-cGFydGllcyByZW1haW4gaW4gZnVsbCBjb21wbGlhbmNlLgoKXGl0ZW0KWW91IGFyZSBub3QgcmVx
-dWlyZWQgdG8gYWNjZXB0IHRoaXMgTGljZW5zZSwgc2luY2UgeW91IGhhdmUgbm90CnNpZ25lZCBp
-dC4gIEhvd2V2ZXIsIG5vdGhpbmcgZWxzZSBncmFudHMgeW91IHBlcm1pc3Npb24gdG8gbW9kaWZ5
-IG9yCmRpc3RyaWJ1dGUgdGhlIFByb2dyYW0gb3IgaXRzIGRlcml2YXRpdmUgd29ya3MuICBUaGVz
-ZSBhY3Rpb25zIGFyZQpwcm9oaWJpdGVkIGJ5IGxhdyBpZiB5b3UgZG8gbm90IGFjY2VwdCB0aGlz
-IExpY2Vuc2UuICBUaGVyZWZvcmUsIGJ5Cm1vZGlmeWluZyBvciBkaXN0cmlidXRpbmcgdGhlIFBy
-b2dyYW0gKG9yIGFueSB3b3JrIGJhc2VkIG9uIHRoZQpQcm9ncmFtKSwgeW91IGluZGljYXRlIHlv
-dXIgYWNjZXB0YW5jZSBvZiB0aGlzIExpY2Vuc2UgdG8gZG8gc28sIGFuZAphbGwgaXRzIHRlcm1z
-IGFuZCBjb25kaXRpb25zIGZvciBjb3B5aW5nLCBkaXN0cmlidXRpbmcgb3IgbW9kaWZ5aW5nCnRo
-ZSBQcm9ncmFtIG9yIHdvcmtzIGJhc2VkIG9uIGl0LgoKXGl0ZW0KRWFjaCB0aW1lIHlvdSByZWRp
-c3RyaWJ1dGUgdGhlIFByb2dyYW0gKG9yIGFueSB3b3JrIGJhc2VkIG9uIHRoZQpQcm9ncmFtKSwg
-dGhlIHJlY2lwaWVudCBhdXRvbWF0aWNhbGx5IHJlY2VpdmVzIGEgbGljZW5zZSBmcm9tIHRoZQpv
-cmlnaW5hbCBsaWNlbnNvciB0byBjb3B5LCBkaXN0cmlidXRlIG9yIG1vZGlmeSB0aGUgUHJvZ3Jh
-bSBzdWJqZWN0IHRvCnRoZXNlIHRlcm1zIGFuZCBjb25kaXRpb25zLiAgWW91IG1heSBub3QgaW1w
-b3NlIGFueSBmdXJ0aGVyCnJlc3RyaWN0aW9ucyBvbiB0aGUgcmVjaXBpZW50cycgZXhlcmNpc2Ug
-b2YgdGhlIHJpZ2h0cyBncmFudGVkIGhlcmVpbi4KWW91IGFyZSBub3QgcmVzcG9uc2libGUgZm9y
-IGVuZm9yY2luZyBjb21wbGlhbmNlIGJ5IHRoaXJkIHBhcnRpZXMgdG8KdGhpcyBMaWNlbnNlLgoK
-XGl0ZW0KSWYsIGFzIGEgY29uc2VxdWVuY2Ugb2YgYSBjb3VydCBqdWRnbWVudCBvciBhbGxlZ2F0
-aW9uIG9mIHBhdGVudAppbmZyaW5nZW1lbnQgb3IgZm9yIGFueSBvdGhlciByZWFzb24gKG5vdCBs
-aW1pdGVkIHRvIHBhdGVudCBpc3N1ZXMpLApjb25kaXRpb25zIGFyZSBpbXBvc2VkIG9uIHlvdSAo
-d2hldGhlciBieSBjb3VydCBvcmRlciwgYWdyZWVtZW50IG9yCm90aGVyd2lzZSkgdGhhdCBjb250
-cmFkaWN0IHRoZSBjb25kaXRpb25zIG9mIHRoaXMgTGljZW5zZSwgdGhleSBkbyBub3QKZXhjdXNl
-IHlvdSBmcm9tIHRoZSBjb25kaXRpb25zIG9mIHRoaXMgTGljZW5zZS4gIElmIHlvdSBjYW5ub3QK
-ZGlzdHJpYnV0ZSBzbyBhcyB0byBzYXRpc2Z5IHNpbXVsdGFuZW91c2x5IHlvdXIgb2JsaWdhdGlv
-bnMgdW5kZXIgdGhpcwpMaWNlbnNlIGFuZCBhbnkgb3RoZXIgcGVydGluZW50IG9ibGlnYXRpb25z
-LCB0aGVuIGFzIGEgY29uc2VxdWVuY2UgeW91Cm1heSBub3QgZGlzdHJpYnV0ZSB0aGUgUHJvZ3Jh
-bSBhdCBhbGwuICBGb3IgZXhhbXBsZSwgaWYgYSBwYXRlbnQKbGljZW5zZSB3b3VsZCBub3QgcGVy
-bWl0IHJveWFsdHktZnJlZSByZWRpc3RyaWJ1dGlvbiBvZiB0aGUgUHJvZ3JhbSBieQphbGwgdGhv
-c2Ugd2hvIHJlY2VpdmUgY29waWVzIGRpcmVjdGx5IG9yIGluZGlyZWN0bHkgdGhyb3VnaCB5b3Us
-IHRoZW4KdGhlIG9ubHkgd2F5IHlvdSBjb3VsZCBzYXRpc2Z5IGJvdGggaXQgYW5kIHRoaXMgTGlj
-ZW5zZSB3b3VsZCBiZSB0bwpyZWZyYWluIGVudGlyZWx5IGZyb20gZGlzdHJpYnV0aW9uIG9mIHRo
-ZSBQcm9ncmFtLgoKSWYgYW55IHBvcnRpb24gb2YgdGhpcyBzZWN0aW9uIGlzIGhlbGQgaW52YWxp
-ZCBvciB1bmVuZm9yY2VhYmxlIHVuZGVyCmFueSBwYXJ0aWN1bGFyIGNpcmN1bXN0YW5jZSwgdGhl
-IGJhbGFuY2Ugb2YgdGhlIHNlY3Rpb24gaXMgaW50ZW5kZWQgdG8KYXBwbHkgYW5kIHRoZSBzZWN0
-aW9uIGFzIGEgd2hvbGUgaXMgaW50ZW5kZWQgdG8gYXBwbHkgaW4gb3RoZXIKY2lyY3Vtc3RhbmNl
-cy4KCkl0IGlzIG5vdCB0aGUgcHVycG9zZSBvZiB0aGlzIHNlY3Rpb24gdG8gaW5kdWNlIHlvdSB0
-byBpbmZyaW5nZSBhbnkKcGF0ZW50cyBvciBvdGhlciBwcm9wZXJ0eSByaWdodCBjbGFpbXMgb3Ig
-dG8gY29udGVzdCB2YWxpZGl0eSBvZiBhbnkKc3VjaCBjbGFpbXM7IHRoaXMgc2VjdGlvbiBoYXMg
-dGhlIHNvbGUgcHVycG9zZSBvZiBwcm90ZWN0aW5nIHRoZQppbnRlZ3JpdHkgb2YgdGhlIGZyZWUg
-c29mdHdhcmUgZGlzdHJpYnV0aW9uIHN5c3RlbSwgd2hpY2ggaXMKaW1wbGVtZW50ZWQgYnkgcHVi
-bGljIGxpY2Vuc2UgcHJhY3RpY2VzLiAgTWFueSBwZW9wbGUgaGF2ZSBtYWRlCmdlbmVyb3VzIGNv
-bnRyaWJ1dGlvbnMgdG8gdGhlIHdpZGUgcmFuZ2Ugb2Ygc29mdHdhcmUgZGlzdHJpYnV0ZWQKdGhy
-b3VnaCB0aGF0IHN5c3RlbSBpbiByZWxpYW5jZSBvbiBjb25zaXN0ZW50IGFwcGxpY2F0aW9uIG9m
-IHRoYXQKc3lzdGVtOyBpdCBpcyB1cCB0byB0aGUgYXV0aG9yL2Rvbm9yIHRvIGRlY2lkZSBpZiBo
-ZSBvciBzaGUgaXMgd2lsbGluZwp0byBkaXN0cmlidXRlIHNvZnR3YXJlIHRocm91Z2ggYW55IG90
-aGVyIHN5c3RlbSBhbmQgYSBsaWNlbnNlZSBjYW5ub3QKaW1wb3NlIHRoYXQgY2hvaWNlLgoKVGhp
-cyBzZWN0aW9uIGlzIGludGVuZGVkIHRvIG1ha2UgdGhvcm91Z2hseSBjbGVhciB3aGF0IGlzIGJl
-bGlldmVkIHRvCmJlIGEgY29uc2VxdWVuY2Ugb2YgdGhlIHJlc3Qgb2YgdGhpcyBMaWNlbnNlLgoK
-XGl0ZW0KSWYgdGhlIGRpc3RyaWJ1dGlvbiBhbmQvb3IgdXNlIG9mIHRoZSBQcm9ncmFtIGlzIHJl
-c3RyaWN0ZWQgaW4KY2VydGFpbiBjb3VudHJpZXMgZWl0aGVyIGJ5IHBhdGVudHMgb3IgYnkgY29w
-eXJpZ2h0ZWQgaW50ZXJmYWNlcywgdGhlCm9yaWdpbmFsIGNvcHlyaWdodCBob2xkZXIgd2hvIHBs
-YWNlcyB0aGUgUHJvZ3JhbSB1bmRlciB0aGlzIExpY2Vuc2UKbWF5IGFkZCBhbiBleHBsaWNpdCBn
-ZW9ncmFwaGljYWwgZGlzdHJpYnV0aW9uIGxpbWl0YXRpb24gZXhjbHVkaW5nCnRob3NlIGNvdW50
-cmllcywgc28gdGhhdCBkaXN0cmlidXRpb24gaXMgcGVybWl0dGVkIG9ubHkgaW4gb3IgYW1vbmcK
-Y291bnRyaWVzIG5vdCB0aHVzIGV4Y2x1ZGVkLiAgSW4gc3VjaCBjYXNlLCB0aGlzIExpY2Vuc2Ug
-aW5jb3Jwb3JhdGVzCnRoZSBsaW1pdGF0aW9uIGFzIGlmIHdyaXR0ZW4gaW4gdGhlIGJvZHkgb2Yg
-dGhpcyBMaWNlbnNlLgoKXGl0ZW0KVGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiBtYXkgcHVi
-bGlzaCByZXZpc2VkIGFuZC9vciBuZXcgdmVyc2lvbnMKb2YgdGhlIEdlbmVyYWwgUHVibGljIExp
-Y2Vuc2UgZnJvbSB0aW1lIHRvIHRpbWUuICBTdWNoIG5ldyB2ZXJzaW9ucyB3aWxsCmJlIHNpbWls
-YXIgaW4gc3Bpcml0IHRvIHRoZSBwcmVzZW50IHZlcnNpb24sIGJ1dCBtYXkgZGlmZmVyIGluIGRl
-dGFpbCB0bwphZGRyZXNzIG5ldyBwcm9ibGVtcyBvciBjb25jZXJucy4KCkVhY2ggdmVyc2lvbiBp
-cyBnaXZlbiBhIGRpc3Rpbmd1aXNoaW5nIHZlcnNpb24gbnVtYmVyLiAgSWYgdGhlIFByb2dyYW0K
-c3BlY2lmaWVzIGEgdmVyc2lvbiBudW1iZXIgb2YgdGhpcyBMaWNlbnNlIHdoaWNoIGFwcGxpZXMg
-dG8gaXQgYW5kIGBgYW55CmxhdGVyIHZlcnNpb24nJywgeW91IGhhdmUgdGhlIG9wdGlvbiBvZiBm
-b2xsb3dpbmcgdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zCmVpdGhlciBvZiB0aGF0IHZlcnNpb24g
-b3Igb2YgYW55IGxhdGVyIHZlcnNpb24gcHVibGlzaGVkIGJ5IHRoZSBGcmVlClNvZnR3YXJlIEZv
-dW5kYXRpb24uICBJZiB0aGUgUHJvZ3JhbSBkb2VzIG5vdCBzcGVjaWZ5IGEgdmVyc2lvbiBudW1i
-ZXIgb2YKdGhpcyBMaWNlbnNlLCB5b3UgbWF5IGNob29zZSBhbnkgdmVyc2lvbiBldmVyIHB1Ymxp
-c2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZQpGb3VuZGF0aW9uLgoKXGl0ZW0KSWYgeW91IHdpc2gg
-dG8gaW5jb3Jwb3JhdGUgcGFydHMgb2YgdGhlIFByb2dyYW0gaW50byBvdGhlciBmcmVlCnByb2dy
-YW1zIHdob3NlIGRpc3RyaWJ1dGlvbiBjb25kaXRpb25zIGFyZSBkaWZmZXJlbnQsIHdyaXRlIHRv
-IHRoZSBhdXRob3IKdG8gYXNrIGZvciBwZXJtaXNzaW9uLiAgRm9yIHNvZnR3YXJlIHdoaWNoIGlz
-IGNvcHlyaWdodGVkIGJ5IHRoZSBGcmVlClNvZnR3YXJlIEZvdW5kYXRpb24sIHdyaXRlIHRvIHRo
-ZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IHdlIHNvbWV0aW1lcwptYWtlIGV4Y2VwdGlvbnMg
-Zm9yIHRoaXMuICBPdXIgZGVjaXNpb24gd2lsbCBiZSBndWlkZWQgYnkgdGhlIHR3byBnb2Fscwpv
-ZiBwcmVzZXJ2aW5nIHRoZSBmcmVlIHN0YXR1cyBvZiBhbGwgZGVyaXZhdGl2ZXMgb2Ygb3VyIGZy
-ZWUgc29mdHdhcmUgYW5kCm9mIHByb21vdGluZyB0aGUgc2hhcmluZyBhbmQgcmV1c2Ugb2Ygc29m
-dHdhcmUgZ2VuZXJhbGx5LgoKXGJlZ2lue2NlbnRlcn0Ke1xMYXJnZVxzYwpObyBXYXJyYW50eQp9
-ClxlbmR7Y2VudGVyfQoKXGl0ZW0Ke1xzYyBCZWNhdXNlIHRoZSBwcm9ncmFtIGlzIGxpY2Vuc2Vk
-IGZyZWUgb2YgY2hhcmdlLCB0aGVyZSBpcyBubyB3YXJyYW50eQpmb3IgdGhlIHByb2dyYW0sIHRv
-IHRoZSBleHRlbnQgcGVybWl0dGVkIGJ5IGFwcGxpY2FibGUgbGF3LiAgRXhjZXB0IHdoZW4Kb3Ro
-ZXJ3aXNlIHN0YXRlZCBpbiB3cml0aW5nIHRoZSBjb3B5cmlnaHQgaG9sZGVycyBhbmQvb3Igb3Ro
-ZXIgcGFydGllcwpwcm92aWRlIHRoZSBwcm9ncmFtIGBgYXMgaXMnJyB3aXRob3V0IHdhcnJhbnR5
-IG9mIGFueSBraW5kLCBlaXRoZXIgZXhwcmVzc2VkCm9yIGltcGxpZWQsIGluY2x1ZGluZywgYnV0
-IG5vdCBsaW1pdGVkIHRvLCB0aGUgaW1wbGllZCB3YXJyYW50aWVzIG9mCm1lcmNoYW50YWJpbGl0
-eSBhbmQgZml0bmVzcyBmb3IgYSBwYXJ0aWN1bGFyIHB1cnBvc2UuICBUaGUgZW50aXJlIHJpc2sg
-YXMKdG8gdGhlIHF1YWxpdHkgYW5kIHBlcmZvcm1hbmNlIG9mIHRoZSBwcm9ncmFtIGlzIHdpdGgg
-eW91LiAgU2hvdWxkIHRoZQpwcm9ncmFtIHByb3ZlIGRlZmVjdGl2ZSwgeW91IGFzc3VtZSB0aGUg
-Y29zdCBvZiBhbGwgbmVjZXNzYXJ5IHNlcnZpY2luZywKcmVwYWlyIG9yIGNvcnJlY3Rpb24ufQoK
-XGl0ZW0Ke1xzYyBJbiBubyBldmVudCB1bmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcg
-b3IgYWdyZWVkIHRvIGluIHdyaXRpbmcKd2lsbCBhbnkgY29weXJpZ2h0IGhvbGRlciwgb3IgYW55
-IG90aGVyIHBhcnR5IHdobyBtYXkgbW9kaWZ5IGFuZC9vcgpyZWRpc3RyaWJ1dGUgdGhlIHByb2dy
-YW0gYXMgcGVybWl0dGVkIGFib3ZlLCBiZSBsaWFibGUgdG8geW91IGZvciBkYW1hZ2VzLAppbmNs
-dWRpbmcgYW55IGdlbmVyYWwsIHNwZWNpYWwsIGluY2lkZW50YWwgb3IgY29uc2VxdWVudGlhbCBk
-YW1hZ2VzIGFyaXNpbmcKb3V0IG9mIHRoZSB1c2Ugb3IgaW5hYmlsaXR5IHRvIHVzZSB0aGUgcHJv
-Z3JhbSAoaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZAp0byBsb3NzIG9mIGRhdGEgb3IgZGF0YSBi
-ZWluZyByZW5kZXJlZCBpbmFjY3VyYXRlIG9yIGxvc3NlcyBzdXN0YWluZWQgYnkKeW91IG9yIHRo
-aXJkIHBhcnRpZXMgb3IgYSBmYWlsdXJlIG9mIHRoZSBwcm9ncmFtIHRvIG9wZXJhdGUgd2l0aCBh
-bnkgb3RoZXIKcHJvZ3JhbXMpLCBldmVuIGlmIHN1Y2ggaG9sZGVyIG9yIG90aGVyIHBhcnR5IGhh
-cyBiZWVuIGFkdmlzZWQgb2YgdGhlCnBvc3NpYmlsaXR5IG9mIHN1Y2ggZGFtYWdlcy59CgpcZW5k
-e2VudW1lcmF0ZX0KCgpcYmVnaW57Y2VudGVyfQp7XExhcmdlXHNjIEVuZCBvZiBUZXJtcyBhbmQg
-Q29uZGl0aW9uc30KXGVuZHtjZW50ZXJ9CgoKXHBhZ2VicmVha1syXQoKXHNlY3Rpb24qe0FwcGVu
-ZGl4OiBIb3cgdG8gQXBwbHkgVGhlc2UgVGVybXMgdG8gWW91ciBOZXcgUHJvZ3JhbXN9CgpJZiB5
-b3UgZGV2ZWxvcCBhIG5ldyBwcm9ncmFtLCBhbmQgeW91IHdhbnQgaXQgdG8gYmUgb2YgdGhlIGdy
-ZWF0ZXN0CnBvc3NpYmxlIHVzZSB0byB0aGUgcHVibGljLCB0aGUgYmVzdCB3YXkgdG8gYWNoaWV2
-ZSB0aGlzIGlzIHRvIG1ha2UgaXQKZnJlZSBzb2Z0d2FyZSB3aGljaCBldmVyeW9uZSBjYW4gcmVk
-aXN0cmlidXRlIGFuZCBjaGFuZ2UgdW5kZXIgdGhlc2UKdGVybXMuCgogIFRvIGRvIHNvLCBhdHRh
-Y2ggdGhlIGZvbGxvd2luZyBub3RpY2VzIHRvIHRoZSBwcm9ncmFtLiAgSXQgaXMgc2FmZXN0IHRv
-CiAgYXR0YWNoIHRoZW0gdG8gdGhlIHN0YXJ0IG9mIGVhY2ggc291cmNlIGZpbGUgdG8gbW9zdCBl
-ZmZlY3RpdmVseSBjb252ZXkKICB0aGUgZXhjbHVzaW9uIG9mIHdhcnJhbnR5OyBhbmQgZWFjaCBm
-aWxlIHNob3VsZCBoYXZlIGF0IGxlYXN0IHRoZQogIGBgY29weXJpZ2h0JycgbGluZSBhbmQgYSBw
-b2ludGVyIHRvIHdoZXJlIHRoZSBmdWxsIG5vdGljZSBpcyBmb3VuZC4KClxiZWdpbntxdW90ZX0K
-b25lIGxpbmUgdG8gZ2l2ZSB0aGUgcHJvZ3JhbSdzIG5hbWUgYW5kIGEgYnJpZWYgaWRlYSBvZiB3
-aGF0IGl0IGRvZXMuIFxcCkNvcHlyaWdodCAoQykgeXl5eSAgbmFtZSBvZiBhdXRob3IgXFwKClRo
-aXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQv
-b3IgbW9kaWZ5Cml0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExp
-Y2Vuc2UgYXMgcHVibGlzaGVkIGJ5CnRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhl
-ciB2ZXJzaW9uIDIgb2YgdGhlIExpY2Vuc2UsIG9yCihhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVy
-IHZlcnNpb24uCgpUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBp
-dCB3aWxsIGJlIHVzZWZ1bCwKYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4g
-dGhlIGltcGxpZWQgd2FycmFudHkgb2YKTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEg
-UEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZQpHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBm
-b3IgbW9yZSBkZXRhaWxzLgoKWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUg
-R05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UKYWxvbmcgd2l0aCB0aGlzIHByb2dyYW07IGlmIG5v
-dCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUKRm91bmRhdGlvbiwgSW5jLiwgNTkgVGVtcGxl
-IFBsYWNlIC0gU3VpdGUgMzMwLCBCb3N0b24sIE1BICAwMjExMS0xMzA3LCBVU0EuClxlbmR7cXVv
-dGV9CgpBbHNvIGFkZCBpbmZvcm1hdGlvbiBvbiBob3cgdG8gY29udGFjdCB5b3UgYnkgZWxlY3Ry
-b25pYyBhbmQgcGFwZXIgbWFpbC4KCklmIHRoZSBwcm9ncmFtIGlzIGludGVyYWN0aXZlLCBtYWtl
-IGl0IG91dHB1dCBhIHNob3J0IG5vdGljZSBsaWtlIHRoaXMKd2hlbiBpdCBzdGFydHMgaW4gYW4g
-aW50ZXJhY3RpdmUgbW9kZToKClxiZWdpbntxdW90ZX0KR25vbW92aXNpb24gdmVyc2lvbiA2OSwg
-Q29weXJpZ2h0IChDKSB5eXl5ICBuYW1lIG9mIGF1dGhvciBcXApHbm9tb3Zpc2lvbiBjb21lcyB3
-aXRoIEFCU09MVVRFTFkgTk8gV0FSUkFOVFk7IGZvciBkZXRhaWxzIHR5cGUgYHNob3cgdycuIFxc
-ClRoaXMgaXMgZnJlZSBzb2Z0d2FyZSwgYW5kIHlvdSBhcmUgd2VsY29tZSB0byByZWRpc3RyaWJ1
-dGUgaXQKdW5kZXIgY2VydGFpbiBjb25kaXRpb25zOyB0eXBlIGBzaG93IGMnIGZvciBkZXRhaWxz
-LgpcZW5ke3F1b3RlfQoKClRoZSBoeXBvdGhldGljYWwgY29tbWFuZHMge1x0dCBzaG93IHd9IGFu
-ZCB7XHR0IHNob3cgY30gc2hvdWxkIHNob3cgdGhlCmFwcHJvcHJpYXRlIHBhcnRzIG9mIHRoZSBH
-ZW5lcmFsIFB1YmxpYyBMaWNlbnNlLiAgT2YgY291cnNlLCB0aGUgY29tbWFuZHMKeW91IHVzZSBt
-YXkgYmUgY2FsbGVkIHNvbWV0aGluZyBvdGhlciB0aGFuIHtcdHQgc2hvdyB3fSBhbmQge1x0dCBz
-aG93IGN9Owp0aGV5IGNvdWxkIGV2ZW4gYmUgbW91c2UtY2xpY2tzIG9yIG1lbnUgaXRlbXMtLS13
-aGF0ZXZlciBzdWl0cyB5b3VyCnByb2dyYW0uCgpZb3Ugc2hvdWxkIGFsc28gZ2V0IHlvdXIgZW1w
-bG95ZXIgKGlmIHlvdSB3b3JrIGFzIGEgcHJvZ3JhbW1lcikgb3IgeW91cgpzY2hvb2wsIGlmIGFu
-eSwgdG8gc2lnbiBhIGBgY29weXJpZ2h0IGRpc2NsYWltZXInJyBmb3IgdGhlIHByb2dyYW0sIGlm
-Cm5lY2Vzc2FyeS4gIEhlcmUgaXMgYSBzYW1wbGU7IGFsdGVyIHRoZSBuYW1lczoKClxiZWdpbntx
-dW90ZX0KWW95b2R5bmUsIEluYy4sIGhlcmVieSBkaXNjbGFpbXMgYWxsIGNvcHlyaWdodCBpbnRl
-cmVzdCBpbiB0aGUgcHJvZ3JhbSBcXApgR25vbW92aXNpb24nICh3aGljaCBtYWtlcyBwYXNzZXMg
-YXQgY29tcGlsZXJzKSB3cml0dGVuIGJ5IEphbWVzIEhhY2tlci4gXFwKCnNpZ25hdHVyZSBvZiBU
-eSBDb29uLCAxIEFwcmlsIDE5ODkgXFwKVHkgQ29vbiwgUHJlc2lkZW50IG9mIFZpY2UKXGVuZHtx
-dW90ZX0KCgpUaGlzIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZG9lcyBub3QgcGVybWl0IGluY29y
-cG9yYXRpbmcgeW91ciBwcm9ncmFtCmludG8gcHJvcHJpZXRhcnkgcHJvZ3JhbXMuICBJZiB5b3Vy
-IHByb2dyYW0gaXMgYSBzdWJyb3V0aW5lIGxpYnJhcnksIHlvdQptYXkgY29uc2lkZXIgaXQgbW9y
-ZSB1c2VmdWwgdG8gcGVybWl0IGxpbmtpbmcgcHJvcHJpZXRhcnkgYXBwbGljYXRpb25zCndpdGgg
-dGhlIGxpYnJhcnkuICBJZiB0aGlzIGlzIHdoYXQgeW91IHdhbnQgdG8gZG8sIHVzZSB0aGUgR05V
-IExpYnJhcnkKR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBpbnN0ZWFkIG9mIHRoaXMgTGljZW5zZS4K
-Cgo=
-" ++ Glurf ++ lists:reverse(Glurf++"kalle").
diff --git a/lib/compiler/test/compilation_SUITE_data/nested_tuples_in_case_expr.erl b/lib/compiler/test/compilation_SUITE_data/nested_tuples_in_case_expr.erl
deleted file mode 100644
index 76401cea97..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/nested_tuples_in_case_expr.erl
+++ /dev/null
@@ -1,37 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2009. 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(nested_tuples_in_case_expr).
--export([nested_tuples_in_case_expr/0,t/2]).
-
-nested_tuples_in_case_expr() ->
- ok.
-
-t(A, B) ->
- case {{element(1, A),element(2, B)},{element(2, A),element(2, B)}} of
- {Same,Same} -> ok;
- {{0,1},{up,X}} -> bar(X);
- {_,{X,_}} -> bar(X)
- end.
-
-bar(X) -> X.
-
-
-
-
diff --git a/lib/compiler/test/compilation_SUITE_data/opt_crash.erl b/lib/compiler/test/compilation_SUITE_data/opt_crash.erl
index 9a88df33af..f1607cca68 100644
--- a/lib/compiler/test/compilation_SUITE_data/opt_crash.erl
+++ b/lib/compiler/test/compilation_SUITE_data/opt_crash.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/other/vsn_1.erl b/lib/compiler/test/compilation_SUITE_data/other/vsn_1.erl
index 7acdb047fb..ea9b32bcbb 100644
--- a/lib/compiler/test/compilation_SUITE_data/other/vsn_1.erl
+++ b/lib/compiler/test/compilation_SUITE_data/other/vsn_1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/other/vsn_3.erl b/lib/compiler/test/compilation_SUITE_data/other/vsn_3.erl
index c8c9975d9b..9815138886 100644
--- a/lib/compiler/test/compilation_SUITE_data/other/vsn_3.erl
+++ b/lib/compiler/test/compilation_SUITE_data/other/vsn_3.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_2173.erl b/lib/compiler/test/compilation_SUITE_data/otp_2173.erl
deleted file mode 100644
index 4155e2d1ff..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/otp_2173.erl
+++ /dev/null
@@ -1,32 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. 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(otp_2173).
--compile(export_all).
-
--record(t, {a = fun(X) -> X*X end}).
-
-otp_2173() ->
- ok.
-
-t() ->
- #t{}.
-
-
-
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_2330.erl b/lib/compiler/test/compilation_SUITE_data/otp_2330.erl
index c9ba7c7ba5..92e93be1c1 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_2330.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_2330.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_2380.erl b/lib/compiler/test/compilation_SUITE_data/otp_2380.erl
index dbf44e5fb8..b7b2b04793 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_2380.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_2380.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_4790.erl b/lib/compiler/test/compilation_SUITE_data/otp_4790.erl
index 3a32372cc9..08769c5303 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_4790.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_4790.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_5076.erl b/lib/compiler/test/compilation_SUITE_data/otp_5076.erl
deleted file mode 100644
index 7d96b5c734..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/otp_5076.erl
+++ /dev/null
@@ -1,28 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. 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(otp_5076).
--export([?MODULE/0]).
-
-?MODULE() ->
- [] = t(),
- ok.
-
-t() ->
- [3 || {3=4} <- []].
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_5092.erl b/lib/compiler/test/compilation_SUITE_data/otp_5092.erl
deleted file mode 100644
index b675e09af6..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/otp_5092.erl
+++ /dev/null
@@ -1,40 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. 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(otp_5092).
--export([?MODULE/0]).
-
-?MODULE() ->
- [] = t(),
- [] = t2(),
- [t] = t4(),
- [] = t5(),
- ok.
-
-t() ->
- [t || {C=D}={_,_} <- []].
-
-t2() ->
- [X || {X,{Y}={X,X}} <- []].
-
-t4() ->
- [t || "a"++"b" = "ab" <- ["ab"]].
-
-t5() ->
- [{X,Y} || {X} <- [], begin Y = X, Y =:= X end].
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_5151.erl b/lib/compiler/test/compilation_SUITE_data/otp_5151.erl
index c40de9e508..02a19ebd3d 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_5151.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_5151.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_5235.erl b/lib/compiler/test/compilation_SUITE_data/otp_5235.erl
index 69a0a476fb..e0f77c73f6 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_5235.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_5235.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_5244.erl b/lib/compiler/test/compilation_SUITE_data/otp_5244.erl
deleted file mode 100644
index 0fc32ddd36..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/otp_5244.erl
+++ /dev/null
@@ -1,48 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. 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(otp_5244).
--export([?MODULE/0]).
-
-?MODULE() ->
- L = [{stretch,0,0},
- {bad,[]},
- {bad,atom},
- {bad,0},
- {bad,16#AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA},
- {bad,16#555555555555555555555555555555555555555555555555555}],
- remove_failure(L, unit, 0).
-
-remove_failure([], _Unit, _MaxFailure) ->
- ok;
-remove_failure([{bad,Bad}|_], _Unit, _MaxFailure) ->
- Bad;
-remove_failure([{stretch,_,Mi}=Stretch | Specs], Unit, _MaxFailure) ->
- {MinMax,NewMaxFailure} = max_failure(),
- case {MinMax,remove_failure(Specs, Unit, NewMaxFailure)} of
- {min,{NewMaxFailure,Rest}} ->
- {done,[{fixed,Mi} | Rest]};
- {min,_} when Specs =/= [] ->
- remove_failure([Stretch|tl(Specs)], Unit, NewMaxFailure);
- {min,_} ->
- ok
- end.
-
-max_failure() ->
- {min,1}.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_5404.erl b/lib/compiler/test/compilation_SUITE_data/otp_5404.erl
index 66256fe33b..393c32aa00 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_5404.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_5404.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_5436.erl b/lib/compiler/test/compilation_SUITE_data/otp_5436.erl
index 1ae564eed0..842d46e93e 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_5436.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_5436.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_5481.erl b/lib/compiler/test/compilation_SUITE_data/otp_5481.erl
index 068845ac98..881d2cd239 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_5481.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_5481.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_5553.erl b/lib/compiler/test/compilation_SUITE_data/otp_5553.erl
index fb654dca8a..fd7757ac1e 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_5553.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_5553.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_5632.erl b/lib/compiler/test/compilation_SUITE_data/otp_5632.erl
index 229b5197bc..aaf6814f4e 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_5632.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_5632.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_5714.erl b/lib/compiler/test/compilation_SUITE_data/otp_5714.erl
index d90f937385..b65663f063 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_5714.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_5714.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_5872.erl b/lib/compiler/test/compilation_SUITE_data/otp_5872.erl
index 00d210c4c8..b9b9677a14 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_5872.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_5872.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_6121.erl b/lib/compiler/test/compilation_SUITE_data/otp_6121.erl
index 898e6304d6..f2bc9b3ee8 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_6121.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_6121.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_6121a.erl b/lib/compiler/test/compilation_SUITE_data/otp_6121a.erl
deleted file mode 100644
index fd0a25c779..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/otp_6121a.erl
+++ /dev/null
@@ -1,33 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2006-2009. 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(otp_6121a).
--export([?MODULE/0]).
-
-%% Thanks to Martin Bjorklund.
-
-?MODULE() ->
- G = fun() -> ok end,
- try
- fun() -> ok end
- after
- fun({A, B}) -> A + B end
- end,
- ok.
-
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_6121b.erl b/lib/compiler/test/compilation_SUITE_data/otp_6121b.erl
deleted file mode 100644
index 0c6b511bec..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/otp_6121b.erl
+++ /dev/null
@@ -1,34 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2006-2009. 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(otp_6121b).
--export([?MODULE/0]).
-
-%% Thanks to Tim Rath.
-
-?MODULE() ->
- A = {6},
- try
- io:fwrite("")
- after
- fun () ->
- fun () -> {B} = A end
- end
- end.
-
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_7202.erl b/lib/compiler/test/compilation_SUITE_data/otp_7202.erl
index 4437c484b4..4d86763b52 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_7202.erl
+++ b/lib/compiler/test/compilation_SUITE_data/otp_7202.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/pattern_expr.erl b/lib/compiler/test/compilation_SUITE_data/pattern_expr.erl
deleted file mode 100644
index da9c3c0a9a..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/pattern_expr.erl
+++ /dev/null
@@ -1,31 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. 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(pattern_expr).
-
--export(pattern_expr/0).
-
-pattern_expr() ->
- f().
-
-f() ->
- case 4 of
- 2+2 ->
- ok
- end.
diff --git a/lib/compiler/test/compilation_SUITE_data/trycatch_4.erl b/lib/compiler/test/compilation_SUITE_data/trycatch_4.erl
deleted file mode 100644
index e6f87bf01b..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/trycatch_4.erl
+++ /dev/null
@@ -1,51 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2009. 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(trycatch_4).
--export([trycatch_4/0]).
--record(state, {foo}).
-
-trycatch_4() ->
- handle_info({foo}, #state{}),
- ok.
-
-handle_info({_}, State) ->
- foo(),
- State#state{foo = bar},
- case ok of
- _ ->
- case catch foo() of
- ok ->
- {stop, State}
- end
- end;
-handle_info(_, State) ->
- (catch begin
- foo(),
- State#state{foo = bar}
- end),
- case ok of
- _ ->
- case catch foo() of
- ok ->
- {stop, State}
- end
- end.
-
-foo() -> ok.
diff --git a/lib/compiler/test/compilation_SUITE_data/vsn_1.erl b/lib/compiler/test/compilation_SUITE_data/vsn_1.erl
index c3ce2f0445..fed91a25c6 100644
--- a/lib/compiler/test/compilation_SUITE_data/vsn_1.erl
+++ b/lib/compiler/test/compilation_SUITE_data/vsn_1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/vsn_2.erl b/lib/compiler/test/compilation_SUITE_data/vsn_2.erl
index ced2d7ca0b..670b3b34ed 100644
--- a/lib/compiler/test/compilation_SUITE_data/vsn_2.erl
+++ b/lib/compiler/test/compilation_SUITE_data/vsn_2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE_data/vsn_3.erl b/lib/compiler/test/compilation_SUITE_data/vsn_3.erl
index 8312668d27..8fcd596636 100644
--- a/lib/compiler/test/compilation_SUITE_data/vsn_3.erl
+++ b/lib/compiler/test/compilation_SUITE_data/vsn_3.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index cbdd9ce8cd..5e35dc1d02 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. 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.
@@ -21,22 +21,24 @@
%% Tests compile:file/1 and compile:file/2 with various options.
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
+-include_lib("stdlib/include/erl_compile.hrl").
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
app_test/1,appup_test/1,
+ debug_info/4, custom_debug_info/1,
file_1/1, forms_2/1, module_mismatch/1, big_file/1, outdir/1,
binary/1, makedep/1, cond_and_ifdef/1, listings/1, listings_big/1,
- other_output/1, encrypted_abstr/1,
- bad_record_use1/1, bad_record_use2/1, strict_record/1,
- missing_testheap/1, cover/1, env/1, core/1, asm/1,
+ other_output/1, kernel_listing/1, encrypted_abstr/1,
+ strict_record/1, utf8_atoms/1, utf8_functions/1, extra_chunks/1,
+ cover/1, env/1, core_pp/1,
+ core_roundtrip/1, asm/1, optimized_guards/1,
sys_pre_attributes/1, dialyzer/1,
- warnings/1
+ warnings/1, pre_load_check/1, env_compiler_options/1,
+ bc_options/1
]).
--export([init/3]).
-
suite() -> [{ct_hooks,[ts_install_cth]}].
%% To cover the stripping of 'type' and 'spec' in beam_asm.
@@ -47,14 +49,14 @@ all() ->
test_lib:recompile(?MODULE),
[app_test, appup_test, file_1, forms_2, module_mismatch, big_file, outdir,
binary, makedep, cond_and_ifdef, listings, listings_big,
- other_output, encrypted_abstr,
- {group, bad_record_use}, strict_record,
- missing_testheap, cover, env, core, asm,
- sys_pre_attributes, dialyzer, warnings].
+ other_output, kernel_listing, encrypted_abstr,
+ strict_record, utf8_atoms, utf8_functions, extra_chunks,
+ cover, env, core_pp, core_roundtrip, asm, optimized_guards,
+ sys_pre_attributes, dialyzer, warnings, pre_load_check,
+ env_compiler_options, custom_debug_info, bc_options].
groups() ->
- [{bad_record_use, [],
- [bad_record_use1, bad_record_use2]}].
+ [].
init_per_suite(Config) ->
Config.
@@ -72,71 +74,130 @@ end_per_group(_GroupName, Config) ->
%% Test that the Application file has no `basic' errors.";
app_test(Config) when is_list(Config) ->
- ?line ?t:app_test(compiler).
+ test_server:app_test(compiler).
%% Test that the Application upgrade file has no `basic' errors.";
appup_test(Config) when is_list(Config) ->
- ok = ?t:appup_test(compiler).
+ ok = test_server:appup_test(compiler).
%% Tests that we can compile and run a simple Erlang program,
%% using compile:file/1.
file_1(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:minutes(5)),
-
process_flag(trap_exit, true),
- ?line {Simple, Target} = files(Config, "file_1"),
- ?line {ok, Cwd} = file:get_cwd(),
- ?line ok = file:set_cwd(filename:dirname(Target)),
+ {Simple, Target} = get_files(Config, simple, "file_1"),
+ {ok, Cwd} = file:get_cwd(),
+ ok = file:set_cwd(filename:dirname(Target)),
%% Native from BEAM without compilation info.
- ?line {ok,simple} = compile:file(Simple, [slim]), %Smoke test only.
- ?line {ok,simple} = compile:file(Target, [native,from_beam]), %Smoke test.
+ {ok,simple} = compile:file(Simple, [slim]), %Smoke test only.
+ {ok,simple} = compile:file(Target, [native,from_beam]), %Smoke test.
%% Native from BEAM with compilation info.
- ?line {ok,simple} = compile:file(Simple), %Smoke test only.
- ?line {ok,simple} = compile:file(Target, [native,from_beam]), %Smoke test.
+ {ok,simple} = compile:file(Simple), %Smoke test only.
+ {ok,simple} = compile:file(Target, [native,from_beam]), %Smoke test.
- ?line {ok,simple} = compile:file(Simple, [native,report]), %Smoke test.
+ {ok,simple} = compile:file(Simple, [native,report]), %Smoke test.
- ?line compile_and_verify(Simple, Target, []),
- ?line compile_and_verify(Simple, Target, [native]),
- ?line compile_and_verify(Simple, Target, [debug_info]),
- ?line {ok,simple} = compile:file(Simple, [no_line_info]), %Coverage
+ compile_and_verify(Simple, Target, []),
+ compile_and_verify(Simple, Target, [native]),
+ compile_and_verify(Simple, Target, [debug_info]),
+ {ok,simple} = compile:file(Simple, [no_line_info]), %Coverage
{ok,simple} = compile:file(Simple, [{eprof,beam_z}]), %Coverage
- ?line ok = file:set_cwd(Cwd),
- ?line true = exists(Target),
- ?line passed = run(Target, test, []),
+
+ %% Test option 'deterministic'.
+ {ok,simple} = compile:file(Simple, [deterministic]),
+ {module,simple} = c:l(simple),
+ [{version,_}] = simple:module_info(compile),
+ true = code:delete(simple),
+ false = code:purge(simple),
+
+ ok = file:set_cwd(Cwd),
+ true = exists(Target),
+ passed = run(Target, test, []),
+
+ %% Test option 'deterministic' as a compiler attribute.
+ Det = deterministic_module,
+ {DetPath, DetTarget} = get_files(Config, Det, "det_target"),
+ {ok,Det,DetCode} = compile:file(DetPath, [binary]),
+ {module,Det} = code:load_binary(Det, "", DetCode),
+ [{version,_}] = Det:module_info(compile),
+ true = code:delete(Det),
+ false = code:purge(Det),
%% Cleanup.
- ?line ok = file:delete(Target),
- ?line ok = file:del_dir(filename:dirname(Target)),
+ ok = file:delete(Target),
+ ok = file:del_dir(filename:dirname(Target)),
+ ok = file:del_dir(filename:dirname(DetTarget)),
%% There should not be any messages in the messages.
receive
Any ->
- ?t:fail({unexpected,Any})
+ ct:fail({unexpected,Any})
after 10 ->
ok
end,
- ?line test_server:timetrap_cancel(Dog),
ok.
forms_2(Config) when is_list(Config) ->
Src = "/foo/bar",
AbsSrc = filename:absname(Src),
Anno = erl_anno:new(1),
- {ok,simple,Binary} = compile:forms([{attribute,Anno,module,simple}],
- [binary,{source,Src}]),
- code:load_binary(simple, Src, Binary),
- Info = simple:module_info(compile),
+ SimpleCode = [{attribute,Anno,module,simple}],
+ {ok,simple,Bin1} = compile:forms(SimpleCode, [binary,{source,Src}]),
+
+ %% Load and test that the proper source is returned.
+ AbsSrc = forms_load_code(simple, Src, Bin1),
+
+ %% Work in a deleted directory.
+ PrivDir = proplists:get_value(priv_dir, Config),
+ WorkDir = filename:join(PrivDir, ?FUNCTION_NAME),
+ ok = file:make_dir(WorkDir),
+ ok = file:set_cwd(WorkDir),
+ case os:type() of
+ {unix,_} -> os:cmd("rm -rf " ++ WorkDir);
+ _ -> ok
+ end,
+ {ok,simple,Bin2} = compile:forms(SimpleCode),
+ undefined = forms_load_code(simple, "ignore", Bin2),
+
+ {ok,simple,Bin3} = compile:forms(SimpleCode, [{source,Src},report]),
+ case forms_load_code(simple, "ignore", Bin3) of
+ Src -> %Unix.
+ ok;
+ AbsSrc -> %Windows.
+ ok
+ end,
+
+ {ok,simple,Core} = compile:forms(SimpleCode, [to_core0,binary]),
+ forms_compile_and_load(Core, [from_core]),
+ forms_compile_and_load(Core, [from_core,native]),
- %% Test that the proper source is returned.
- AbsSrc = proplists:get_value(source, Info),
+ {ok,simple,Asm} = compile:forms(SimpleCode, [to_asm,binary]),
+ forms_compile_and_load(Asm, [from_asm]),
+ forms_compile_and_load(Asm, [from_asm,native]),
+
+ {ok,simple,Beam} = compile:forms(SimpleCode, []),
+ forms_compile_and_load(Beam, [from_beam]),
+ forms_compile_and_load(Beam, [from_beam,native]),
+
+ %% Cover the error handling code.
+ error = compile:forms(bad_core, [from_core,report]),
+ error = compile:forms(bad_asm, [from_asm,report]),
+ error = compile:forms(<<"bad_beam">>, [from_beam,report]),
+ error = compile:forms(<<"bad_beam">>, [from_beam,native,report]),
+
+ ok.
+
+
+forms_load_code(Mod, Src, Bin) ->
+ {module,Mod} = code:load_binary(Mod, Src, Bin),
+ Info = Mod:module_info(compile),
+ SourceOption = proplists:get_value(source, Info),
%% Ensure that the options are not polluted with 'source'.
[] = proplists:get_value(options, Info),
@@ -144,124 +205,123 @@ forms_2(Config) when is_list(Config) ->
%% Cleanup.
true = code:delete(simple),
false = code:purge(simple),
+
+ SourceOption.
+
+forms_compile_and_load(Code, Opts) ->
+ Mod = simple,
+ {ok,Mod,Bin} = compile:forms(Code, Opts),
+ {module,Mod} = code:load_binary(Mod, "ignore", Bin),
+ _ = Mod:module_info(),
+ true = code:delete(simple),
+ false = code:purge(simple),
ok.
module_mismatch(Config) when is_list(Config) ->
- ?line DataDir = ?config(data_dir, Config),
- ?line File = filename:join(DataDir, "wrong_module_name.erl"),
+ DataDir = proplists:get_value(data_dir, Config),
+ File = filename:join(DataDir, "wrong_module_name.erl"),
{error,[{"wrong_module_name.beam",
[{none,compile,{module_name,arne,"wrong_module_name"}}]}],
[]} = compile:file(File, [return]),
- ?line error = compile:file(File, [report]),
+ error = compile:file(File, [report]),
- ?line {ok,arne,[]} = compile:file(File,
+ {ok,arne,[]} = compile:file(File,
[return,no_error_module_mismatch]),
ok.
big_file(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:minutes(5)),
- ?line DataDir = ?config(data_dir, Config),
- ?line PrivDir = ?config(priv_dir, Config),
- ?line Big = filename:join(DataDir, "big.erl"),
- ?line Target = filename:join(PrivDir, "big.beam"),
- ?line ok = file:set_cwd(PrivDir),
- ?line compile_and_verify(Big, Target, []),
- ?line compile_and_verify(Big, Target, [debug_info]),
- ?line compile_and_verify(Big, Target, [no_postopt]),
+ {Big,Target} = get_files(Config, big, "big_file"),
+ ok = file:set_cwd(filename:dirname(Target)),
+ compile_and_verify(Big, Target, []),
+ compile_and_verify(Big, Target, [debug_info]),
+ compile_and_verify(Big, Target, [no_postopt]),
%% Cleanup.
- ?line ok = file:delete(Target),
- ?line test_server:timetrap_cancel(Dog),
+ ok = file:delete(Target),
ok.
%% Tests that the {outdir, Dir} option works.
outdir(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(60)),
- ?line {Simple, Target} = files(Config, "outdir"),
- ?line {ok, simple} = compile:file(Simple, [{outdir, filename:dirname(Target)}]),
- ?line true = exists(Target),
- ?line passed = run(Target, test, []),
- ?line ok = file:delete(Target),
- ?line ok = file:del_dir(filename:dirname(Target)),
- ?line test_server:timetrap_cancel(Dog),
+ {Simple, Target} = get_files(Config, simple, "outdir"),
+ {ok, simple} = compile:file(Simple, [{outdir, filename:dirname(Target)}]),
+ true = exists(Target),
+ passed = run(Target, test, []),
+ ok = file:delete(Target),
+ ok = file:del_dir(filename:dirname(Target)),
ok.
%% Tests that the binary option works.
binary(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(60)),
- ?line {Simple, Target} = files(Config, "binary"),
- ?line {ok, simple, Binary} = compile:file(Simple, [binary]),
- ?line code:load_binary(simple, Target, Binary),
- ?line passed = simple:test(),
- ?line true = code:delete(simple),
- ?line false = code:purge(simple),
- ?line ok = file:del_dir(filename:dirname(Target)),
- ?line test_server:timetrap_cancel(Dog),
+ {Simple, Target} = get_files(Config, simple, "binary"),
+ {ok, simple, Binary} = compile:file(Simple, [binary]),
+ code:load_binary(simple, Target, Binary),
+ passed = simple:test(),
+ true = code:delete(simple),
+ false = code:purge(simple),
+ ok = file:del_dir(filename:dirname(Target)),
ok.
%% Tests that the dependencies-Makefile-related options work.
makedep(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(60)),
- ?line {Simple,Target} = files(Config, "makedep"),
- ?line DataDir = ?config(data_dir, Config),
- ?line SimpleRootname = filename:rootname(Simple),
- ?line IncludeDir = filename:join(filename:dirname(Simple), "include"),
- ?line IncludeOptions = [
- {d,need_foo},
- {d,foo_value,42},
- {d,include_generated},
- {i,IncludeDir}
- ],
+ {Simple,Target} = get_files(Config, simple, "makedep"),
+ DataDir = proplists:get_value(data_dir, Config),
+ SimpleRootname = filename:rootname(Simple),
+ IncludeDir = filename:join(filename:dirname(Simple), "include"),
+ IncludeOptions = [
+ {d,need_foo},
+ {d,foo_value,42},
+ {d,include_generated},
+ {i,IncludeDir}
+ ],
%% Basic rule.
- ?line BasicMf1Name = SimpleRootname ++ "-basic1.mk",
- ?line {ok,BasicMf1} = file:read_file(BasicMf1Name),
- ?line {ok,_,Mf1} = compile:file(Simple, [binary,makedep]),
- ?line BasicMf1 = makedep_canonicalize_result(Mf1, DataDir),
+ BasicMf1Name = SimpleRootname ++ "-basic1.mk",
+ {ok,BasicMf1} = file:read_file(BasicMf1Name),
+ {ok,_,Mf1} = compile:file(Simple, [binary,makedep]),
+ BasicMf1 = makedep_canonicalize_result(Mf1, DataDir),
%% Basic rule with one existing header.
- ?line BasicMf2Name = SimpleRootname ++ "-basic2.mk",
- ?line {ok,BasicMf2} = file:read_file(BasicMf2Name),
- ?line {ok,_,Mf2} = compile:file(Simple, [binary,makedep|IncludeOptions]),
- ?line BasicMf2 = makedep_canonicalize_result(Mf2, DataDir),
+ BasicMf2Name = SimpleRootname ++ "-basic2.mk",
+ {ok,BasicMf2} = file:read_file(BasicMf2Name),
+ {ok,_,Mf2} = compile:file(Simple, [binary,makedep|IncludeOptions]),
+ BasicMf2 = makedep_canonicalize_result(Mf2, DataDir),
%% Rule with one existing header and one missing header.
- ?line MissingMfName = SimpleRootname ++ "-missing.mk",
- ?line {ok,MissingMf} = file:read_file(MissingMfName),
- ?line {ok,_,Mf3} = compile:file(Simple,
+ MissingMfName = SimpleRootname ++ "-missing.mk",
+ {ok,MissingMf} = file:read_file(MissingMfName),
+ {ok,_,Mf3} = compile:file(Simple,
[binary,makedep,makedep_add_missing|IncludeOptions]),
- ?line MissingMf = makedep_canonicalize_result(Mf3, DataDir),
+ MissingMf = makedep_canonicalize_result(Mf3, DataDir),
%% Rule with modified target.
- ?line TargetMf1Name = SimpleRootname ++ "-target1.mk",
- ?line {ok,TargetMf1} = file:read_file(TargetMf1Name),
- ?line {ok,_,Mf4} = compile:file(Simple,
+ TargetMf1Name = SimpleRootname ++ "-target1.mk",
+ {ok,TargetMf1} = file:read_file(TargetMf1Name),
+ {ok,_,Mf4} = compile:file(Simple,
[binary,makedep,{makedep_target,"$target"}|IncludeOptions]),
- ?line TargetMf1 = makedep_modify_target(
+ TargetMf1 = makedep_modify_target(
makedep_canonicalize_result(Mf4, DataDir), "$$target"),
%% Rule with quoted modified target.
- ?line TargetMf2Name = SimpleRootname ++ "-target2.mk",
- ?line {ok,TargetMf2} = file:read_file(TargetMf2Name),
- ?line {ok,_,Mf5} = compile:file(Simple,
+ TargetMf2Name = SimpleRootname ++ "-target2.mk",
+ {ok,TargetMf2} = file:read_file(TargetMf2Name),
+ {ok,_,Mf5} = compile:file(Simple,
[binary,makedep,{makedep_target,"$target"},makedep_quote_target|
IncludeOptions]),
- ?line TargetMf2 = makedep_modify_target(
+ TargetMf2 = makedep_modify_target(
makedep_canonicalize_result(Mf5, DataDir), "$$target"),
%% Basic rule written to some file.
- ?line {ok,_} = compile:file(Simple,
+ {ok,_} = compile:file(Simple,
[makedep,{makedep_output,Target}|IncludeOptions]),
- ?line {ok,Mf6} = file:read_file(Target),
- ?line BasicMf2 = makedep_canonicalize_result(Mf6, DataDir),
+ {ok,Mf6} = file:read_file(Target),
+ BasicMf2 = makedep_canonicalize_result(Mf6, DataDir),
%% Rule with creating phony target.
- ?line PhonyMfName = SimpleRootname ++ "-phony.mk",
- ?line {ok,PhonyMf} = file:read_file(PhonyMfName),
- ?line {ok,_,Mf7} = compile:file(Simple,
+ PhonyMfName = SimpleRootname ++ "-phony.mk",
+ {ok,PhonyMf} = file:read_file(PhonyMfName),
+ {ok,_,Mf7} = compile:file(Simple,
[binary,makedep,makedep_phony|IncludeOptions]),
- ?line PhonyMf = makedep_canonicalize_result(Mf7, DataDir),
+ PhonyMf = makedep_canonicalize_result(Mf7, DataDir),
- ?line ok = file:delete(Target),
- ?line ok = file:del_dir(filename:dirname(Target)),
- ?line test_server:timetrap_cancel(Dog),
+ ok = file:delete(Target),
+ ok = file:del_dir(filename:dirname(Target)),
ok.
makedep_canonicalize_result(Mf, DataDir) ->
@@ -281,30 +341,26 @@ makedep_modify_target(Mf, Target) ->
%% Tests that conditional compilation, defining values, including files work.
cond_and_ifdef(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(60)),
- ?line {Simple, Target} = files(Config, "cond_and_ifdef"),
- ?line IncludeDir = filename:join(filename:dirname(Simple), "include"),
- ?line Options = [{outdir, filename:dirname(Target)},
+ {Simple, Target} = get_files(Config, simple, "cond_and_ifdef"),
+ IncludeDir = filename:join(filename:dirname(Simple), "include"),
+ Options = [{outdir, filename:dirname(Target)},
{d, need_foo}, {d, foo_value, 42},
{i, IncludeDir}, report],
- ?line {ok, simple} = compile:file(Simple, Options),
- ?line true = exists(Target),
- ?line {hiker, 42} = run(Target, foo, []),
- ?line ok = file:delete(Target),
- ?line ok = file:del_dir(filename:dirname(Target)),
- ?line test_server:timetrap_cancel(Dog),
+ {ok, simple} = compile:file(Simple, Options),
+ true = exists(Target),
+ {hiker, 42} = run(Target, foo, []),
+ ok = file:delete(Target),
+ ok = file:del_dir(filename:dirname(Target)),
ok.
listings(Config) when is_list(Config) ->
- Dog = test_server:timetrap(test_server:minutes(8)),
- DataDir = ?config(data_dir, Config),
- PrivDir = ?config(priv_dir, Config),
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
ok = do_file_listings(DataDir, PrivDir, [
"simple",
"small",
"small_maps"
]),
- test_server:timetrap_cancel(Dog),
ok.
do_file_listings(_, _, []) -> ok;
@@ -325,12 +381,14 @@ do_file_listings(DataDir, PrivDir, [File|Files]) ->
do_listing(Simple, TargetDir, dinline, ".inline"),
do_listing(Simple, TargetDir, dcore, ".core"),
do_listing(Simple, TargetDir, dcopt, ".copt"),
+ do_listing(Simple, TargetDir, dcbsm, ".core_bsm"),
do_listing(Simple, TargetDir, dsetel, ".dsetel"),
do_listing(Simple, TargetDir, dkern, ".kernel"),
do_listing(Simple, TargetDir, dlife, ".life"),
do_listing(Simple, TargetDir, dcg, ".codegen"),
do_listing(Simple, TargetDir, dblk, ".block"),
- do_listing(Simple, TargetDir, dbool, ".bool"),
+ do_listing(Simple, TargetDir, dexcept, ".except"),
+ do_listing(Simple, TargetDir, dbs, ".bs"),
do_listing(Simple, TargetDir, dtype, ".type"),
do_listing(Simple, TargetDir, ddead, ".dead"),
do_listing(Simple, TargetDir, djmp, ".jump"),
@@ -359,159 +417,179 @@ do_file_listings(DataDir, PrivDir, [File|Files]) ->
do_file_listings(DataDir,PrivDir,Files).
listings_big(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:minutes(10)),
- ?line DataDir = ?config(data_dir, Config),
- ?line PrivDir = ?config(priv_dir, Config),
- ?line Big = filename:join(DataDir, big),
- ?line TargetDir = filename:join(PrivDir, listings_big),
- ?line ok = file:make_dir(TargetDir),
- ?line do_listing(Big, TargetDir, 'S'),
- ?line do_listing(Big, TargetDir, 'E'),
- ?line do_listing(Big, TargetDir, 'P'),
- ?line do_listing(Big, TargetDir, dkern, ".kernel"),
-
- ?line Target = filename:join(TargetDir, big),
- {ok,big} = compile:file(Target, [from_asm,{outdir,TargetDir}]),
+ {Big,Target} = get_files(Config, big, listings_big),
+ TargetDir = filename:dirname(Target),
+ do_listing(Big, TargetDir, 'S'),
+ do_listing(Big, TargetDir, 'E'),
+ do_listing(Big, TargetDir, 'P'),
+ do_listing(Big, TargetDir, dkern, ".kernel"),
+
+ TargetNoext = filename:rootname(Target, code:objfile_extension()),
+ {ok,big} = compile:file(TargetNoext, [from_asm,{outdir,TargetDir}]),
%% Cleanup.
- ?line ok = file:delete(Target ++ ".beam"),
- ?line lists:foreach(fun(F) -> ok = file:delete(F) end,
- filelib:wildcard(filename:join(TargetDir, "*"))),
- ?line ok = file:del_dir(TargetDir),
- ?line test_server:timetrap_cancel(Dog),
+ ok = file:delete(Target),
+ lists:foreach(fun(F) -> ok = file:delete(F) end,
+ filelib:wildcard(filename:join(TargetDir, "*"))),
+ ok = file:del_dir(TargetDir),
ok.
other_output(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:minutes(8)),
- ?line DataDir = ?config(data_dir, Config),
- ?line PrivDir = ?config(priv_dir, Config),
- ?line Simple = filename:join(DataDir, simple),
- ?line TargetDir = filename:join(PrivDir, other_output),
- ?line ok = file:make_dir(TargetDir),
+ {Simple,_Target} = get_files(Config, simple, "other_output"),
io:put_chars("to_pp"),
- ?line {ok,[],PP} = compile:file(Simple, [to_pp,binary,time]),
- ?line [] = [E || E <- PP,
- begin
- case element(1, E) of
- attribute -> false;
- function -> false;
- eof -> false
- end
- end],
+ {ok,[],PP} = compile:file(Simple, [to_pp,binary,time]),
+ [] = [E || E <- PP,
+ begin
+ case element(1, E) of
+ attribute -> false;
+ function -> false;
+ eof -> false
+ end
+ end],
io:put_chars("to_exp (file)"),
- ?line {ok,simple,Expand} = compile:file(Simple, [to_exp,binary,time]),
- ?line case Expand of
- {simple,Exports,Forms} when is_list(Exports), is_list(Forms) -> ok
- end,
+ {ok,[],Expand} = compile:file(Simple, [to_exp,binary,time]),
+ true = is_list(Expand),
+ {attribute,_,module,simple} = lists:keyfind(module, 3, Expand),
io:put_chars("to_exp (forms)"),
- ?line {ok,simple,Expand} = compile:forms(PP, [to_exp,binary,time]),
+ {ok,[],Expand} = compile:forms(PP, [to_exp,binary,time]),
io:put_chars("to_core (file)"),
- ?line {ok,simple,Core} = compile:file(Simple, [to_core,binary,time]),
- ?line c_module = element(1, Core),
- ?line {ok,_} = core_lint:module(Core),
+ {ok,simple,Core} = compile:file(Simple, [to_core,binary,time]),
+ c_module = element(1, Core),
+ {ok,_} = core_lint:module(Core),
io:put_chars("to_core (forms)"),
- ?line {ok,simple,Core} = compile:forms(PP, [to_core,binary,time]),
+ {ok,simple,Core} = compile:forms(PP, [to_core,binary,time]),
io:put_chars("to_kernel (file)"),
- ?line {ok,simple,Kernel} = compile:file(Simple, [to_kernel,binary,time]),
- ?line k_mdef = element(1, Kernel),
+ {ok,simple,Kernel} = compile:file(Simple, [to_kernel,binary,time]),
+ k_mdef = element(1, Kernel),
io:put_chars("to_kernel (forms)"),
- ?line {ok,simple,Kernel} = compile:forms(PP, [to_kernel,binary,time]),
+ {ok,simple,Kernel} = compile:forms(PP, [to_kernel,binary,time]),
io:put_chars("to_asm (file)"),
- ?line {ok,simple,Asm} = compile:file(Simple, [to_asm,binary,time]),
- ?line {simple,_,_,_,_} = Asm,
+ {ok,simple,Asm} = compile:file(Simple, [to_asm,binary,time]),
+ {simple,_,_,_,_} = Asm,
io:put_chars("to_asm (forms)"),
- ?line {ok,simple,Asm} = compile:forms(PP, [to_asm,binary,time]),
+ {ok,simple,Asm} = compile:forms(PP, [to_asm,binary,time]),
- ?line test_server:timetrap_cancel(Dog),
ok.
+%% Smoke test and cover of pretty-printing of Kernel code.
+kernel_listing(_Config) ->
+ TestBeams = get_unique_beam_files(),
+ Abstr = [begin {ok,{Mod,[{abstract_code,
+ {raw_abstract_v1,Abstr}}]}} =
+ beam_lib:chunks(Beam, [abstract_code]),
+ {Mod,Abstr} end || Beam <- TestBeams],
+ test_lib:p_run(fun(F) -> do_kernel_listing(F) end, Abstr).
+
+do_kernel_listing({M,A}) ->
+ try
+ {ok,M,Kern} = compile:forms(A, [to_kernel]),
+ IoList = v3_kernel_pp:format(Kern),
+ case unicode:characters_to_binary(IoList) of
+ Bin when is_binary(Bin) ->
+ ok
+ end
+ catch
+ throw:{error,Error} ->
+ io:format("*** compilation failure '~p' for module ~s\n",
+ [Error,M]),
+ error;
+ Class:Error ->
+ io:format("~p: ~p ~p\n~p\n",
+ [M,Class,Error,erlang:get_stacktrace()]),
+ error
+ end.
+
encrypted_abstr(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:minutes(10)),
- ?line {Simple,Target} = files(Config, "encrypted_abstr"),
+ {Simple,Target} = get_files(Config, simple, "encrypted_abstr"),
Res = case has_crypto() of
false ->
%% No crypto.
- ?line encrypted_abstr_no_crypto(Simple, Target),
+ encrypted_abstr_no_crypto(Simple, Target),
{comment,"The crypto application is missing or broken"};
true ->
%% Simulate not having crypto by removing
%% the crypto application from the path.
- ?line OldPath = code:get_path(),
+ OldPath = code:get_path(),
try
- ?line NewPath = OldPath -- [filename:dirname(code:which(crypto))],
- ?line (catch crypto:stop()),
- ?line code:delete(crypto),
- ?line code:purge(crypto),
- ?line code:set_path(NewPath),
- ?line encrypted_abstr_no_crypto(Simple, Target)
+ NewPath = OldPath -- [filename:dirname(code:which(crypto))],
+ (catch crypto:stop()),
+ code:delete(crypto),
+ code:purge(crypto),
+ code:set_path(NewPath),
+ encrypted_abstr_no_crypto(Simple, Target)
after
code:set_path(OldPath)
end,
%% Now run the tests that require crypto.
- ?line encrypted_abstr_1(Simple, Target),
- ?line ok = file:delete(Target),
- ?line ok = file:del_dir(filename:dirname(Target))
+ encrypted_abstr_1(Simple, Target),
+ ok = file:delete(Target),
+ ok = file:del_dir(filename:dirname(Target))
end,
%% Cleanup.
- ?line test_server:timetrap_cancel(Dog),
Res.
encrypted_abstr_1(Simple, Target) ->
- ?line TargetDir = filename:dirname(Target),
- ?line Key = "ablurf123BX#$;3",
- ?line install_crypto_key(Key),
- ?line {ok,simple} = compile:file(Simple,
+ TargetDir = filename:dirname(Target),
+ Key = "ablurf123BX#$;3",
+ install_crypto_key(Key),
+ {ok,simple} = compile:file(Simple,
[debug_info,{debug_info_key,Key},
{outdir,TargetDir}]),
- ?line verify_abstract(Target),
+ verify_abstract(Target, erl_abstract_code),
- ?line {ok,simple} = compile:file(Simple,
+ {ok,simple} = compile:file(Simple,
[{debug_info_key,Key},
{outdir,TargetDir}]),
- ?line verify_abstract(Target),
+ verify_abstract(Target, erl_abstract_code),
- ?line {ok,simple} = compile:file(Simple,
+ {ok,simple} = compile:file(Simple,
[debug_info,{debug_info_key,{des3_cbc,Key}},
{outdir,TargetDir}]),
- ?line verify_abstract(Target),
+ verify_abstract(Target, erl_abstract_code),
+
+ {ok,simple} = compile:file(Simple,
+ [{debug_info,{?MODULE,ok}},
+ {debug_info_key,Key},
+ {outdir,TargetDir}]),
+ verify_abstract(Target, ?MODULE),
- ?line {ok,{simple,[{compile_info,CInfo}]}} =
+ {ok,{simple,[{compile_info,CInfo}]}} =
beam_lib:chunks(Target, [compile_info]),
- ?line {value,{_,Opts}} = lists:keysearch(options, 1, CInfo),
- ?line {value,{_,'********'}} = lists:keysearch(debug_info_key, 1, Opts),
+ {_,Opts} = lists:keyfind(options, 1, CInfo),
+ {_,'********'} = lists:keyfind(debug_info_key, 1, Opts),
%% Try some illegal forms of crypto keys.
- ?line error = compile:file(Simple,
+ error = compile:file(Simple,
[debug_info,{debug_info_key,{blurf,"ss"}},report]),
- ?line error = compile:file(Simple,
+ error = compile:file(Simple,
[debug_info,{debug_info_key,{blurf,1,"ss"}},report]),
- ?line error = compile:file(Simple,
+ error = compile:file(Simple,
[debug_info,{debug_info_key,42},report]),
%% Place the crypto key in .erlang.crypt.
- ?line beam_lib:clear_crypto_key_fun(),
- ?line {ok,OldCwd} = file:get_cwd(),
- ?line ok = file:set_cwd(TargetDir),
-
- ?line error = compile:file(Simple, [encrypt_debug_info,report]),
-
- ?line NewKey = "better use another key here",
- ?line write_crypt_file(["[{debug_info,des3_cbc,simple,\"",NewKey,"\"}].\n"]),
- ?line {ok,simple} = compile:file(Simple, [encrypt_debug_info,report]),
- ?line verify_abstract("simple.beam"),
- ?line ok = file:delete(".erlang.crypt"),
- ?line beam_lib:clear_crypto_key_fun(),
- ?line {error,beam_lib,{key_missing_or_invalid,"simple.beam",abstract_code}} =
+ beam_lib:clear_crypto_key_fun(),
+ {ok,OldCwd} = file:get_cwd(),
+ ok = file:set_cwd(TargetDir),
+
+ error = compile:file(Simple, [encrypt_debug_info,report]),
+
+ NewKey = "better use another key here",
+ write_crypt_file(["[{debug_info,des3_cbc,simple,\"",NewKey,"\"}].\n"]),
+ {ok,simple} = compile:file(Simple, [encrypt_debug_info,report]),
+ verify_abstract("simple.beam", erl_abstract_code),
+ ok = file:delete(".erlang.crypt"),
+ beam_lib:clear_crypto_key_fun(),
+ {error,beam_lib,{key_missing_or_invalid,"simple.beam",abstract_code}} =
beam_lib:chunks("simple.beam", [abstract_code]),
- ?line ok = file:set_cwd(OldCwd),
+ ok = file:set_cwd(OldCwd),
%% Test key compatibility by reading a BEAM file produced before
%% the update to the new crypto functions.
@@ -532,21 +610,21 @@ write_crypt_file(Contents0) ->
encrypted_abstr_no_crypto(Simple, Target) ->
io:format("simpe: ~p~n", [Simple]),
- ?line TargetDir = filename:dirname(Target),
- ?line Key = "ablurf123BX#$;3",
- ?line error = compile:file(Simple,
+ TargetDir = filename:dirname(Target),
+ Key = "ablurf123BX#$;3",
+ error = compile:file(Simple,
[debug_info,{debug_info_key,Key},
{outdir,TargetDir},report]),
ok.
-verify_abstract(Target) ->
- {ok,{simple,[Chunk]}} = beam_lib:chunks(Target, [abstract_code]),
- {abstract_code,{raw_abstract_v1,_}} = Chunk.
+verify_abstract(Beam, Backend) ->
+ {ok,{simple,[Abst, Dbgi]}} = beam_lib:chunks(Beam, [abstract_code, debug_info]),
+ {abstract_code,{raw_abstract_v1,_}} = Abst,
+ {debug_info,{debug_info_v1,Backend,_}} = Dbgi.
has_crypto() ->
try
crypto:start(),
- <<_,_,_,_,_>> = crypto:rand_bytes(5),
crypto:stop(),
true
catch
@@ -561,8 +639,28 @@ install_crypto_key(Key) ->
ok = beam_lib:crypto_key_fun(F).
%% Miscellanous tests, mainly to get better coverage.
+debug_info(erlang_v1, Module, ok, _Opts) ->
+ {ok, [Module]};
+debug_info(erlang_v1, _Module, error, _Opts) ->
+ {error, unknown_format}.
+
+custom_debug_info(Config) when is_list(Config) ->
+ {Simple,_} = get_files(Config, simple, "file_1"),
+
+ {ok,simple,OkBin} = compile:file(Simple, [binary, {debug_info,{?MODULE,ok}}]), %Coverage
+ {ok,{simple,[{abstract_code,{raw_abstract_v1,[simple]}}]}} =
+ beam_lib:chunks(OkBin, [abstract_code]),
+ {ok,{simple,[{debug_info,{debug_info_v1,?MODULE,ok}}]}} =
+ beam_lib:chunks(OkBin, [debug_info]),
+
+ {ok,simple,ErrorBin} = compile:file(Simple, [binary, {debug_info,{?MODULE,error}}]), %Coverage
+ {ok,{simple,[{abstract_code,no_abstract_code}]}} =
+ beam_lib:chunks(ErrorBin, [abstract_code]),
+ {ok,{simple,[{debug_info,{debug_info_v1,?MODULE,error}}]}} =
+ beam_lib:chunks(ErrorBin, [debug_info]).
+
cover(Config) when is_list(Config) ->
- ?line io:format("~p\n", [compile:options()]),
+ io:format("~p\n", [compile:options()]),
ok.
do_listing(Source, TargetDir, Type) ->
@@ -573,31 +671,31 @@ do_listing(Source, TargetDir, Type, Ext) ->
[Source, TargetDir, Type, Ext]),
case compile:file(Source, [Type, time, {outdir, TargetDir}]) of
{ok, _} -> ok;
- Other -> test_server:fail({unexpected_result, Other})
+ Other -> ct:fail({unexpected_result, Other})
end,
SourceBase = filename:rootname(filename:basename(Source)),
Target = filename:join(TargetDir, SourceBase ++ Ext),
true = exists(Target).
-files(Config, Name) ->
- ?line code:delete(simple),
- ?line code:purge(simple),
- ?line DataDir = ?config(data_dir, Config),
- ?line PrivDir = ?config(priv_dir, Config),
- ?line Simple = filename:join(DataDir, "simple"),
- ?line TargetDir = filename:join(PrivDir, Name),
- ?line ok = file:make_dir(TargetDir),
- ?line Target = filename:join(TargetDir, "simple"++code:objfile_extension()),
- {Simple, Target}.
-
+get_files(Config, Module, OutputName) ->
+ code:delete(Module),
+ code:purge(Module),
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Src = filename:join(DataDir, atom_to_list(Module)),
+ TargetDir = filename:join(PrivDir, OutputName),
+ ok = file:make_dir(TargetDir),
+ File = atom_to_list(Module) ++ code:objfile_extension(),
+ Target = filename:join(TargetDir, File),
+ {Src, Target}.
run(Target, Func, Args) ->
- ?line Module = list_to_atom(filename:rootname(filename:basename(Target))),
- ?line {module, Module} = code:load_abs(filename:rootname(Target)),
- ?line Result = (catch apply(Module, Func, Args)),
- ?line true = code:delete(Module),
- ?line false = code:purge(Module),
+ Module = list_to_atom(filename:rootname(filename:basename(Target))),
+ {module, Module} = code:load_abs(filename:rootname(Target)),
+ Result = (catch apply(Module, Func, Args)),
+ true = code:delete(Module),
+ false = code:purge(Module),
Result.
exists(Name) ->
@@ -607,49 +705,27 @@ exists(Name) ->
end.
-%% Tests that the compiler does not accept
-%% bad use of records.
-bad_record_use1(Config) when is_list(Config) ->
- ?line {ok, Cwd} = file:get_cwd(),
- ?line file:set_cwd(?config(data_dir, Config)),
- ?line true=exists("bad_record_use.erl"),
- ?line Ret=c:c(bad_record_use),
- ?line file:set_cwd(Cwd),
- ?line error=Ret,
- ok.
-
-%% Tests that the compiler does not accept
-%% bad use of records.
-bad_record_use2(Config) when is_list(Config) ->
- ?line {ok, Cwd} = file:get_cwd(),
- ?line file:set_cwd(?config(data_dir, Config)),
- ?line true=exists("bad_record_use2.erl"),
- ?line Ret=c:c(bad_record_use),
- ?line file:set_cwd(Cwd),
- ?line error=Ret,
- ok.
-
strict_record(Config) when is_list(Config) ->
- ?line Priv = ?config(priv_dir, Config),
- ?line file:set_cwd(?config(data_dir, Config)),
- ?line Opts = [{outdir,Priv},report_errors],
+ Priv = proplists:get_value(priv_dir, Config),
+ ok = file:set_cwd(proplists:get_value(data_dir, Config)),
+ Opts = [{outdir,Priv},report_errors],
M = record_access,
- ?line {ok,M} = c:c(M, [strict_record_tests|Opts]),
- ?line Turtle = test_strict(),
+ {ok,M} = c:c(M, [strict_record_tests|Opts]),
+ Turtle = test_strict(),
- ?line {ok,M} = c:c(M, [no_strict_record_tests|Opts]),
- ?line Turtle = test_sloppy(),
+ {ok,M} = c:c(M, [no_strict_record_tests|Opts]),
+ Turtle = test_sloppy(),
%% The option first given wins.
- ?line {ok,M} = c:c(M, [no_strict_record_tests,strict_record_tests|Opts]),
- ?line Turtle = test_sloppy(),
- ?line {ok,M} = c:c(M, [strict_record_tests,no_strict_record_tests|Opts]),
- ?line Turtle = test_strict(),
+ {ok,M} = c:c(M, [no_strict_record_tests,strict_record_tests|Opts]),
+ Turtle = test_sloppy(),
+ {ok,M} = c:c(M, [strict_record_tests,no_strict_record_tests|Opts]),
+ Turtle = test_strict(),
%% Default (possibly influenced by ERL_COMPILER_OPTIONS).
- ?line {ok,M} = c:c(M, [{outdir,Priv},report_errors]),
- ?line try
+ {ok,M} = c:c(M, [{outdir,Priv},report_errors]),
+ try
{1,2} = record_access:test(Turtle),
{comment,"Default: no_strict_record_tests"}
catch
@@ -659,7 +735,7 @@ strict_record(Config) when is_list(Config) ->
test_strict() ->
Turtle = record_access:turtle(),
- ?line try
+ try
record_access:test(Turtle)
catch
error:{badrecord,tortoise} ->
@@ -672,103 +748,105 @@ test_sloppy() ->
{1,2} = record_access:test(Turtle),
Turtle.
-missing_testheap(Config) when is_list(Config) ->
- DataDir = ?config(data_dir, Config),
- PrivDir = ?config(priv_dir, Config),
- Opts = [{outdir,PrivDir}],
- OldPath = code:get_path(),
- try
- code:add_patha(PrivDir),
- c:c(filename:join(DataDir, "missing_testheap1"), Opts),
- c:c(filename:join(DataDir, "missing_testheap2"), Opts),
- ?line ok = test(fun() ->
- missing_testheap1:f({a,self()},{state,true,b})
- end, {a,b}),
- ?line ok = test(fun() ->
- missing_testheap2:f({a,self()},16#80000000) end,
- bigger)
- after
- code:set_path(OldPath),
- file:delete(filename:join(PrivDir, "missing_testheap1.beam")),
- file:delete(filename:join(PrivDir, "missing_testheap2.beam"))
- end,
- ok.
-
-test(Fun, Result) ->
- test(500, Fun, Result, []).
-
-test(0, _, _, _) ->
- ok;
-test(Iter, Fun, Result, Filler) ->
- spawn(?MODULE, init, [self(), Fun, list_to_tuple(Filler)]),
- receive
- {result, Result} ->
- test(Iter-1, Fun, Result, [0|Filler]);
- {result, Other} ->
- io:format("Expected ~p; got ~p~n", [Result, Other]),
- test_server:fail()
- end.
+utf8_atoms(Config) when is_list(Config) ->
+ Anno = erl_anno:new(1),
+ Atom = binary_to_atom(<<"こんにちは"/utf8>>, utf8),
+ Forms = [{attribute,Anno,compile,[export_all]},
+ {function,Anno,atom,0,[{clause,Anno,[],[],[{atom,Anno,Atom}]}]}],
+
+ Utf8AtomForms = [{attribute,Anno,module,utf8_atom}|Forms],
+ {ok,utf8_atom,Utf8AtomBin} =
+ compile:forms(Utf8AtomForms, [binary]),
+ {ok,{utf8_atom,[{atoms,_}]}} =
+ beam_lib:chunks(Utf8AtomBin, [atoms]),
+ code:load_binary(utf8_atom, "compile_SUITE", Utf8AtomBin),
+ Atom = utf8_atom:atom(),
+
+ NoUtf8AtomForms = [{attribute,Anno,module,no_utf8_atom}|Forms],
+ error = compile:forms(NoUtf8AtomForms, [binary, r19]).
+
+utf8_functions(Config) when is_list(Config) ->
+ Anno = erl_anno:new(1),
+ Atom = binary_to_atom(<<"こんにちは"/utf8>>, utf8),
+ Forms = [{attribute,Anno,compile,[export_all]},
+ {function,Anno,Atom,0,[{clause,Anno,[],[],[{atom,Anno,world}]}]}],
+
+ Utf8FunctionForms = [{attribute,Anno,module,utf8_function}|Forms],
+ {ok,utf8_function,Utf8FunctionBin} =
+ compile:forms(Utf8FunctionForms, [binary]),
+ {ok,{utf8_function,[{atoms,_}]}} =
+ beam_lib:chunks(Utf8FunctionBin, [atoms]),
+ code:load_binary(utf8_function, "compile_SUITE", Utf8FunctionBin),
+ world = utf8_function:Atom(),
+
+ NoUtf8FunctionForms = [{attribute,Anno,module,no_utf8_function}|Forms],
+ error = compile:forms(NoUtf8FunctionForms, [binary, r19]).
+
+extra_chunks(Config) when is_list(Config) ->
+ Anno = erl_anno:new(1),
+ Forms = [{attribute,Anno,module,extra_chunks}],
-init(ReplyTo, Fun, _Filler) ->
- ReplyTo ! {result, Fun()}.
+ {ok,extra_chunks,ExtraChunksBinary} =
+ compile:forms(Forms, [binary, {extra_chunks, [{<<"ExCh">>, <<"Contents">>}]}]),
+ {ok,{extra_chunks,[{"ExCh",<<"Contents">>}]}} =
+ beam_lib:chunks(ExtraChunksBinary, ["ExCh"]).
env(Config) when is_list(Config) ->
- ?line {Simple,Target} = files(Config, "file_1"),
- ?line {ok,Cwd} = file:get_cwd(),
- ?line ok = file:set_cwd(filename:dirname(Target)),
+ {Simple,Target} = get_files(Config, simple, env),
+ {ok,Cwd} = file:get_cwd(),
+ ok = file:set_cwd(filename:dirname(Target)),
true = os:putenv("ERL_COMPILER_OPTIONS", "binary"),
try
env_1(Simple, Target)
after
true = os:putenv("ERL_COMPILER_OPTIONS", "ignore_me"),
- file:set_cwd(Cwd),
- file:delete(Target),
- file:del_dir(filename:dirname(Target))
+ file:set_cwd(Cwd),
+ file:delete(Target),
+ file:del_dir(filename:dirname(Target))
end,
ok.
env_1(Simple, Target) ->
%% file
- ?line {ok,simple,<<_/binary>>} = compile:file(Simple),
- ?line {ok,simple} = compile:noenv_file(Simple, [debug_info]),
- ?line true = exists(Target),
- ?line {ok,{simple,[{abstract_code,Abstr0}]}} =
+ {ok,simple,<<_/binary>>} = compile:file(Simple),
+ {ok,simple} = compile:noenv_file(Simple, [debug_info]),
+ true = exists(Target),
+ {ok,{simple,[{abstract_code,Abstr0}]}} =
beam_lib:chunks(Target, [abstract_code]),
- ?line {raw_abstract_v1,Forms} = Abstr0,
+ {raw_abstract_v1,Forms} = Abstr0,
%% forms
- ?line true = os:putenv("ERL_COMPILER_OPTIONS", "strong_validation"),
- ?line {ok,simple} = compile:forms(Forms),
- ?line {ok,simple,<<"FOR1",_/binary>>} = compile:noenv_forms(Forms, []),
+ true = os:putenv("ERL_COMPILER_OPTIONS", "strong_validation"),
+ {ok,simple} = compile:forms(Forms),
+ {ok,simple,<<"FOR1",_/binary>>} = compile:noenv_forms(Forms, []),
%% output_generated
- ?line false = compile:output_generated([]),
- ?line true = compile:noenv_output_generated([]),
+ false = compile:output_generated([]),
+ true = compile:noenv_output_generated([]),
- ?line ok = file:delete(Target),
+ ok = file:delete(Target),
ok.
%% Test pretty-printing in Core Erlang format and then try to
%% compile the generated Core Erlang files.
-core(Config) when is_list(Config) ->
- PrivDir = ?config(priv_dir, Config),
- Outdir = filename:join(PrivDir, "core"),
+core_pp(Config) when is_list(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Outdir = filename:join(PrivDir, atom_to_list(?FUNCTION_NAME)),
ok = file:make_dir(Outdir),
- Wc = filename:join(filename:dirname(code:which(?MODULE)), "*.beam"),
- TestBeams = filelib:wildcard(Wc),
+ TestBeams = get_unique_beam_files(),
Abstr = [begin {ok,{Mod,[{abstract_code,
{raw_abstract_v1,Abstr}}]}} =
beam_lib:chunks(Beam, [abstract_code]),
{Mod,Abstr} end || Beam <- TestBeams],
- test_lib:p_run(fun(F) -> do_core(F, Outdir) end, Abstr).
+ test_lib:p_run(fun(F) -> do_core_pp(F, Outdir) end, Abstr).
-do_core({M,A}, Outdir) ->
+do_core_pp({M,A}, Outdir) ->
try
- do_core_1(M, A, Outdir)
+ do_core_pp_1(M, A, Outdir)
catch
throw:{error,Error} ->
io:format("*** compilation failure '~p' for module ~s\n",
@@ -780,11 +858,11 @@ do_core({M,A}, Outdir) ->
error
end.
-do_core_1(M, A, Outdir) ->
+do_core_pp_1(M, A, Outdir) ->
{ok,M,Core0} = compile:forms(A, [to_core]),
CoreFile = filename:join(Outdir, atom_to_list(M)++".core"),
CorePP = core_pp:format(Core0),
- ok = file:write_file(CoreFile, CorePP),
+ ok = file:write_file(CoreFile, unicode:characters_to_binary(CorePP)),
%% Parse the .core file and return the result as Core Erlang Terms.
Core = case compile:file(CoreFile, [report_errors,from_core,no_copt,to_core,binary]) of
@@ -794,7 +872,7 @@ do_core_1(M, A, Outdir) ->
ok = file:delete(CoreFile),
%% Compile as usual (including optimizations).
- compile_forms(Core, [clint,from_core,binary]),
+ compile_forms(M, Core, [clint,from_core,binary]),
%% Don't optimize to test that we are not dependent
%% on the Core Erlang optmimization passes.
@@ -803,29 +881,203 @@ do_core_1(M, A, Outdir) ->
%% records; if sys_core_fold was run it would fix
%% that; if sys_core_fold was not run v3_kernel would
%% crash.)
- compile_forms(Core, [clint,from_core,no_copt,binary]),
+ compile_forms(M, Core, [clint,from_core,no_copt,binary]),
ok.
-compile_forms(Forms, Opts) ->
+compile_forms(Mod, Forms, Opts) ->
case compile:forms(Forms, [report_errors|Opts]) of
- {ok,[],_} -> ok;
+ {ok,Mod,_} -> ok;
Other -> throw({error,Other})
end.
+%% Pretty-print core and read it back. Should be identical.
+
+core_roundtrip(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Outdir = filename:join(PrivDir, atom_to_list(?FUNCTION_NAME)),
+ ok = file:make_dir(Outdir),
+
+ TestBeams = get_unique_beam_files(),
+ test_lib:p_run(fun(F) -> do_core_roundtrip(F, Outdir) end, TestBeams).
+
+do_core_roundtrip(Beam, Outdir) ->
+ try
+ {ok,{Mod,[{abstract_code,{raw_abstract_v1,Abstr}}]}} =
+ beam_lib:chunks(Beam, [abstract_code]),
+ do_core_roundtrip_1(Mod, Abstr, Outdir)
+ catch
+ throw:{error,Error} ->
+ io:format("*** compilation failure '~p' for file ~s\n",
+ [Error,Beam]),
+ error;
+ Class:Error ->
+ io:format("~p: ~p ~p\n~p\n",
+ [Beam,Class,Error,erlang:get_stacktrace()]),
+ error
+ end.
+
+do_core_roundtrip_1(Mod, Abstr, Outdir) ->
+ {ok,Mod,Core0} = compile:forms(Abstr, [to_core0]),
+ do_core_roundtrip_2(Mod, Core0, Outdir),
+
+ %% Primarily, test that annotations are accepted for all
+ %% constructs. Secondarily, smoke test cerl_trees:label/1.
+ {Core1,_} = cerl_trees:label(Core0),
+ do_core_roundtrip_2(Mod, Core1, Outdir),
+
+ %% Run the inliner to force generation of variables
+ %% with numeric names.
+ {ok,Mod,Core2} = compile:forms(Abstr, [inline,to_core]),
+ do_core_roundtrip_2(Mod, Core2, Outdir).
+
+do_core_roundtrip_2(M, Core0, Outdir) ->
+ CoreFile = filename:join(Outdir, atom_to_list(M)++".core"),
+ CorePP = core_pp:format_all(Core0),
+ ok = file:write_file(CoreFile, unicode:characters_to_binary(CorePP)),
+
+ %% Parse the .core file and return the result as Core Erlang Terms.
+ Core2 = case compile:file(CoreFile, [report_errors,from_core,
+ no_copt,to_core,binary]) of
+ {ok,M,Core1} -> Core1;
+ Other -> throw({error,Other})
+ end,
+ Core = undo_var_translation(Core2),
+ ok = file:delete(CoreFile),
+
+ case cmp_core(Core0, Core, M) of
+ true -> ok;
+ false -> error
+ end.
+
+undo_var_translation(Tree) ->
+ F = fun(Node) ->
+ case cerl:is_c_var(Node) of
+ true ->
+ Name0 = cerl:var_name(Node),
+ try atom_to_list(Name0) of
+ "_X"++Name ->
+ cerl:update_c_var(Node, list_to_atom(Name));
+ "_"++Name ->
+ cerl:update_c_var(Node, list_to_atom(Name));
+ _ ->
+ Node
+ catch
+ error:badarg ->
+ Node
+
+ end;
+ false ->
+ Node
+ end
+ end,
+ cerl_trees:map(F, Tree).
+
+cmp_core(E, E, _Mod) ->
+ true;
+cmp_core(M1, M2, Mod) ->
+ cmp_core_fs(cerl:module_defs(M1), cerl:module_defs(M2), Mod).
+
+cmp_core_fs([F1|T1], [F2|T2], Mod) ->
+ cmp_core_f(F1, F2, Mod) andalso cmp_core_fs(T1, T2, Mod);
+cmp_core_fs([], [], _Mod) ->
+ true;
+cmp_core_fs(_, _, _Mod) ->
+ false.
+
+cmp_core_f(E, E, _Mod) ->
+ true;
+cmp_core_f({Name,F1}, {Name,F2}, Mod) ->
+ case diff(F1, F2) of
+ F1 ->
+ true;
+ Diff ->
+ io:format("~p ~p:\n~p\n", [Mod,Name,Diff]),
+ false
+ end.
+
+diff(E, E) ->
+ E;
+diff([H1|T1], [H2|T2]) ->
+ [diff(H1, H2)|diff(T1, T2)];
+diff(T1, T2) when tuple_size(T1) =:= tuple_size(T2) ->
+ case cerl:is_c_var(T1) andalso cerl:is_c_var(T2) of
+ true ->
+ diff_var(T1, T2);
+ false ->
+ case cerl:is_c_map(T1) andalso cerl:is_c_map(T2) of
+ true ->
+ diff_map(T1, T2);
+ false ->
+ diff_tuple(T1, T2)
+ end
+ end;
+diff(E1, E2) ->
+ {'DIFF',E1,E2}.
+
+diff_var(V1, V2) ->
+ case {cerl:var_name(V1),cerl:var_name(V2)} of
+ {Same,Same} ->
+ V1;
+ {Name1,Name2} ->
+ %% The inliner uses integers as variable names. Such integers
+ %% are read back as atoms.
+ case is_integer(Name1) andalso
+ list_to_atom(integer_to_list(Name1)) =:= Name2 of
+ true ->
+ V1;
+ _ ->
+ cerl:update_c_var(V1, {'DIFF',Name1,Name2})
+ end
+ end.
+
+%% Annotations for maps are not preserved exactly, but that is not
+%% a real problem. Workaround by not comparing all annotations when
+%% comparing maps.
+
+diff_map(M, M) ->
+ M;
+diff_map(M1, M2) ->
+ case cerl:get_ann(M1) =:= cerl:get_ann(M2) of
+ false ->
+ diff_tuple(M1, M2);
+ true ->
+ case remove_compiler_gen(M1) =:= remove_compiler_gen(M2) of
+ true ->
+ M1;
+ false ->
+ diff_tuple(M1, M2)
+ end
+ end.
+
+diff_tuple(T1, T2) ->
+ L = diff(tuple_to_list(T1), tuple_to_list(T2)),
+ list_to_tuple(L).
+
+remove_compiler_gen(M) ->
+ Arg0 = cerl:map_arg(M),
+ Arg = cerl:set_ann(Arg0, []),
+ Es0 = cerl:map_es(M),
+ Es = [remove_compiler_gen_1(Pair) || Pair <- Es0],
+ cerl:update_c_map(M, Arg, Es).
+
+remove_compiler_gen_1(Pair) ->
+ Op0 = cerl:map_pair_op(Pair),
+ Op = cerl:set_ann(Op0, []),
+ K = cerl:map_pair_key(Pair),
+ V = cerl:map_pair_val(Pair),
+ cerl:update_c_map_pair(Pair, Op, K, V).
+
%% Compile to Beam assembly language (.S) and then try to
%% run .S through the compiler again.
asm(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:minutes(20)),
- ?line PrivDir = ?config(priv_dir, Config),
- ?line Outdir = filename:join(PrivDir, "asm"),
- ?line ok = file:make_dir(Outdir),
-
- ?line Wc = filename:join(filename:dirname(code:which(?MODULE)), "*.beam"),
- ?line TestBeams = filelib:wildcard(Wc),
- ?line Res = test_lib:p_run(fun(F) -> do_asm(F, Outdir) end, TestBeams),
- ?line test_server:timetrap_cancel(Dog),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Outdir = filename:join(PrivDir, "asm"),
+ ok = file:make_dir(Outdir),
+
+ TestBeams = get_unique_beam_files(),
+ Res = test_lib:p_run(fun(F) -> do_asm(F, Outdir) end, TestBeams),
Res.
@@ -852,8 +1104,98 @@ do_asm(Beam, Outdir) ->
error
end.
+%% Make sure that guards are fully optimized. Guards should
+%% should use 'test' instructions, not 'bif' instructions.
+
+optimized_guards(_Config) ->
+ TestBeams = get_unique_beam_files(),
+ test_lib:p_run(fun(F) -> do_opt_guards(F) end, TestBeams).
+
+do_opt_guards(Beam) ->
+ {ok,{M,[{abstract_code,{raw_abstract_v1,A}}]}} =
+ beam_lib:chunks(Beam, [abstract_code]),
+ try
+ {ok,M,Asm} = compile:forms(A, ['S']),
+ do_opt_guards_mod(Asm)
+ catch Class:Error ->
+ io:format("~p: ~p ~p\n~p\n",
+ [M,Class,Error,erlang:get_stacktrace()]),
+ error
+ end.
+
+do_opt_guards_mod({Mod,_Exp,_Attr,Asm,_NumLabels}) ->
+ case do_opt_guards_fs(Mod, Asm) of
+ [] ->
+ ok;
+ [_|_]=Bifs ->
+ io:format("ERRORS FOR ~p:\n~p\n", [Mod,Bifs]),
+ error
+ end.
+
+do_opt_guards_fs(Mod, [{function,Name,Arity,_,Is}|Fs]) ->
+ Bifs0 = do_opt_guards_fun(Is),
+
+ %% The compiler does not attempt to optimize 'xor'.
+ %% Therefore, ignore all functions that use 'xor' in
+ %% a guard.
+ Bifs = case lists:any(fun({bif,'xor',_,_,_}) -> true;
+ (_) -> false
+ end, Bifs0) of
+ true -> [];
+ false -> Bifs0
+ end,
+
+ %% Filter out the allowed exceptions.
+ FA = {Name,Arity},
+ case {Bifs,is_exception(Mod, FA)} of
+ {[_|_],true} ->
+ io:format("~p:~p/~p IGNORED:\n~p\n",
+ [Mod,Name,Arity,Bifs]),
+ do_opt_guards_fs(Mod, Fs);
+ {[_|_],false} ->
+ [{FA,Bifs}|do_opt_guards_fs(Mod, Fs)];
+ {[],false} ->
+ do_opt_guards_fs(Mod, Fs);
+ {[],true} ->
+ io:format("Redundant exception for ~p:~p/~p\n",
+ [Mod,Name,Arity]),
+ error(redundant)
+ end;
+do_opt_guards_fs(_, []) -> [].
+
+do_opt_guards_fun([{bif,Name,{f,F},As,_}=I|Is]) when F =/= 0 ->
+ Arity = length(As),
+ case erl_internal:comp_op(Name, Arity) orelse
+ erl_internal:bool_op(Name, Arity) orelse
+ erl_internal:new_type_test(Name, Arity) of
+ true ->
+ [I|do_opt_guards_fun(Is)];
+ false ->
+ do_opt_guards_fun(Is)
+ end;
+do_opt_guards_fun([_|Is]) ->
+ do_opt_guards_fun(Is);
+do_opt_guards_fun([]) -> [].
+
+is_exception(bs_match_SUITE, {matching_and_andalso_2,2}) -> true;
+is_exception(bs_match_SUITE, {matching_and_andalso_3,2}) -> true;
+is_exception(guard_SUITE, {'-complex_not/1-fun-4-',1}) -> true;
+is_exception(guard_SUITE, {'-complex_not/1-fun-5-',1}) -> true;
+is_exception(guard_SUITE, {basic_andalso_orelse,1}) -> true;
+is_exception(guard_SUITE, {bad_guards,1}) -> true;
+is_exception(guard_SUITE, {bad_guards_2,2}) -> true;
+is_exception(guard_SUITE, {bad_guards_3,2}) -> true;
+is_exception(guard_SUITE, {cqlc,4}) -> true;
+is_exception(guard_SUITE, {csemi7,3}) -> true;
+is_exception(guard_SUITE, {misc,1}) -> true;
+is_exception(guard_SUITE, {nested_not_2b,4}) -> true;
+is_exception(guard_SUITE, {tricky_1,2}) -> true;
+is_exception(map_SUITE, {map_guard_update,2}) -> true;
+is_exception(map_SUITE, {map_guard_update_variables,3}) -> true;
+is_exception(_, _) -> false.
+
sys_pre_attributes(Config) ->
- DataDir = ?config(data_dir, Config),
+ DataDir = proplists:get_value(data_dir, Config),
File = filename:join(DataDir, "attributes.erl"),
Mod = attributes,
CommonOpts = [binary,report,verbose,
@@ -885,8 +1227,8 @@ sys_pre_attributes(Config) ->
%% Test the dialyzer option to cover more code.
dialyzer(Config) ->
- Priv = ?config(priv_dir, Config),
- file:set_cwd(?config(data_dir, Config)),
+ Priv = proplists:get_value(priv_dir, Config),
+ ok = file:set_cwd(proplists:get_value(data_dir, Config)),
Opts = [{outdir,Priv},report_errors],
M = dialyzer_test,
{ok,M} = c:c(M, [dialyzer|Opts]),
@@ -900,8 +1242,7 @@ dialyzer(Config) ->
%% Test that warnings contain filenames and line numbers.
warnings(_Config) ->
- TestDir = filename:dirname(code:which(?MODULE)),
- Files = filelib:wildcard(filename:join(TestDir, "*.erl")),
+ Files = get_unique_files(".erl"),
test_lib:p_run(fun do_warnings/1, Files).
do_warnings(F) ->
@@ -935,6 +1276,173 @@ do_warnings_2([], Next, F) ->
do_warnings_1(Next, F).
+%% Test that the compile:pre_load/0 function (used by 'erlc')
+%% pre-loads the modules that are used by a typical compilation.
+
+pre_load_check(Config) ->
+ case test_server:is_cover() of
+ true ->
+ {skip,"Cover is running"};
+ false ->
+ try
+ do_pre_load_check(Config)
+ after
+ dbg:stop_clear()
+ end
+ end.
+
+do_pre_load_check(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Simple = filename:join(DataDir, "simple.erl"),
+ Big = filename:join(DataDir, "big.erl"),
+ {ok,_} = dbg:tracer(process, {fun pre_load_trace/2,[]}),
+ dbg:p(self(), call),
+ dbg:p(new, call),
+ {ok,_} = dbg:tpl({?MODULE,get_trace_data,0}, []),
+ {ok,_} = dbg:tp({code,ensure_modules_loaded,1}, []),
+
+ %% Compile a simple module using the erl_compile interface
+ %% to find out the modules that are pre-loaded by
+ %% compile:pre_load/0.
+ Opts = #options{specific=[binary]},
+ {ok,simple,_} = compile:compile(Simple, "", Opts),
+ [{code,ensure_modules_loaded,[PreLoaded0]}] = get_trace_data(),
+ PreLoaded1 = ordsets:from_list(PreLoaded0),
+
+ %% Since 'compile' is the function doing the pre-loaded,
+ %% it is useless to include it in the list.
+ case ordsets:is_element(compile, PreLoaded1) of
+ true ->
+ io:put_chars("The 'compile' module should not be included "
+ "in the list of modules to be pre-loaded."),
+ ?t:fail(compile);
+ false ->
+ []
+ end,
+ PreLoaded = ordsets:add_element(compile, PreLoaded1),
+
+ %% Now unload all pre-loaded modules and all modules in
+ %% compiler application. Then compile a module to find
+ %% which modules that get loaded.
+ CompilerMods = compiler_modules(),
+ Unload = ordsets:union(ordsets:from_list(CompilerMods), PreLoaded),
+ _ = [begin
+ code:delete(M),
+ code:purge(M)
+ end || M <- Unload],
+
+ {ok,_} = dbg:ctp({code,ensure_modules_loaded,1}),
+ {ok,_} = dbg:tp({code,ensure_loaded,1}, []),
+ {ok,big,_} = compile:file(Big, [binary]),
+ WasLoaded0 = get_trace_data(),
+ WasLoaded1 = [M || {code,ensure_loaded,[M]} <- WasLoaded0],
+ WasLoaded = ordsets:from_list(WasLoaded1),
+
+ %% Check for modules that should have been pre-loaded.
+ case ordsets:subtract(WasLoaded, PreLoaded) of
+ [] ->
+ ok;
+ [_|_]=NotPreLoaded ->
+ io:format("The following modules were used "
+ "but not pre-loaded:\n~p\n",
+ [NotPreLoaded]),
+ ?t:fail({not_preload,NotPreLoaded})
+ end,
+
+ %% Check for modules that should not be pre-loaded.
+ case ordsets:subtract(PreLoaded, WasLoaded) of
+ [] ->
+ ok;
+ [_|_]=NotUsed ->
+ io:format("The following modules were pre-loaded"
+ " but not used:\n~p\n",
+ [NotUsed]),
+ ?t:fail({not_used,NotUsed})
+ end,
+
+ ok.
+
+get_trace_data() ->
+ %% Apparantely, doing a receive at the beginning of
+ %% a traced function can cause extra trace messages.
+ %% To avoid that, don't do the receive in this function.
+ do_get_trace_data().
+
+do_get_trace_data() ->
+ receive
+ {trace_data,Data} -> Data
+ end.
+
+pre_load_trace({trace,Pid,call,{?MODULE,get_trace_data,[]}}, Acc) ->
+ Pid ! {trace_data,Acc},
+ [];
+pre_load_trace({trace,_,call,MFA}, Acc) ->
+ [MFA|Acc].
+
+compiler_modules() ->
+ Wc = filename:join([code:lib_dir(compiler),"ebin","*.beam"]),
+ Ms = filelib:wildcard(Wc),
+ FN = filename,
+ [list_to_atom(FN:rootname(FN:basename(M), ".beam")) || M <- Ms].
+
+%% Test that ERL_COMPILER_OPTIONS are correctly retrieved
+%% by env_compiler_options/0
+
+env_compiler_options(_Config) ->
+ Cases = [
+ {"bin_opt_info", [bin_opt_info]},
+ {"'S'", ['S']},
+ {"{source, \"test.erl\"}", [{source, "test.erl"}]},
+ {"[{d,macro_one,1},{d,macro_two}]", [{d, macro_one, 1}, {d, macro_two}]},
+ {"[warn_export_all, warn_export_vars]", [warn_export_all, warn_export_vars]}
+ ],
+ F = fun({Env, Expected}) ->
+ true = os:putenv("ERL_COMPILER_OPTIONS", Env),
+ Expected = compile:env_compiler_options()
+ end,
+ lists:foreach(F, Cases).
+
+%% Test options for compatibility with previous major versions of OTP.
+
+bc_options(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+
+ 101 = highest_opcode(DataDir, small_float, [no_line_info]),
+
+ 103 = highest_opcode(DataDir, big,
+ [no_record_opt,no_line_info,no_stack_trimming]),
+
+ 125 = highest_opcode(DataDir, small_float, [no_line_info,no_float_opt]),
+
+ 132 = highest_opcode(DataDir, small,
+ [no_record_opt,no_float_opt,no_line_info]),
+
+ 136 = highest_opcode(DataDir, big, [no_record_opt,no_line_info]),
+
+ 153 = highest_opcode(DataDir, big, [no_record_opt]),
+ 153 = highest_opcode(DataDir, big, [r16]),
+ 153 = highest_opcode(DataDir, big, [r17]),
+ 153 = highest_opcode(DataDir, big, [r18]),
+ 153 = highest_opcode(DataDir, big, [r19]),
+ 153 = highest_opcode(DataDir, small_float, [r16]),
+ 153 = highest_opcode(DataDir, small_float, []),
+
+ 158 = highest_opcode(DataDir, small_maps, [r17]),
+ 158 = highest_opcode(DataDir, small_maps, [r18]),
+ 158 = highest_opcode(DataDir, small_maps, [r19]),
+ 158 = highest_opcode(DataDir, small_maps, []),
+
+ 159 = highest_opcode(DataDir, big, []),
+
+ ok.
+
+highest_opcode(DataDir, Mod, Opt) ->
+ Src = filename:join(DataDir, atom_to_list(Mod)++".erl"),
+ {ok,Mod,Beam} = compile:file(Src, [binary|Opt]),
+ {ok,{Mod,[{"Code",Code}]}} = beam_lib:chunks(Beam, ["Code"]),
+ <<16:32,0:32,HighestOpcode:32,_/binary>> = Code,
+ HighestOpcode.
+
%%%
%%% Utilities.
%%%
@@ -946,3 +1454,21 @@ compile_and_verify(Name, Target, Opts) ->
beam_lib:chunks(Target, [compile_info]),
{options,BeamOpts} = lists:keyfind(options, 1, CInfo),
Opts = BeamOpts.
+
+get_unique_beam_files() ->
+ get_unique_files(".beam").
+
+get_unique_files(Ext) ->
+ Wc = filename:join(filename:dirname(code:which(?MODULE)), "*"++Ext),
+ [F || F <- filelib:wildcard(Wc),
+ not is_cloned(F, Ext), not is_lfe_module(F, Ext)].
+
+is_cloned(File, Ext) ->
+ Mod = list_to_atom(filename:basename(File, Ext)),
+ test_lib:is_cloned_mod(Mod).
+
+is_lfe_module(File, Ext) ->
+ case filename:basename(File, Ext) of
+ "lfe_" ++ _ -> true;
+ _ -> false
+ end.
diff --git a/lib/compiler/test/compile_SUITE_data/attributes.erl b/lib/compiler/test/compile_SUITE_data/attributes.erl
index 00e635a021..140965c97d 100644
--- a/lib/compiler/test/compile_SUITE_data/attributes.erl
+++ b/lib/compiler/test/compile_SUITE_data/attributes.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-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.
diff --git a/lib/compiler/test/compile_SUITE_data/bad_record_use.erl b/lib/compiler/test/compile_SUITE_data/bad_record_use.erl
deleted file mode 100644
index 0fb6fc3045..0000000000
--- a/lib/compiler/test/compile_SUITE_data/bad_record_use.erl
+++ /dev/null
@@ -1,29 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. 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(bad_record_use).
--export([test/0]).
-
--record(bad_use, {a=undefined,
- b=undefined,
- c=undefined}).
-
-test() ->
- NewRecord=#bad_use{a=1, b=2, a=2}.
-
diff --git a/lib/compiler/test/compile_SUITE_data/bad_record_use2.erl b/lib/compiler/test/compile_SUITE_data/bad_record_use2.erl
deleted file mode 100644
index 7c898af00f..0000000000
--- a/lib/compiler/test/compile_SUITE_data/bad_record_use2.erl
+++ /dev/null
@@ -1,30 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. 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(bad_record_use2).
--export([test/0]).
-
--record(bad_use, {a=undefined,
- b=undefined,
- c=undefined}).
-
-test() ->
- R=#bad_use{a=1, b=2},
- R2=R#bad_use{a=1, b=2, a=2},
- ok.
diff --git a/lib/compiler/test/compile_SUITE_data/big.erl b/lib/compiler/test/compile_SUITE_data/big.erl
index d916742770..2e54ee8660 100644
--- a/lib/compiler/test/compile_SUITE_data/big.erl
+++ b/lib/compiler/test/compile_SUITE_data/big.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/lib/compiler/test/compilation_SUITE_data/otp_2141.erl b/lib/compiler/test/compile_SUITE_data/deterministic_module.erl
index 97daf8bffd..5e0e29c25e 100644
--- a/lib/compiler/test/compilation_SUITE_data/otp_2141.erl
+++ b/lib/compiler/test/compile_SUITE_data/deterministic_module.erl
@@ -1,8 +1,8 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2017. 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
@@ -14,12 +14,8 @@
%% 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(otp_2141).
--export([otp_2141/0]).
-
-
-otp_2141() ->
- ok.
+-module(deterministic_module).
+-compile([deterministic]).
diff --git a/lib/compiler/test/compile_SUITE_data/include/simple.hrl b/lib/compiler/test/compile_SUITE_data/include/simple.hrl
index 91398e209a..065378f820 100644
--- a/lib/compiler/test/compile_SUITE_data/include/simple.hrl
+++ b/lib/compiler/test/compile_SUITE_data/include/simple.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/lib/compiler/test/compile_SUITE_data/missing_testheap1.erl b/lib/compiler/test/compile_SUITE_data/missing_testheap1.erl
deleted file mode 100644
index 9d88bc4afe..0000000000
--- a/lib/compiler/test/compile_SUITE_data/missing_testheap1.erl
+++ /dev/null
@@ -1,36 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. 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(missing_testheap1).
-
--compile(export_all).
-%%-export([Function/Arity, ...]).
--record(state,{e1,e2}).
-
-f({a,DpId},State) when State ==
-#state{e1=true,
- e2=a} ->
- {a,a};
-
-f({a,DpId},State) when State ==
-#state{e1=true,
- e2=b} ->
- {a,b}.
-
-
diff --git a/lib/compiler/test/compile_SUITE_data/missing_testheap2.erl b/lib/compiler/test/compile_SUITE_data/missing_testheap2.erl
deleted file mode 100644
index b61e8d3c88..0000000000
--- a/lib/compiler/test/compile_SUITE_data/missing_testheap2.erl
+++ /dev/null
@@ -1,30 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. 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(missing_testheap2).
-
--compile(export_all).
-
-f({a,DpId},16#7fffffff) ->
- big;
-
-f({a,DpId},16#80000000) ->
- bigger.
-
-
diff --git a/lib/compiler/test/compile_SUITE_data/record_access.erl b/lib/compiler/test/compile_SUITE_data/record_access.erl
index 9a83472da4..537e9c8536 100644
--- a/lib/compiler/test/compile_SUITE_data/record_access.erl
+++ b/lib/compiler/test/compile_SUITE_data/record_access.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compile_SUITE_data/simple.erl b/lib/compiler/test/compile_SUITE_data/simple.erl
index 37e7b508f9..9385d101e0 100644
--- a/lib/compiler/test/compile_SUITE_data/simple.erl
+++ b/lib/compiler/test/compile_SUITE_data/simple.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
@@ -19,7 +19,7 @@
%%
-module(simple).
--export([test/0]).
+-export([test/0,unicode/0]).
-ifdef(need_foo).
-export([foo/0]).
@@ -28,6 +28,9 @@
test() ->
passed.
+unicode() ->
+ {"это",'спутник'}.
+
%% Conditional inclusion.
%% Compile with [{d, need_foo}, {d, foo_value, 42}].
diff --git a/lib/compiler/test/compile_SUITE_data/small_float.erl b/lib/compiler/test/compile_SUITE_data/small_float.erl
new file mode 100644
index 0000000000..5cbb5aef83
--- /dev/null
+++ b/lib/compiler/test/compile_SUITE_data/small_float.erl
@@ -0,0 +1,5 @@
+-module(small_float).
+-export([f/1]).
+
+f(F) when is_float(F) ->
+ F / 2.
diff --git a/lib/compiler/test/compile_SUITE_data/wrong_module_name.erl b/lib/compiler/test/compile_SUITE_data/wrong_module_name.erl
index 8b4db1cfa3..77dd4747f0 100644
--- a/lib/compiler/test/compile_SUITE_data/wrong_module_name.erl
+++ b/lib/compiler/test/compile_SUITE_data/wrong_module_name.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
+%% 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.
diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl
index 25f8564ce4..0e07e8dd2e 100644
--- a/lib/compiler/test/core_SUITE.erl
+++ b/lib/compiler/test/core_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,24 +26,25 @@
seq_in_guard/1,make_effect_seq/1,eval_is_boolean/1,
unsafe_case/1,nomatch_shadow/1,reversed_annos/1,
map_core_test/1,eval_case/1,bad_boolean_guard/1,
- bs_shadowed_size_var/1
- ]).
+ bs_shadowed_size_var/1,
+ cover_v3_kernel_1/1,cover_v3_kernel_2/1,cover_v3_kernel_3/1,
+ cover_v3_kernel_4/1,cover_v3_kernel_5/1,
+ non_variable_apply/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
-define(comp(N),
N(Config) when is_list(Config) -> try_it(N, Config)).
init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = test_server:timetrap(?t:minutes(5)),
- [{watchdog,Dog}|Config].
+ Config.
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
ok.
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,5}}].
all() ->
test_lib:recompile(?MODULE),
@@ -54,8 +55,11 @@ groups() ->
[dehydrated_itracer,nested_tries,seq_in_guard,make_effect_seq,
eval_is_boolean,unsafe_case,nomatch_shadow,reversed_annos,
map_core_test,eval_case,bad_boolean_guard,
- bs_shadowed_size_var
- ]}].
+ bs_shadowed_size_var,
+ cover_v3_kernel_1,cover_v3_kernel_2,cover_v3_kernel_3,
+ cover_v3_kernel_4,cover_v3_kernel_5,
+ non_variable_apply
+ ]}].
init_per_suite(Config) ->
@@ -65,10 +69,10 @@ end_per_suite(_Config) ->
ok.
init_per_group(_GroupName, Config) ->
- Config.
+ Config.
end_per_group(_GroupName, Config) ->
- Config.
+ Config.
?comp(dehydrated_itracer).
@@ -83,10 +87,16 @@ end_per_group(_GroupName, Config) ->
?comp(eval_case).
?comp(bad_boolean_guard).
?comp(bs_shadowed_size_var).
-
+?comp(cover_v3_kernel_1).
+?comp(cover_v3_kernel_2).
+?comp(cover_v3_kernel_3).
+?comp(cover_v3_kernel_4).
+?comp(cover_v3_kernel_5).
+?comp(non_variable_apply).
try_it(Mod, Conf) ->
- Src = filename:join(?config(data_dir, Conf), atom_to_list(Mod)),
+ Src = filename:join(proplists:get_value(data_dir, Conf),
+ atom_to_list(Mod)),
compile_and_load(Src, []),
compile_and_load(Src, [no_copt]).
diff --git a/lib/compiler/test/core_SUITE_data/cover_v3_kernel_1.core b/lib/compiler/test/core_SUITE_data/cover_v3_kernel_1.core
new file mode 100644
index 0000000000..9e5788796f
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/cover_v3_kernel_1.core
@@ -0,0 +1,147 @@
+module 'cover_v3_kernel_1' ['cover_v3_kernel_1'/0,
+ 'module_info'/0,
+ 'module_info'/1]
+ attributes []
+'cover_v3_kernel_1'/0 =
+ %% Line 4
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ %% Line 5
+ case apply 'bad_and_args'/1
+ ('x') of
+ <'error'> when 'true' ->
+ %% Line 7
+ case apply 'bad_and_args'/2
+ (1, 2) of
+ <'error'> when 'true' ->
+ %% Line 8
+ case apply 'bad_and_args'/2
+ (1, 'true') of
+ <'error'> when 'true' ->
+ %% Line 9
+ case apply 'bad_and_args'/2
+ ('true', 42) of
+ <'error'> when 'true' ->
+ %% Line 10
+ case apply 'bad_and_args'/2
+ ('true', 'false') of
+ <'error'> when 'true' ->
+ %% Line 11
+ case apply 'bad_and_args'/2
+ ('false', 'true') of
+ <'error'> when 'true' ->
+ %% Line 12
+ case apply 'bad_and_args'/2
+ ('true', 'true') of
+ <'ok'> when 'true' ->
+ %% Line 14
+ 'ok'
+ ( <_@c6> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_@c6})
+ -| ['compiler_generated'] )
+ end
+ ( <_@c5> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_@c5})
+ -| ['compiler_generated'] )
+ end
+ ( <_@c4> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_@c4})
+ -| ['compiler_generated'] )
+ end
+ ( <_@c3> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_@c3})
+ -| ['compiler_generated'] )
+ end
+ ( <_@c2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_@c2})
+ -| ['compiler_generated'] )
+ end
+ ( <_@c1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_@c1})
+ -| ['compiler_generated'] )
+ end
+ ( <_@c0> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_@c0})
+ -| ['compiler_generated'] )
+ end
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'cover_v3_kernel_1',0}}] )
+ -| ['compiler_generated'] )
+ end
+'bad_and_args'/1 =
+ %% Line 16
+ fun (_@c0) ->
+ case _@c0 of
+ <A>
+ when try
+ call 'erlang':'and'(A, 42)
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ %% Line 17
+ <_@c4> when 'true' ->
+ 'error'
+ ( <_@c3> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_@c3})
+ -| [{'function_name',{'bad_and_args',1}}] )
+ -| ['compiler_generated'] )
+ end
+'bad_and_args'/2 =
+ %% Line 19
+ fun (_@c1,_@c0) ->
+ case <_@c1,_@c0> of
+ <X,Y>
+ when try
+ call 'erlang':'and'(X, Y)
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ %% Line 20
+ <_@c6,_@c7> when 'true' ->
+ 'error'
+ ( <_@c5,_@c4> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_@c5,_@c4})
+ -| [{'function_name',{'bad_and_args',2}}] )
+ -| ['compiler_generated'] )
+ end
+'module_info'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('cover_v3_kernel_1')
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'module_info',0}}] )
+ -| ['compiler_generated'] )
+ end
+'module_info'/1 =
+ fun (_@c0) ->
+ case _@c0 of
+ <X> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('cover_v3_kernel_1', X)
+ ( <_@c1> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_@c1})
+ -| [{'function_name',{'module_info',1}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_SUITE_data/cover_v3_kernel_2.core b/lib/compiler/test/core_SUITE_data/cover_v3_kernel_2.core
new file mode 100644
index 0000000000..165aacd691
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/cover_v3_kernel_2.core
@@ -0,0 +1,98 @@
+module 'cover_v3_kernel_2' ['cover_v3_kernel_2'/0,
+ 'module_info'/0,
+ 'module_info'/1]
+ attributes []
+'cover_v3_kernel_2'/0 =
+ %% Line 4
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ %% Line 5
+ case apply 'strange_case'/1
+ ('a') of
+ <'ok'> when 'true' ->
+ %% Line 6
+ case apply 'strange_case'/1
+ ('b') of
+ <'ok'> when 'true' ->
+ %% Line 7
+ case apply 'strange_case'/1
+ ('c') of
+ <'error'> when 'true' ->
+ %% Line 8
+ case apply 'strange_case'/1
+ (42) of
+ <'error'> when 'true' ->
+ %% Line 9
+ 'ok'
+ ( <_cor3> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor3})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor2})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor1})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor0> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor0})
+ -| ['compiler_generated'] )
+ end
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'cover_v3_kernel_2',0}}] )
+ -| ['compiler_generated'] )
+ end
+'strange_case'/1 =
+ %% Line 12
+ fun (_cor0) ->
+ case _cor0 of
+ <X> when
+ case X of
+ <'a'> when 'true' -> 'true'
+ <'b'> when 'true' -> 'true'
+ <Other> when 'true' -> 'false'
+ end ->
+ 'ok'
+ %% Line 13
+ <_cor4> when 'true' ->
+ 'error'
+ ( <_cor3> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_cor3})
+ -| [{'function_name',{'strange_case',1}}] )
+ -| ['compiler_generated'] )
+ end
+'module_info'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('cover_v3_kernel_2')
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'module_info',0}}] )
+ -| ['compiler_generated'] )
+ end
+'module_info'/1 =
+ fun (_cor0) ->
+ case _cor0 of
+ <X> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('cover_v3_kernel_2', X)
+ ( <_cor1> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_cor1})
+ -| [{'function_name',{'module_info',1}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_SUITE_data/cover_v3_kernel_3.core b/lib/compiler/test/core_SUITE_data/cover_v3_kernel_3.core
new file mode 100644
index 0000000000..88a9edc354
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/cover_v3_kernel_3.core
@@ -0,0 +1,98 @@
+module 'cover_v3_kernel_3' ['cover_v3_kernel_3'/0,
+ 'module_info'/0,
+ 'module_info'/1]
+ attributes []
+'cover_v3_kernel_3'/0 =
+ %% Line 4
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ %% Line 5
+ case apply 'strange_case'/1
+ (1) of
+ <'ok'> when 'true' ->
+ %% Line 6
+ case apply 'strange_case'/1
+ (2) of
+ <'ok'> when 'true' ->
+ %% Line 7
+ case apply 'strange_case'/1
+ (42) of
+ <'error'> when 'true' ->
+ %% Line 8
+ case apply 'strange_case'/1
+ ('atom') of
+ <'error'> when 'true' ->
+ %% Line 9
+ 'ok'
+ ( <_cor3> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor3})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor2})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor1})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor0> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor0})
+ -| ['compiler_generated'] )
+ end
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'cover_v3_kernel_3',0}}] )
+ -| ['compiler_generated'] )
+ end
+'strange_case'/1 =
+ %% Line 12
+ fun (_cor0) ->
+ case _cor0 of
+ <X> when
+ case X of
+ <1> when 'true' -> 'true'
+ <2> when 'true' -> 'true'
+ <Other> when 'true' -> 'false'
+ end ->
+ 'ok'
+ %% Line 13
+ <_cor4> when 'true' ->
+ 'error'
+ ( <_cor3> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_cor3})
+ -| [{'function_name',{'strange_case',1}}] )
+ -| ['compiler_generated'] )
+ end
+'module_info'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('cover_v3_kernel_3')
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'module_info',0}}] )
+ -| ['compiler_generated'] )
+ end
+'module_info'/1 =
+ fun (_cor0) ->
+ case _cor0 of
+ <X> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('cover_v3_kernel_3', X)
+ ( <_cor1> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_cor1})
+ -| [{'function_name',{'module_info',1}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_SUITE_data/cover_v3_kernel_4.core b/lib/compiler/test/core_SUITE_data/cover_v3_kernel_4.core
new file mode 100644
index 0000000000..905e236f26
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/cover_v3_kernel_4.core
@@ -0,0 +1,82 @@
+module 'cover_v3_kernel_4' ['cover_v3_kernel_4'/0,
+ 'module_info'/0,
+ 'module_info'/1]
+ attributes []
+'cover_v3_kernel_4'/0 =
+ %% Line 4
+ fun () ->
+ %% Line 5
+ case apply 'turned_case'/1
+ (20) of
+ <'ok'> when 'true' ->
+ %% Line 6
+ case apply 'turned_case'/1
+ (0) of
+ <'error'> when 'true' ->
+ %% Line 7
+ 'ok'
+ ( <_@c1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_@c1})
+ -| ['compiler_generated'] )
+ end
+ ( <_@c0> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_@c0})
+ -| ['compiler_generated'] )
+ end
+'turned_case'/1 =
+ %% Line 9
+ fun (_@c0) ->
+ let <True> =
+ apply %% Line 10
+ 'id'/1
+ (%% Line 10
+ 'true')
+ in %% Line 11
+ case <> of
+ %% Line 12
+ <>
+ when try
+ ( let <_@c4> =
+ case call 'erlang':'<'
+ (_@c0, 10) of
+ ( <( 'false'
+ -| ['compiler_generated'] )> when 'true' ->
+ True
+ -| ['compiler_generated'] )
+ ( <( 'true'
+ -| ['compiler_generated'] )> when 'true' ->
+ 'false'
+ -| ['compiler_generated'] )
+ ( <_@c2> when 'true' ->
+ _@c2
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (( _@c4
+ -| ['compiler_generated'] ), 'true')
+ -| ['compiler_generated'] )
+ -| ['compiler_generated'] )
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ %% Line 13
+ <> when 'true' ->
+ 'error'
+ end
+'id'/1 =
+ %% Line 16
+ fun (_@c0) ->
+ _@c0
+'module_info'/0 =
+ fun () ->
+ call 'erlang':'get_module_info'
+ ('cover_v3_kernel_4')
+'module_info'/1 =
+ fun (_@c0) ->
+ call 'erlang':'get_module_info'
+ ('cover_v3_kernel_4', _@c0)
+end \ No newline at end of file
diff --git a/lib/compiler/test/core_SUITE_data/cover_v3_kernel_5.core b/lib/compiler/test/core_SUITE_data/cover_v3_kernel_5.core
new file mode 100644
index 0000000000..48c1bb84e6
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/cover_v3_kernel_5.core
@@ -0,0 +1,98 @@
+module 'cover_v3_kernel_5' ['cover_v3_kernel_5'/0,
+ 'module_info'/0,
+ 'module_info'/1]
+ attributes []
+'cover_v3_kernel_5'/0 =
+ %% Line 4
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ %% Line 5
+ case apply 'strange_case'/1
+ (1) of
+ <'ok'> when 'true' ->
+ %% Line 6
+ case apply 'strange_case'/1
+ (2) of
+ <'ok'> when 'true' ->
+ %% Line 7
+ case apply 'strange_case'/1
+ (42) of
+ <'error'> when 'true' ->
+ %% Line 8
+ case apply 'strange_case'/1
+ ('atom') of
+ <'error'> when 'true' ->
+ %% Line 9
+ 'ok'
+ ( <_cor3> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor3})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor2})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor1})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor0> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor0})
+ -| ['compiler_generated'] )
+ end
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'cover_v3_kernel_5',0}}] )
+ -| ['compiler_generated'] )
+ end
+'strange_case'/1 =
+ %% Line 12
+ fun (_cor0) ->
+ case _cor0 of
+ <X> when
+ case X of
+ <1> when 'true' -> 'true'
+ <2> when 'true' -> 'true'
+ <Other> when 'true' -> X
+ end ->
+ 'ok'
+ %% Line 13
+ <_cor4> when 'true' ->
+ 'error'
+ ( <_cor3> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_cor3})
+ -| [{'function_name',{'strange_case',1}}] )
+ -| ['compiler_generated'] )
+ end
+'module_info'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('cover_v3_kernel_5')
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'module_info',0}}] )
+ -| ['compiler_generated'] )
+ end
+'module_info'/1 =
+ fun (_cor0) ->
+ case _cor0 of
+ <X> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('cover_v3_kernel_5', X)
+ ( <_cor1> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_cor1})
+ -| [{'function_name',{'module_info',1}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_SUITE_data/non_variable_apply.core b/lib/compiler/test/core_SUITE_data/non_variable_apply.core
new file mode 100644
index 0000000000..d9322cc455
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/non_variable_apply.core
@@ -0,0 +1,80 @@
+module 'non_variable_apply' ['module_info'/0,
+ 'module_info'/1,
+ 'non_variable_apply'/0]
+ attributes []
+
+'non_variable_apply'/0 =
+ %% Line 4
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ let <OkFun> =
+ fun (_@c0) ->
+ %% Line 5
+ case _@c0 of
+ <'ok'> when 'true' ->
+ 'ok'
+ ( <_@c1> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_@c1})
+ -| [{'function_name',{'-non_variable_apply/0-fun-0-',1}}] )
+ -| ['compiler_generated'] )
+ end
+ in let <F> =
+ fun (_@c5,_@c4) ->
+ %% Line 6
+ case <_@c5,_@c4> of
+ <F,X> when 'true' ->
+ apply apply 'id'/1 (F) (X)
+ ( <_@c7,_@c6> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_@c7,_@c6})
+ -| [{'function_name',{'-non_variable_apply/0-fun-1-',2}}] )
+ -| ['compiler_generated'] )
+ end
+ in %% Line 9
+ apply F
+ (OkFun, 'ok')
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'non_variable_apply',0}}] )
+ -| ['compiler_generated'] )
+ end
+'id'/1 =
+ %% Line 11
+ fun (_@c0) ->
+ case _@c0 of
+ <I> when 'true' ->
+ I
+ ( <_@c1> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_@c1})
+ -| [{'function_name',{'id',1}}] )
+ -| ['compiler_generated'] )
+ end
+'module_info'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('non_variable_apply')
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'module_info',0}}] )
+ -| ['compiler_generated'] )
+ end
+'module_info'/1 =
+ fun (_@c0) ->
+ case _@c0 of
+ <X> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('non_variable_apply', X)
+ ( <_@c1> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_@c1})
+ -| [{'function_name',{'module_info',1}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index 016ea9d0d9..0097e28d4d 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
@@ -25,11 +25,12 @@
eq/1,nested_call_in_case/1,guard_try_catch/1,coverage/1,
unused_multiple_values_error/1,unused_multiple_values/1,
multiple_aliases/1,redundant_boolean_clauses/1,
- mixed_matching_clauses/1,unnecessary_building/1]).
+ mixed_matching_clauses/1,unnecessary_building/1,
+ no_no_file/1,configuration/1,supplies/1]).
-export([foo/0,foo/1,foo/2,foo/3]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -43,7 +44,8 @@ groups() ->
eq,nested_call_in_case,guard_try_catch,coverage,
unused_multiple_values_error,unused_multiple_values,
multiple_aliases,redundant_boolean_clauses,
- mixed_matching_clauses,unnecessary_building]}].
+ mixed_matching_clauses,unnecessary_building,
+ no_no_file,configuration,supplies]}].
init_per_suite(Config) ->
@@ -61,8 +63,8 @@ end_per_group(_GroupName, Config) ->
t_element(Config) when is_list(Config) ->
X = make_ref(),
- ?line X = id(element(1, {X,y,z})),
- ?line b = id(element(2, {a,b,c,d})),
+ X = id(element(1, {X,y,z})),
+ b = id(element(2, {a,b,c,d})),
(fun() ->
case {a,#{k=>X}} of
{a,#{k:=X}}=Tuple ->
@@ -73,21 +75,21 @@ t_element(Config) when is_list(Config) ->
%% No optimization, but should work.
Tuple = id({x,y,z}),
Pos = id(3),
- ?line x = id(element(1, Tuple)),
- ?line c = id(element(Pos, {a,b,c,d})),
- ?line X = id(element(Pos, {a,b,X,d})),
- ?line z = id(element(Pos, Tuple)),
+ x = id(element(1, Tuple)),
+ c = id(element(Pos, {a,b,c,d})),
+ X = id(element(Pos, {a,b,X,d})),
+ z = id(element(Pos, Tuple)),
%% Calls that will fail.
- ?line {'EXIT',{badarg,_}} = (catch element(5, {a,b,c,d})),
- ?line {'EXIT',{badarg,_}} = (catch element(5, {a,b,X,d})),
- ?line {'EXIT',{badarg,_}} = (catch element(5.0, {a,b,X,d})),
+ {'EXIT',{badarg,_}} = (catch element(5, {a,b,c,d})),
+ {'EXIT',{badarg,_}} = (catch element(5, {a,b,X,d})),
+ {'EXIT',{badarg,_}} = (catch element(5.0, {a,b,X,d})),
{'EXIT',{badarg,_}} = (catch element(2, not_a_tuple)),
{'EXIT',{badarg,_}} = (catch element(2, [])),
{'EXIT',{badarg,_}} = (catch element(2, Tuple == 3)),
case id({a,b,c}) of
{_,_,_}=Tup ->
- ?line {'EXIT',{badarg,_}} = (catch element(4, Tup))
+ {'EXIT',{badarg,_}} = (catch element(4, Tup))
end,
{'EXIT',{badarg,_}} = (catch element(1, tuple_size(Tuple))),
@@ -96,16 +98,16 @@ t_element(Config) when is_list(Config) ->
setelement(Config) when is_list(Config) ->
X = id(b),
New = id([1,2,3]),
- ?line {y,b,c} = id(setelement(1, {a,b,c}, y)),
- ?line {y,b,c} = id(setelement(1, {a,X,c}, y)),
- ?line {a,y,c} = id(setelement(2, {a,X,c}, y)),
- ?line {a,[1,2,3],c} = id(setelement(2, {a,b,c}, New)),
- ?line {a,[1,2,3],c} = id(setelement(2, {a,X,c}, New)),
- ?line {a,b,[1,2,3]} = id(setelement(3, {a,b,c}, New)),
- ?line {a,b,[1,2,3]} = id(setelement(3, {a,X,c}, New)),
+ {y,b,c} = id(setelement(1, {a,b,c}, y)),
+ {y,b,c} = id(setelement(1, {a,X,c}, y)),
+ {a,y,c} = id(setelement(2, {a,X,c}, y)),
+ {a,[1,2,3],c} = id(setelement(2, {a,b,c}, New)),
+ {a,[1,2,3],c} = id(setelement(2, {a,X,c}, New)),
+ {a,b,[1,2,3]} = id(setelement(3, {a,b,c}, New)),
+ {a,b,[1,2,3]} = id(setelement(3, {a,X,c}, New)),
- ?line {'EXIT',{badarg,_}} = (catch setelement_crash({a,b,c,d,e,f})),
- ?line error = setelement_crash_2({a,b,c,d,e,f}, <<42>>),
+ {'EXIT',{badarg,_}} = (catch setelement_crash({a,b,c,d,e,f})),
+ error = setelement_crash_2({a,b,c,d,e,f}, <<42>>),
{'EXIT',{badarg,_}} = (catch setelement(1, not_a_tuple, New)),
{'EXIT',{badarg,_}} = (catch setelement(3, {a,b}, New)),
@@ -132,19 +134,19 @@ setelement_crash_2(Tuple, Bin) ->
t_length(Config) when is_list(Config) ->
Blurf = id({blurf,a,b}),
Tail = id([42,43,44,45]),
- ?line 0 = id(length([])),
- ?line 1 = id(length([x])),
- ?line 2 = id(length([x,Blurf])),
- ?line 4 = id(length([x,Blurf,a,b])),
+ 0 = id(length([])),
+ 1 = id(length([x])),
+ 2 = id(length([x,Blurf])),
+ 4 = id(length([x,Blurf,a,b])),
%% No or partial optimization.
- ?line 4 = length(Tail),
- ?line 5 = id(length([x|Tail])),
+ 4 = length(Tail),
+ 5 = id(length([x|Tail])),
%% Will fail.
- ?line {'EXIT',{badarg,_}} = (catch id(length([a,b|c]))),
- ?line {'EXIT',{badarg,_}} = (catch id(length([a,Blurf|c]))),
- ?line {'EXIT',{badarg,_}} = (catch id(length(atom))),
+ {'EXIT',{badarg,_}} = (catch id(length([a,b|c]))),
+ {'EXIT',{badarg,_}} = (catch id(length([a,Blurf|c]))),
+ {'EXIT',{badarg,_}} = (catch id(length(atom))),
ok.
@@ -156,34 +158,34 @@ t_length(Config) when is_list(Config) ->
append(Config) when is_list(Config) ->
A = id(0),
- ?line [a,b,c,d,e,f,g,h,i,j,k] = id(?APPEND([a,b,c,d,e,f],[g,h,i,j,k])),
- ?line [a,b,c,d,e] = id(?APPEND([a,b,c],id([d,e]))),
- ?line [0,1,2,3,4,5,6] = id(?APPEND([A,1,2,3],[4,5,6])),
- ?line {'EXIT',{badarg,_}} = (catch id(?APPEND([A|blurf],[4,5,6]))),
+ [a,b,c,d,e,f,g,h,i,j,k] = id(?APPEND([a,b,c,d,e,f],[g,h,i,j,k])),
+ [a,b,c,d,e] = id(?APPEND([a,b,c],id([d,e]))),
+ [0,1,2,3,4,5,6] = id(?APPEND([A,1,2,3],[4,5,6])),
+ {'EXIT',{badarg,_}} = (catch id(?APPEND([A|blurf],[4,5,6]))),
ok.
t_apply(Config) when is_list(Config) ->
- ?line ok = apply(?MODULE, foo, []),
- ?line 4 = apply(?MODULE, foo, [3]),
- ?line 7 = apply(?MODULE, foo, [3,4]),
- ?line 12 = apply(?MODULE, foo, [id(8),4]),
- ?line 21 = apply(?MODULE, foo, [8,id(9),4]),
- ?line 20 = apply(?MODULE, foo, [8,8,id(4)]),
- ?line 24 = apply(?MODULE, foo, [id(10),10,4]),
+ ok = apply(?MODULE, foo, []),
+ 4 = apply(?MODULE, foo, [3]),
+ 7 = apply(?MODULE, foo, [3,4]),
+ 12 = apply(?MODULE, foo, [id(8),4]),
+ 21 = apply(?MODULE, foo, [8,id(9),4]),
+ 20 = apply(?MODULE, foo, [8,8,id(4)]),
+ 24 = apply(?MODULE, foo, [id(10),10,4]),
M = id(?MODULE),
- ?line ok = apply(M, foo, []),
- ?line 4 = apply(M, foo, [3]),
- ?line 16.0 = apply(M, foo, [12.0,4]),
+ ok = apply(M, foo, []),
+ 4 = apply(M, foo, [3]),
+ 16.0 = apply(M, foo, [12.0,4]),
%% Will fail.
- ?line {'EXIT',{badarg,_}} = (catch apply([a,b,c], foo, [])),
- ?line {'EXIT',{badarg,_}} = (catch apply(42, foo, [])),
- ?line {'EXIT',{badarg,_}} = (catch apply(?MODULE, 45, [xx])),
- ?line {'EXIT',{badarg,_}} = (catch apply(?MODULE, foo, {a,b})),
- ?line {'EXIT',{badarg,_}} = (catch apply(M, M, [1009|10010])),
- ?line {'EXIT',{badarg,_}} = (catch apply(?MODULE, foo, [10000|9999])),
- ?line {'EXIT',{badarg,_}} = (catch apply(?MODULE, foo, a)),
+ {'EXIT',{badarg,_}} = (catch apply([a,b,c], foo, [])),
+ {'EXIT',{badarg,_}} = (catch apply(42, foo, [])),
+ {'EXIT',{badarg,_}} = (catch apply(?MODULE, 45, [xx])),
+ {'EXIT',{badarg,_}} = (catch apply(?MODULE, foo, {a,b})),
+ {'EXIT',{badarg,_}} = (catch apply(M, M, [1009|10010])),
+ {'EXIT',{badarg,_}} = (catch apply(?MODULE, foo, [10000|9999])),
+ {'EXIT',{badarg,_}} = (catch apply(?MODULE, foo, a)),
ok.
@@ -210,13 +212,13 @@ bifs(Config) when is_list(Config) ->
-define(CMP_DIFF(A0, B), (fun(A) -> false = A == B, true = A /= B end)(id(A0))).
eq(Config) when is_list(Config) ->
- ?line ?CMP_SAME([a,b,c], [a,b,c]),
- ?line ?CMP_SAME([42.0], [42.0]),
- ?line ?CMP_SAME([42], [42]),
- ?line ?CMP_SAME([42.0], [42]),
+ ?CMP_SAME([a,b,c], [a,b,c]),
+ ?CMP_SAME([42.0], [42.0]),
+ ?CMP_SAME([42], [42]),
+ ?CMP_SAME([42.0], [42]),
- ?line ?CMP_DIFF(a, [a]),
- ?line ?CMP_DIFF(a, {1,2,3}),
+ ?CMP_DIFF(a, [a]),
+ ?CMP_DIFF(a, {1,2,3}),
?CMP_SAME(#{a=>1.0,b=>2}, #{b=>2.0,a=>1}),
?CMP_SAME(#{a=>[1.0],b=>[2]}, #{b=>[2.0],a=>[1]}),
@@ -232,7 +234,7 @@ eq(Config) when is_list(Config) ->
%% OTP-7117.
nested_call_in_case(Config) when is_list(Config) ->
- PrivDir = ?config(priv_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
Dir = test_lib:get_data_dir(Config),
Core = filename:join(Dir, "nested_call_in_case"),
Opts = [from_core,{outdir,PrivDir}|test_lib:opt_opts(?MODULE)],
@@ -265,12 +267,12 @@ do_guard_try_catch(K, V) ->
-record(cover_opt_guard_try, {list=[]}).
coverage(Config) when is_list(Config) ->
- ?line {'EXIT',{{case_clause,{a,b,c}},_}} =
+ {'EXIT',{{case_clause,{a,b,c}},_}} =
(catch cover_will_match_list_type({a,b,c})),
- ?line {'EXIT',{{case_clause,{a,b,c,d}},_}} =
+ {'EXIT',{{case_clause,{a,b,c,d}},_}} =
(catch cover_will_match_list_type({a,b,c,d})),
- ?line a = cover_remove_non_vars_alias({a,b,c}),
- ?line error = cover_will_match_lit_list(),
+ a = cover_remove_non_vars_alias({a,b,c}),
+ error = cover_will_match_lit_list(),
{ok,[a]} = cover_is_safe_bool_expr(a),
ok = cover_opt_guard_try(#cover_opt_guard_try{list=[a]}),
@@ -347,7 +349,7 @@ bsm_an_inlined(<<_:8>>, _) -> ok;
bsm_an_inlined(_, _) -> error.
unused_multiple_values_error(Config) when is_list(Config) ->
- PrivDir = ?config(priv_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
Dir = test_lib:get_data_dir(Config),
Core = filename:join(Dir, "unused_multiple_values_error"),
Opts = [no_copt,clint,return,from_core,{outdir,PrivDir}
@@ -454,4 +456,75 @@ do_unnecessary_building_2({a,_,_}=T) ->
[_,_] = [T,none],
x}.
+%% This test tests that v3_core has provided annotations and that
+%% sys_core_fold retains them, so that warnings produced by
+%% sys_core_fold will have proper filenames and line numbers. Thus, no
+%% "no_file" warnings.
+no_no_file(_Config) ->
+ {'EXIT',{{case_clause,0},_}} = (catch source(true, any)),
+ surgery = (tim(#{reduction => any}))(),
+
+ false = soul(#{[] => true}),
+ {'EXIT',{{case_clause,true},_}} = (catch soul(#{[] => false})),
+
+ ok = experiment(),
+ ok.
+
+source(true, Activities) ->
+ case 0 of
+ Activities when [] ->
+ Activities
+ end.
+
+tim(#{reduction := Emergency}) ->
+ try
+ fun() -> surgery end
+ catch
+ _ when [] ->
+ planet
+ end.
+
+soul(#{[] := Properly}) ->
+ not case true of
+ Properly -> true;
+ Properly -> 0
+ end.
+
+experiment() ->
+ case kingdom of
+ _ ->
+ +case "map" of
+ _ -> 0.0
+ end
+ end,
+ ok.
+
+
+%% Make sure we don't try to move a fun into a guard.
+configuration(_Config) ->
+ {'EXIT',_} = (catch configuration()),
+ ok.
+
+configuration() ->
+ [forgotten || Components <- enemy, is_tuple(fun art/0)].
+
+art() ->
+ creating.
+
+%% core_lint would complain after optimization. A call to error/1
+%% must not occur unconditionally in a guard.
+supplies(_Config) ->
+ case ?MODULE of
+ core_fold_inline_SUITE ->
+ %% Other error behaviour when inlined.
+ ok;
+ _ ->
+ {'EXIT',{function_clause,_}} = (catch do_supplies(#{1 => <<1,2,3>>})),
+ {'EXIT',{function_clause,_}} = (catch do_supplies(#{1 => a})),
+ {'EXIT',{function_clause,_}} = (catch do_supplies(42)),
+ ok
+ end.
+
+do_supplies(#{1 := Value}) when byte_size(Value), byte_size(kg) -> working.
+
id(I) -> I.
diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl
index 2962e3ff77..01c779b181 100644
--- a/lib/compiler/test/error_SUITE.erl
+++ b/lib/compiler/test/error_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
@@ -18,7 +18,7 @@
%% %CopyrightEnd%
-module(error_SUITE).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
@@ -65,7 +65,7 @@ bif_clashes(Config) when is_list(Config) ->
[return_warnings],
{error,
[{4, erl_lint,{call_to_redefined_old_bif,{length,1}}}], []} }],
- ?line [] = run(Config, Ts),
+ [] = run(Config, Ts),
Ts1 = [{bif_clashes2,
<<"
-export([t/0]).
@@ -76,7 +76,7 @@ bif_clashes(Config) when is_list(Config) ->
[return_warnings],
{error,
[{3, erl_lint,{redefine_old_bif_import,{length,1}}}], []} }],
- ?line [] = run(Config, Ts1),
+ [] = run(Config, Ts1),
Ts00 = [{bif_clashes3,
<<"
-export([t/0]).
@@ -89,7 +89,7 @@ bif_clashes(Config) when is_list(Config) ->
">>,
[return_warnings],
[]}],
- ?line [] = run(Config, Ts00),
+ [] = run(Config, Ts00),
Ts11 = [{bif_clashes4,
<<"
-export([t/0]).
@@ -100,7 +100,7 @@ bif_clashes(Config) when is_list(Config) ->
">>,
[return_warnings],
[]}],
- ?line [] = run(Config, Ts11),
+ [] = run(Config, Ts11),
Ts000 = [{bif_clashes5,
<<"
-export([t/0]).
@@ -113,7 +113,7 @@ bif_clashes(Config) when is_list(Config) ->
[return_warnings],
{warning,
[{4, erl_lint,{call_to_redefined_bif,{binary_part,3}}}]} }],
- ?line [] = run(Config, Ts000),
+ [] = run(Config, Ts000),
Ts111 = [{bif_clashes6,
<<"
-export([t/0]).
@@ -124,7 +124,7 @@ bif_clashes(Config) when is_list(Config) ->
[return_warnings],
{warning,
[{3, erl_lint,{redefine_bif_import,{binary_part,3}}}]} }],
- ?line [] = run(Config, Ts111),
+ [] = run(Config, Ts111),
Ts2 = [{bif_clashes7,
<<"
-export([t/0]).
@@ -139,7 +139,7 @@ bif_clashes(Config) when is_list(Config) ->
{error,
[{7,erl_lint,{define_import,{length,1}}}],
[]} }],
- ?line [] = run2(Config, Ts2),
+ [] = run2(Config, Ts2),
Ts3 = [{bif_clashes8,
<<"
-export([t/1]).
@@ -153,7 +153,7 @@ bif_clashes(Config) when is_list(Config) ->
{error,
[{4,erl_lint,{illegal_guard_local_call,{length,1}}}],
[]} }],
- ?line [] = run2(Config, Ts3),
+ [] = run2(Config, Ts3),
Ts4 = [{bif_clashes9,
<<"
-export([t/1]).
@@ -166,7 +166,7 @@ bif_clashes(Config) when is_list(Config) ->
{error,
[{5,erl_lint,{illegal_guard_local_call,{length,1}}}],
[]} }],
- ?line [] = run2(Config, Ts4),
+ [] = run2(Config, Ts4),
ok.
@@ -175,23 +175,23 @@ bif_clashes(Config) when is_list(Config) ->
%% Tests that a head mismatch is reported on the correct line (OTP-2125).
head_mismatch_line(Config) when is_list(Config) ->
- ?line [E|_] = get_compilation_errors(Config, "head_mismatch_line"),
- ?line {26, Mod, Reason} = E,
- ?line Mod:format_error(Reason),
+ [E|_] = get_compilation_errors(Config, "head_mismatch_line"),
+ {26, Mod, Reason} = E,
+ Mod:format_error(Reason),
ok.
%% Compiles a test file and returns the list of errors.
get_compilation_errors(Config, Filename) ->
- ?line DataDir = ?config(data_dir, Config),
- ?line File = filename:join(DataDir, Filename),
- ?line {error, [{_Name, E}|_], []} = compile:file(File, [return_errors]),
+ DataDir = proplists:get_value(data_dir, Config),
+ File = filename:join(DataDir, Filename),
+ {error, [{_Name, E}|_], []} = compile:file(File, [return_errors]),
E.
warnings_as_errors(Config) when is_list(Config) ->
- ?line TestFile = test_filename(Config),
- ?line BeamFile = filename:rootname(TestFile, ".erl") ++ ".beam",
- ?line OutDir = ?config(priv_dir, Config),
+ TestFile = test_filename(Config),
+ BeamFile = filename:rootname(TestFile, ".erl") ++ ".beam",
+ OutDir = proplists:get_value(priv_dir, Config),
Ts1 = [{warnings_as_errors,
<<"
@@ -203,8 +203,8 @@ warnings_as_errors(Config) when is_list(Config) ->
{error,
[],
[{3,erl_lint,{unused_var,'A'}}]} }],
- ?line [] = run(Ts1, TestFile, write_beam),
- ?line false = filelib:is_regular(BeamFile),
+ [] = run(Ts1, TestFile, write_beam),
+ false = filelib:is_regular(BeamFile),
Ts2 = [{warning_unused_var,
<<"
@@ -216,9 +216,9 @@ warnings_as_errors(Config) when is_list(Config) ->
{warning,
[{3,erl_lint,{unused_var,'A'}}]} }],
- ?line [] = run(Ts2, TestFile, write_beam),
- ?line true = filelib:is_regular(BeamFile),
- ?line ok = file:delete(BeamFile),
+ [] = run(Ts2, TestFile, write_beam),
+ true = filelib:is_regular(BeamFile),
+ ok = file:delete(BeamFile),
ok.
@@ -295,7 +295,7 @@ bad_utf8(Config) ->
run(Config, Tests) ->
- ?line File = test_filename(Config),
+ File = test_filename(Config),
run(Tests, File, dont_write_beam).
run(Tests, File, WriteBeam) ->
@@ -304,7 +304,7 @@ run(Tests, File, WriteBeam) ->
E ->
BadL;
Bad ->
- ?t:format("~nTest ~p failed. Expected~n ~p~n"
+ io:format("~nTest ~p failed. Expected~n ~p~n"
"but got~n ~p~n", [N, E, Bad]),
fail()
end
@@ -312,7 +312,7 @@ run(Tests, File, WriteBeam) ->
lists:foldl(F, [], Tests).
run2(Config, Tests) ->
- ?line File = test_filename(Config),
+ File = test_filename(Config),
run2(Tests, File, dont_write_beam).
run2(Tests, File, WriteBeam) ->
@@ -321,7 +321,7 @@ run2(Tests, File, WriteBeam) ->
E ->
BadL;
Bad ->
- ?t:format("~nTest ~p failed. Expected~n ~p~n"
+ io:format("~nTest ~p failed. Expected~n ~p~n"
"but got~n ~p~n", [N, E, Bad]),
fail()
end
@@ -338,56 +338,45 @@ filter(X) ->
test_filename(Conf) ->
Filename = ["errors_test_",test_lib:uniq(),".erl"],
- DataDir = ?config(priv_dir, Conf),
+ DataDir = proplists:get_value(priv_dir, Conf),
filename:join(DataDir, Filename).
run_test(Test0, File, Warnings, WriteBeam) ->
ModName = filename:rootname(filename:basename(File), ".erl"),
Mod = list_to_atom(ModName),
Test = ["-module(",ModName,"). ",Test0],
- ?line Opts = case WriteBeam of
- dont_write_beam ->
- [binary,return_errors|Warnings];
- write_beam ->
- [return_errors|Warnings]
- end,
- ?line ok = file:write_file(File, Test),
+ Opts = case WriteBeam of
+ dont_write_beam ->
+ [binary,return_errors|Warnings];
+ write_beam ->
+ [return_errors|Warnings]
+ end,
+ ok = file:write_file(File, Test),
%% Compile once just to print all errors and warnings.
- ?line compile:file(File, [binary,report|Warnings]),
+ compile:file(File, [binary,report|Warnings]),
%% Test result of compilation.
io:format("~p\n", [Opts]),
- ?line Res = case compile:file(File, Opts) of
- {ok,Mod,_,[{_File,Ws}]} ->
- %io:format("compile:file(~s,~p) ->~n~p~n",
- % [File,Opts,Ws]),
- {warning,Ws};
- {ok,Mod,_,[]} ->
- %io:format("compile:file(~s,~p) ->~n~p~n",
- % [File,Opts,Ws]),
- [];
- {ok,Mod,[{_File,Ws}]} ->
- {warning,Ws};
- {ok,Mod,[]} ->
- [];
- {error,[{XFile,Es}],Ws} = _ZZ when is_list(XFile) ->
- %io:format("compile:file(~s,~p) ->~n~p~n",
- % [File,Opts,_ZZ]),
- {error,Es,Ws};
- {error,[{XFile,Es1},{XFile,Es2}],Ws} = _ZZ
- when is_list(XFile) ->
- %io:format("compile:file(~s,~p) ->~n~p~n",
- % [File,Opts,_ZZ]),
- {error,Es1++Es2,Ws};
- {error,Es,[{_File,Ws}]} = _ZZ->
- %io:format("compile:file(~s,~p) ->~n~p~n",
- % [File,Opts,_ZZ]),
- {error,Es,Ws}
- end,
+ Res = case compile:file(File, Opts) of
+ {ok,Mod,_,[{_File,Ws}]} ->
+ {warning,Ws};
+ {ok,Mod,_,[]} ->
+ [];
+ {ok,Mod,[{_File,Ws}]} ->
+ {warning,Ws};
+ {ok,Mod,[]} ->
+ [];
+ {error,[{XFile,Es}],Ws} = _ZZ when is_list(XFile) ->
+ {error,Es,Ws};
+ {error,[{XFile,Es1},{XFile,Es2}],Ws} = _ZZ
+ when is_list(XFile) ->
+ {error,Es1++Es2,Ws};
+ {error,Es,[{_File,Ws}]} = _ZZ->
+ {error,Es,Ws}
+ end,
file:delete(File),
Res.
fail() ->
- io:format("failed~n"),
- ?t:fail().
+ ct:fail(failed).
diff --git a/lib/compiler/test/error_SUITE_data/head_mismatch_line.erl b/lib/compiler/test/error_SUITE_data/head_mismatch_line.erl
index 090f2fb829..5676d60daa 100644
--- a/lib/compiler/test/error_SUITE_data/head_mismatch_line.erl
+++ b/lib/compiler/test/error_SUITE_data/head_mismatch_line.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
diff --git a/lib/compiler/test/float_SUITE.erl b/lib/compiler/test/float_SUITE.erl
index 1b313ad021..08c3dd8593 100644
--- a/lib/compiler/test/float_SUITE.erl
+++ b/lib/compiler/test/float_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
init_per_group/2,end_per_group/2,
pending/1,bif_calls/1,math_functions/1,mixed_float_and_int/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -51,11 +51,11 @@ end_per_group(_GroupName, Config) ->
%% Shows the effect of pending exceptions on the x86.
pending(Config) when is_list(Config) ->
- ?line case catch float_mul(1, 1.1e300, 3.14e300) of
- {'EXIT',{badarith,_}} -> ok;
- Other -> ?t:fail({expected_exception,Other})
- end,
- ?line 0.0 = float_sub(2.0).
+ case catch float_mul(1, 1.1e300, 3.14e300) of
+ {'EXIT',{badarith,_}} -> ok;
+ Other -> ct:fail({expected_exception,Other})
+ end,
+ 0.0 = float_sub(2.0).
float_sub(A)->
catch A - 2.0.
@@ -69,11 +69,11 @@ float_mul(Iter, A, B) when is_float(A), is_float(B) ->
%% Thanks to Mikael Pettersson and Tobias Lindahl (HiPE).
bif_calls(Config) when is_list(Config) ->
- ?line {'EXIT',{badarith,_}} = (catch bad_arith(2.0, 1.7)),
- ?line {'EXIT',{badarith,_}} = (catch bad_arith_again(2.0, [])),
- ?line {'EXIT',{badarith,_}} = (catch bad_arith_xor(2.0, [])),
- ?line {'EXIT',{badarith,_}} = (catch bad_arith_hd(2.0, [])),
- ?line {'EXIT',{badarith,_}} = (catch bad_negate(2.0, 1.7)),
+ {'EXIT',{badarith,_}} = (catch bad_arith(2.0, 1.7)),
+ {'EXIT',{badarith,_}} = (catch bad_arith_again(2.0, [])),
+ {'EXIT',{badarith,_}} = (catch bad_arith_xor(2.0, [])),
+ {'EXIT',{badarith,_}} = (catch bad_arith_hd(2.0, [])),
+ {'EXIT',{badarith,_}} = (catch bad_negate(2.0, 1.7)),
ok.
bad_arith(X, Y) when is_float(X) ->
@@ -114,51 +114,63 @@ bad_negate(X, Y) when is_float(X) ->
math_functions(Config) when is_list(Config) ->
%% Mostly silly coverage.
- ?line 0.0 = math:tan(0),
- ?line 0.0 = math:atan2(0, 1),
- ?line 0.0 = math:sinh(0),
- ?line 1.0 = math:cosh(0),
- ?line 0.0 = math:tanh(0),
+ 0.0 = math:tan(0),
+ 0.0 = math:atan2(0, 1),
+ 0.0 = math:sinh(0),
+ 1.0 = math:cosh(0),
+ 0.0 = math:tanh(0),
1.0 = math:log2(2),
- ?line 1.0 = math:log10(10),
- ?line -1.0 = math:cos(math:pi()),
- ?line 1.0 = math:exp(0),
- ?line 1.0 = math:pow(math:pi(), 0),
- ?line 0.0 = math:log(1),
- ?line 0.0 = math:asin(0),
- ?line 0.0 = math:acos(1),
- ?line ?OPTIONAL(0.0, math:asinh(0)),
- ?line ?OPTIONAL(0.0, math:acosh(1)),
- ?line ?OPTIONAL(0.0, math:atanh(0)),
- ?line ?OPTIONAL(0.0, math:erf(0)),
- ?line ?OPTIONAL(1.0, math:erfc(0)),
-
- ?line 0.0 = math:tan(id(0)),
- ?line 0.0 = math:atan2(id(0), 1),
- ?line 0.0 = math:sinh(id(0)),
- ?line 1.0 = math:cosh(id(0)),
- ?line 0.0 = math:tanh(id(0)),
+ 1.0 = math:log10(10),
+ -1.0 = math:cos(math:pi()),
+ 1.0 = math:exp(0),
+ 1.0 = math:pow(math:pi(), 0),
+ 0.0 = math:log(1),
+ 0.0 = math:asin(0),
+ 0.0 = math:acos(1),
+ ?OPTIONAL(0.0, math:asinh(0)),
+ ?OPTIONAL(0.0, math:acosh(1)),
+ ?OPTIONAL(0.0, math:atanh(0)),
+ ?OPTIONAL(0.0, math:erf(0)),
+ ?OPTIONAL(1.0, math:erfc(0)),
+
+ 0.0 = math:tan(id(0)),
+ 0.0 = math:atan2(id(0), 1),
+ 0.0 = math:sinh(id(0)),
+ 1.0 = math:cosh(id(0)),
+ 0.0 = math:tanh(id(0)),
1.0 = math:log2(id(2)),
- ?line 1.0 = math:log10(id(10)),
- ?line 1.0 = math:exp(id(0)),
- ?line 0.0 = math:log(id(1)),
- ?line 0.0 = math:asin(id(0)),
- ?line 0.0 = math:acos(id(1)),
- ?line ?OPTIONAL(0.0, math:asinh(id(0))),
- ?line ?OPTIONAL(0.0, math:acosh(id(1))),
- ?line ?OPTIONAL(0.0, math:atanh(id(0))),
- ?line ?OPTIONAL(0.0, math:erf(id(0))),
- ?line ?OPTIONAL(1.0, math:erfc(id(0))),
+ 1.0 = math:log10(id(10)),
+ 1.0 = math:exp(id(0)),
+ 0.0 = math:log(id(1)),
+ 0.0 = math:asin(id(0)),
+ 0.0 = math:acos(id(1)),
+ ?OPTIONAL(0.0, math:asinh(id(0))),
+ ?OPTIONAL(0.0, math:acosh(id(1))),
+ ?OPTIONAL(0.0, math:atanh(id(0))),
+ ?OPTIONAL(0.0, math:erf(id(0))),
+ ?OPTIONAL(1.0, math:erfc(id(0))),
+
+ 5.0 = math:floor(5.6),
+ 6.0 = math:ceil(5.6),
+ 5.0 = math:floor(id(5.4)),
+ 6.0 = math:ceil(id(5.4)),
+
+ 0.0 = math:fmod(42, 42),
+ 0.25 = math:fmod(1, 0.75),
+ -1.0 = math:fmod(-4.0, 1.5),
+ -0.375 = math:fmod(-3.0, -0.875),
+ 0.125 = math:fmod(8.125, -4),
+ {'EXIT',{badarith,_}} = (catch math:fmod(5.0, 0.0)),
%% Only for coverage (of beam_type.erl).
- ?line {'EXIT',{undef,_}} = (catch math:fnurfla(0)),
- ?line {'EXIT',{undef,_}} = (catch math:fnurfla(0, 0)),
- ?line {'EXIT',{badarg,_}} = (catch float(kalle)),
- ?line {'EXIT',{badarith,_}} = (catch name/1),
+ {'EXIT',{undef,_}} = (catch math:fnurfla(0)),
+ {'EXIT',{undef,_}} = (catch math:fnurfla(0, 0)),
+ {'EXIT',{badarg,_}} = (catch float(kalle)),
+ {'EXIT',{badarith,_}} = (catch name/1),
ok.
mixed_float_and_int(Config) when is_list(Config) ->
- ?line 129.0 = pc(77, 23, 5),
+ 129.0 = pc(77, 23, 5),
ok.
pc(Cov, NotCov, X) ->
diff --git a/lib/compiler/test/fun_SUITE.erl b/lib/compiler/test/fun_SUITE.erl
index 36a4d6fce2..16474adf5b 100644
--- a/lib/compiler/test/fun_SUITE.erl
+++ b/lib/compiler/test/fun_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,21 +22,23 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
test1/1,overwritten_fun/1,otp_7202/1,bif_fun/1,
- external/1,eep37/1,eep37_dup/1,badarity/1]).
+ external/1,eep37/1,eep37_dup/1,badarity/1,badfun/1]).
%% Internal exports.
-export([call_me/1,dup1/0,dup2/0]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [test1,overwritten_fun,otp_7202,bif_fun,external,eep37,eep37_dup,badarity].
+ [{group,p}].
-groups() ->
- [].
+groups() ->
+ [{p,[parallel],
+ [test1,overwritten_fun,otp_7202,bif_fun,external,eep37,
+ eep37_dup,badarity,badfun]}].
init_per_suite(Config) ->
Config.
@@ -60,9 +62,8 @@ l1() ->
?T((begin G = fun(1=0) -> ok end, {'EXIT',_} = (catch G(2)), ok end), ok)
].
-test1(suite) -> [];
test1(Config) when is_list(Config) ->
- ?line lists:foreach(fun one_test/1, eval_list(l1(), [])),
+ lists:foreach(fun one_test/1, eval_list(l1(), [])),
ok.
evaluate(Str, Vars) ->
@@ -93,7 +94,7 @@ one_test({C, E, Str, Correct}) ->
true ->
io:format("ERROR: Compiled: ~p. Expected ~p. Got ~p.~n",
[Str, Correct, C]),
- test_server:fail(comp)
+ ct:fail(comp)
end,
if
E == Correct ->
@@ -101,7 +102,7 @@ one_test({C, E, Str, Correct}) ->
true ->
io:format("ERROR: Interpreted: ~p. Expected ~p. Got ~p.~n",
[Str, Correct, E]),
- test_server:fail(comp)
+ ct:fail(comp)
end.
-record(b, {c}).
@@ -109,9 +110,9 @@ one_test({C, E, Str, Correct}) ->
%% OTP-7102. (Thanks to Simon Cornish.)
overwritten_fun(Config) when is_list(Config) ->
- ?line {a2,a} = overwritten_fun_1(a),
- ?line {a2,{b,c}} = overwritten_fun_1(#b{c=c}),
- ?line one = overwritten_fun_1(#b{c=[]}),
+ {a2,a} = overwritten_fun_1(a),
+ {a2,{b,c}} = overwritten_fun_1(#b{c=c}),
+ one = overwritten_fun_1(#b{c=[]}),
ok.
overwritten_fun_1(A) ->
@@ -153,8 +154,8 @@ otp_7202_func() ->
no_value.
bif_fun(Config) when is_list(Config) ->
- ?line F = fun abs/1,
- ?line 5 = F(-5),
+ F = fun abs/1,
+ 5 = F(-5),
ok.
-define(APPLY(M, F, A), (fun(Fun) -> {ok,{a,b}} = Fun({a,b}) end)(fun M:F/A)).
@@ -222,5 +223,25 @@ badarity(Config) when is_list(Config) ->
{'EXIT',{{badarity,{_,[]}},_}} = (catch (fun badarity/1)()),
ok.
+badfun(_Config) ->
+ X = not_a_fun,
+ expect_badfun(42, catch 42()),
+ expect_badfun(42.0, catch 42.0(1)),
+ expect_badfun(X, catch X()),
+ expect_badfun(X, catch X(1)),
+ Len = length(atom_to_list(X)),
+ expect_badfun(Len, catch begin length(atom_to_list(X)) end(1)),
+
+ expect_badfun(42, catch 42(put(?FUNCTION_NAME, yes))),
+ yes = erase(?FUNCTION_NAME),
+
+ expect_badfun(X, catch X(put(?FUNCTION_NAME, of_course))),
+ of_course = erase(?FUNCTION_NAME),
+
+ ok.
+
+expect_badfun(Term, Exit) ->
+ {'EXIT',{{badfun,Term},_}} = Exit.
+
id(I) ->
I.
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index 47eb1ba78b..ccb9b58225 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2017. 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.
@@ -19,7 +19,7 @@
%%
-module(guard_SUITE).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
@@ -28,14 +28,14 @@
or_guard/1,more_or_guards/1,
complex_or_guards/1,and_guard/1,
xor_guard/1,more_xor_guards/1,
- old_guard_tests/1,
+ old_guard_tests/1,complex_guard/1,
build_in_guard/1,gbif/1,
t_is_boolean/1,is_function_2/1,
tricky/1,rel_ops/1,rel_op_combinations/1,literal_type_tests/1,
basic_andalso_orelse/1,traverse_dcd/1,
check_qlc_hrl/1,andalso_semi/1,t_tuple_size/1,binary_part/1,
- bad_constants/1,bad_guards/1,scotland/1,
- guard_in_catch/1]).
+ bad_constants/1,bad_guards/1,
+ guard_in_catch/1,beam_bool_SUITE/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -48,12 +48,13 @@ groups() ->
[misc,const_cond,basic_not,complex_not,nested_nots,
semicolon,complex_semicolon,comma,or_guard,
more_or_guards,complex_or_guards,and_guard,xor_guard,
- more_xor_guards,build_in_guard,old_guard_tests,gbif,
+ more_xor_guards,build_in_guard,
+ old_guard_tests,complex_guard,gbif,
t_is_boolean,is_function_2,tricky,
rel_ops,rel_op_combinations,
literal_type_tests,basic_andalso_orelse,traverse_dcd,
check_qlc_hrl,andalso_semi,t_tuple_size,binary_part,
- bad_constants,bad_guards,scotland,guard_in_catch]}].
+ bad_constants,bad_guards,guard_in_catch,beam_bool_SUITE]}].
init_per_suite(Config) ->
Config.
@@ -69,25 +70,49 @@ end_per_group(_GroupName, Config) ->
misc(Config) when is_list(Config) ->
- ?line 42 = case id(42) of
- X when -X -> ok;
- X -> X
- end,
- ?line {a,b,c} = misc_1([{{a,b,c}},{[4]},{[3]},{-2}]),
- ?line none = misc_1([{{a,b,c}},{[4]},{[3]},{-3}]),
- ?line none = misc_1([{{a,b,c}},{[4]},{[7]},{-2}]),
- ?line none = misc_1([{{a,b,c}},{[4]},{[3]},{[1,2,3]}]),
-
- ?line {ok,buf,<<>>} = get_data({o,true,raw}, 0, buf),
- ?line {ok,buf,<<>>} = get_data({o,true,raw}, 42, buf),
- ?line {ok,buf,<<>>} = get_data({o,false,raw}, 0, buf),
- ?line error = get_data({o,false,raw}, 42, buf),
- ?line {ok,buf,<<>>} = get_data({o,true,0}, 0, buf),
- ?line {ok,buf,<<>>} = get_data({o,true,0}, 42, buf),
- ?line {ok,buf,<<>>} = get_data({o,false,0}, 0, buf),
- ?line error = get_data({o,false,0}, 42, buf),
+ 42 = case id(42) of
+ X when -X -> ok;
+ X -> X
+ end,
+ {a,b,c} = misc_1([{{a,b,c}},{[4]},{[3]},{-2}]),
+ none = misc_1([{{a,b,c}},{[4]},{[3]},{-3}]),
+ none = misc_1([{{a,b,c}},{[4]},{[7]},{-2}]),
+ none = misc_1([{{a,b,c}},{[4]},{[3]},{[1,2,3]}]),
+
+ {ok,buf,<<>>} = get_data({o,true,raw}, 0, buf),
+ {ok,buf,<<>>} = get_data({o,true,raw}, 42, buf),
+ {ok,buf,<<>>} = get_data({o,false,raw}, 0, buf),
+ error = get_data({o,false,raw}, 42, buf),
+ {ok,buf,<<>>} = get_data({o,true,0}, 0, buf),
+ {ok,buf,<<>>} = get_data({o,true,0}, 42, buf),
+ {ok,buf,<<>>} = get_data({o,false,0}, 0, buf),
+ error = get_data({o,false,0}, 42, buf),
+
+ relief = misc_2(0),
+ error = misc_2(1),
+ error = misc_2(true),
+
+ if
+ is_integer(Config) =/= true ->
+ ok
+ end,
+
+ true = misc_3(1, 0),
+ true = misc_3(0, 0),
+ false = misc_3(0, 2),
+
+ %% Abuse of boolean values.
+
+ Zero = id(0),
+ One = id(1),
+ ok = if (Zero == 0) > false -> ok end,
+ ok = if (Zero == 0) =:= (One == 1) -> ok end,
+ ok = if (Zero == 0) =:= (One == 1) -> ok end,
+ ok = if is_atom(Zero > One) -> ok end,
+ error = if abs(Zero > One) -> ok; true -> error end,
+ ok = if is_integer(Zero) >= is_integer(One) -> ok end,
+
ok.
-
misc_1([{W},{X},{Y},{Z}]) ->
if
@@ -97,6 +122,17 @@ misc_1([{W},{X},{Y},{Z}]) ->
none
end.
+misc_2(0) -> relief;
+misc_2(Adapter = 1) when Adapter -> franklin;
+misc_2(_) -> error.
+
+misc_3(LenUp, LenDw) ->
+ if
+ %% Cover handling of #k_alt{}.
+ LenUp >= 1 orelse ((LenDw >= 2) xor true) -> true;
+ true -> false
+ end.
+
get_data({o,Active,Raw}, BytesToRead, Buffer)
when Raw =:= raw; Raw =:= 0 ->
if
@@ -107,11 +143,11 @@ get_data({o,Active,Raw}, BytesToRead, Buffer)
end.
const_cond(Config) when is_list(Config) ->
- ?line ok = const_cond({}, 0),
- ?line ok = const_cond({a}, 1),
- ?line error = const_cond({a,b}, 3),
- ?line error = const_cond({a}, 0),
- ?line error = const_cond({a,b}, 1),
+ ok = const_cond({}, 0),
+ ok = const_cond({a}, 1),
+ error = const_cond({a,b}, 3),
+ error = const_cond({a}, 0),
+ error = const_cond({a,b}, 1),
ok.
const_cond(T, Sz) ->
@@ -132,207 +168,282 @@ basic_not(Config) when is_list(Config) ->
D = id(5),
ATuple = {False,True,Glurf},
- ?line check(fun() -> if not false -> ok; true -> error end end, ok),
- ?line check(fun() -> if not true -> ok; true -> error end end, error),
- ?line check(fun() -> if not False -> ok; true -> error end end, ok),
- ?line check(fun() -> if not True -> ok; true -> error end end, error),
+ check(fun() -> if not false -> ok; true -> error end end, ok),
+ check(fun() -> if not true -> ok; true -> error end end, error),
+ check(fun() -> if not False -> ok; true -> error end end, ok),
+ check(fun() -> if not True -> ok; true -> error end end, error),
+
+ check(fun() -> if A > B -> gt; A < B -> lt; A == B -> eq end end, lt),
+ check(fun() -> if A > C -> gt; A < C -> lt; A == C -> eq end end, gt),
+ check(fun() -> if A > D -> gt; A < D -> lt; A == D -> eq end end, eq),
+
+ check(fun() -> if not (7 > 453) -> le; not (7 < 453) -> ge;
+ not (7 == 453) -> ne; true -> eq end end, le),
+ check(fun() -> if not (7 > -8) -> le; not (7 < -8) -> ge;
+ not (7 == -8) -> ne; true -> eq end end, ge),
+ check(fun() -> if not (7 > 7) -> le; not (7 < 7) -> ge;
+ not (7 == 7) -> ne; true -> eq end end, le),
- ?line check(fun() -> if A > B -> gt; A < B -> lt; A == B -> eq end end, lt),
- ?line check(fun() -> if A > C -> gt; A < C -> lt; A == C -> eq end end, gt),
- ?line check(fun() -> if A > D -> gt; A < D -> lt; A == D -> eq end end, eq),
+ check(fun() -> if not (A > B) -> le; not (A < B) -> ge;
+ not (A == B) -> ne; true -> eq end end, le),
+ check(fun() -> if not (A > C) -> le; not (A < C) -> ge;
+ not (A == C) -> ne; true -> eq end end, ge),
+ check(fun() -> if not (A > D) -> le; not (A < D) -> ge;
+ not (A == D) -> ne; true -> eq end end, le),
- ?line check(fun() -> if not (7 > 453) -> le; not (7 < 453) -> ge;
- not (7 == 453) -> ne; true -> eq end end, le),
- ?line check(fun() -> if not (7 > -8) -> le; not (7 < -8) -> ge;
- not (7 == -8) -> ne; true -> eq end end, ge),
- ?line check(fun() -> if not (7 > 7) -> le; not (7 < 7) -> ge;
- not (7 == 7) -> ne; true -> eq end end, le),
+ check(fun() -> if not element(1, ATuple) -> ok; true -> error end end, ok),
+ check(fun() -> if not element(2, ATuple) -> ok; true -> error end end, error),
+ check(fun() -> if not element(3, ATuple) -> ok; true -> error end end, error),
- ?line check(fun() -> if not (A > B) -> le; not (A < B) -> ge;
- not (A == B) -> ne; true -> eq end end, le),
- ?line check(fun() -> if not (A > C) -> le; not (A < C) -> ge;
- not (A == C) -> ne; true -> eq end end, ge),
- ?line check(fun() -> if not (A > D) -> le; not (A < D) -> ge;
- not (A == D) -> ne; true -> eq end end, le),
+ check(fun() -> if not glurf -> ok; true -> error end end, error),
+ check(fun() -> if not Glurf -> ok; true -> error end end, error),
- ?line check(fun() -> if not element(1, ATuple) -> ok; true -> error end end, ok),
- ?line check(fun() -> if not element(2, ATuple) -> ok; true -> error end end, error),
- ?line check(fun() -> if not element(3, ATuple) -> ok; true -> error end end, error),
+ check(fun() -> if not (not true) -> broken end end, broken),
- ?line check(fun() -> if not glurf -> ok; true -> error end end, error),
- ?line check(fun() -> if not Glurf -> ok; true -> error end end, error),
+ check(fun() -> if not (True xor True) -> ok end end, ok),
+ check(fun() -> if not (True xor False) -> ok;
+ true -> error end end, error),
ok.
complex_not(Config) when is_list(Config) ->
ATuple = id({false,true,gurka}),
- ?line check(fun() -> if not(element(1, ATuple)) -> ok; true -> error end end, ok),
- ?line check(fun() -> if not(element(2, ATuple)) -> ok; true -> error end end, error),
+ check(fun() -> if not(element(1, ATuple)) -> ok; true -> error end end, ok),
+ check(fun() -> if not(element(2, ATuple)) -> ok; true -> error end end, error),
- ?line check(fun() -> if not(element(3, ATuple) == gurka) -> ok;
- true -> error end end, error),
- ?line check(fun() -> if not(element(3, ATuple) =/= gurka) -> ok;
- true -> error end end, ok),
+ check(fun() -> if not(element(3, ATuple) == gurka) -> ok;
+ true -> error end end, error),
+ check(fun() -> if not(element(3, ATuple) =/= gurka) -> ok;
+ true -> error end end, ok),
- ?line check(fun() -> if {a,not(element(2, ATuple))} == {a,false} -> ok;
- true -> error end end, ok),
- ?line check(fun() -> if {a,not(element(1, ATuple))} == {a,false} -> ok;
- true -> error end end, error),
+ check(fun() -> if {a,not(element(2, ATuple))} == {a,false} -> ok;
+ true -> error end end, ok),
+ check(fun() -> if {a,not(element(1, ATuple))} == {a,false} -> ok;
+ true -> error end end, error),
- ?line check(fun() -> if not(element(1, ATuple) or element(3, ATuple)) -> ok;
- true -> error end end, error),
+ check(fun() -> if not(element(1, ATuple) or element(3, ATuple)) -> ok;
+ true -> error end end, error),
%% orelse
- ?line check(fun() -> if not(element(1, ATuple) orelse element(3, ATuple)) -> ok;
- true -> error end end, error),
+ check(fun() -> if not(element(1, ATuple) orelse element(3, ATuple)) -> ok;
+ true -> error end end, error),
+
+ %% complex_not_1/4
+ ok = complex_not_1(1, 1, 1, a),
+ error = complex_not_1(1, 1, 1, []),
+ error = complex_not_1(1, 1, 3, a),
+ error = complex_not_1(1, 1, 3, []),
+ error = complex_not_1(1, 2, 1, a),
+ error = complex_not_1(1, 2, 1, []),
+ error = complex_not_1(1, 2, 3, a),
+ error = complex_not_1(1, 2, 3, []),
+
+ %% complex_not_2/4
+ ok = complex_not_2(1, 2, 0, x),
+ error = complex_not_2(1, 2, 0, []),
+ error = complex_not_2(1, 2, 3, x),
+ error = complex_not_2(1, 2, 3, []),
+ error = complex_not_2(1, 1, 0, x),
+ error = complex_not_2(1, 1, 0, []),
+ error = complex_not_2(1, 1, 3, x),
+ error = complex_not_2(1, 1, 3, []),
ok.
+complex_not_1(A, B, C, D) ->
+ Res = complex_not_1a(A, B, C, D),
+ Res = complex_not_1b(A, B, C, D).
+
+complex_not_1a(A, B, C, D)
+ when (not (A < B)) andalso (not (B < C)) andalso (not is_list(D)) ->
+ ok;
+complex_not_1a(_, _, _, _) ->
+ error.
+
+complex_not_1b(A, B, C, D)
+ when (not (A < B)) and (not (B < C)) and (not is_list(D)) ->
+ ok;
+complex_not_1b(_, _, _, _) ->
+ error.
+
+complex_not_2(A, B, C, D) ->
+ Res = complex_not_2a(A, B, C, D),
+ Res = complex_not_2b(A, B, C, D).
+
+complex_not_2a(A, B, C, D)
+ when A < B andalso not (B < C) andalso not is_list(D) ->
+ ok;
+complex_not_2a(_, _, _, _) ->
+ error.
+
+complex_not_2b(A, B, C, D)
+ when A < B, not (B < C), not is_list(D) ->
+ ok;
+complex_not_2b(_, _, _, _) ->
+ error.
+
nested_nots(Config) when is_list(Config) ->
- ?line true = nested_not_1(0, 0),
- ?line true = nested_not_1(0, 1),
- ?line true = nested_not_1(a, b),
- ?line true = nested_not_1(10, 0),
- ?line false = nested_not_1(z, a),
- ?line false = nested_not_1(3.4, {anything,goes}),
- ?line false = nested_not_1(3.4, atom),
- ?line true = nested_not_1(3.0, [list]),
-
- ?line true = nested_not_2(false, false, 42),
- ?line true = nested_not_2(false, true, 42),
- ?line true = nested_not_2(true, false, 42),
- ?line true = nested_not_2(true, true, 42),
- ?line true = nested_not_2(false, false, atom),
- ?line false = nested_not_2(false, true, atom),
- ?line false = nested_not_2(true, false, atom),
- ?line false = nested_not_2(true, true, atom),
+ true = nested_not_1(0, 0),
+ true = nested_not_1(0, 1),
+ true = nested_not_1(a, b),
+ true = nested_not_1(10, 0),
+ false = nested_not_1(z, a),
+ false = nested_not_1(3.4, {anything,goes}),
+ false = nested_not_1(3.4, atom),
+ true = nested_not_1(3.0, [list]),
+
+ true = nested_not_2(false, false, 42),
+ true = nested_not_2(false, true, 42),
+ true = nested_not_2(true, false, 42),
+ true = nested_not_2(true, true, 42),
+ true = nested_not_2(false, false, atom),
+ false = nested_not_2(false, true, atom),
+ false = nested_not_2(true, false, atom),
+ false = nested_not_2(true, true, atom),
ok.
-nested_not_1(X, Y) when not (((X>Y) or not(is_atom(X))) and
+nested_not_1(X, Y) ->
+ Res = nested_not_1a(X, Y),
+ Res = nested_not_1b(X, Y).
+
+nested_not_1a(X, Y) when not (((X>Y) or not(is_atom(X))) and
(is_atom(Y) or (X==3.4))) ->
true;
-nested_not_1(_, _) ->
+nested_not_1a(_, _) ->
+ false.
+
+nested_not_1b(X, Y) when not (((X>Y) orelse not(is_atom(X))) andalso
+ (is_atom(Y) orelse (X==3.4))) ->
+ true;
+nested_not_1b(_, _) ->
false.
nested_not_2(X, Y, Z) ->
- nested_not_2(X, Y, Z, true).
+ Res = nested_not_2a(X, Y, Z, true),
+ Res = nested_not_2b(X, Y, Z, true).
-nested_not_2(X, Y, Z, True)
+nested_not_2a(X, Y, Z, True)
when not(True and not((not(X) and not(Y)) or not(is_atom(Z)))) ->
true;
-nested_not_2(_, _, _, _) ->
+nested_not_2a(_, _, _, _) ->
+ false.
+
+nested_not_2b(X, Y, Z, True)
+ when not(True andalso not((not(X) andalso not(Y)) orelse not(is_atom(Z)))) ->
+ true;
+nested_not_2b(_, _, _, _) ->
false.
semicolon(Config) when is_list(Config) ->
%% True/false combined using ';' (literal atoms).
- ?line check(fun() -> if true; false -> ok end end, ok),
- ?line check(fun() -> if false; true -> ok end end, ok),
- ?line check(fun() -> if true; true -> ok end end, ok),
- ?line check(fun() -> if false; false -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} = (catch if false; false -> ok end),
- exit
- end, exit),
+ check(fun() -> if true; false -> ok end end, ok),
+ check(fun() -> if false; true -> ok end end, ok),
+ check(fun() -> if true; true -> ok end end, ok),
+ check(fun() -> if false; false -> ok; true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} = (catch if false; false -> ok end),
+ exit
+ end, exit),
%% True/false combined used ';'.
True = id(true),
False = id(false),
- ?line check(fun() -> if True; False -> ok end end, ok),
- ?line check(fun() -> if False; True -> ok end end, ok),
- ?line check(fun() -> if True; True -> ok end end, ok),
- ?line check(fun() -> if False; False -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} = (catch if False; False -> ok end),
- exit
- end, exit),
+ check(fun() -> if True; False -> ok end end, ok),
+ check(fun() -> if False; True -> ok end end, ok),
+ check(fun() -> if True; True -> ok end end, ok),
+ check(fun() -> if False; False -> ok; true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} = (catch if False; False -> ok end),
+ exit
+ end, exit),
%% Combine true/false with a non-boolean value.
Glurf = id(glurf),
- ?line check(fun() -> if True; Glurf -> ok end end, ok),
- ?line check(fun() -> if Glurf; True -> ok end end, ok),
- ?line check(fun() -> if Glurf; Glurf -> ok; true -> error end end, error),
- ?line check(fun() -> if False; Glurf -> ok; true -> error end end, error),
- ?line check(fun() -> if Glurf; False -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} = (catch if Glurf; Glurf -> ok end),
- exit
- end, exit),
+ check(fun() -> if True; Glurf -> ok end end, ok),
+ check(fun() -> if Glurf; True -> ok end end, ok),
+ check(fun() -> if Glurf; Glurf -> ok; true -> error end end, error),
+ check(fun() -> if False; Glurf -> ok; true -> error end end, error),
+ check(fun() -> if Glurf; False -> ok; true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} = (catch if Glurf; Glurf -> ok end),
+ exit
+ end, exit),
%% Combine true/false with errors.
ATuple = id({false,true,gurka}),
- ?line check(fun() -> if True; element(42, ATuple) -> ok end end, ok),
- ?line check(fun() -> if element(42, ATuple); True -> ok end end, ok),
- ?line check(fun() -> if element(42, ATuple); element(42, ATuple) -> ok;
- true -> error end end, error),
- ?line check(fun() -> if False; element(42, ATuple) -> ok;
- true -> error end end, error),
- ?line check(fun() -> if element(42, ATuple);
- False -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} =
- (catch if element(42, ATuple);
- element(42, ATuple) -> ok end),
- exit
- end, exit),
+ check(fun() -> if True; element(42, ATuple) -> ok end end, ok),
+ check(fun() -> if element(42, ATuple); True -> ok end end, ok),
+ check(fun() -> if element(42, ATuple); element(42, ATuple) -> ok;
+ true -> error end end, error),
+ check(fun() -> if False; element(42, ATuple) -> ok;
+ true -> error end end, error),
+ check(fun() -> if element(42, ATuple);
+ False -> ok; true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} =
+ (catch if element(42, ATuple);
+ element(42, ATuple) -> ok end),
+ exit
+ end, exit),
ok.
complex_semicolon(Config) when is_list(Config) ->
- ?line ok = csemi1(int, {blurf}),
- ?line ok = csemi1(string, {blurf}),
- ?line ok = csemi1(float, [a]),
- ?line error = csemi1(35, 42),
+ ok = csemi1(int, {blurf}),
+ ok = csemi1(string, {blurf}),
+ ok = csemi1(float, [a]),
+ error = csemi1(35, 42),
%% 2
- ?line ok = csemi2({}, {a,b,c}),
- ?line ok = csemi2({1,3.5}, {a,b,c}),
- ?line ok = csemi2(dum, {a,b,c}),
+ ok = csemi2({}, {a,b,c}),
+ ok = csemi2({1,3.5}, {a,b,c}),
+ ok = csemi2(dum, {a,b,c}),
- ?line ok = csemi2({45,-19.3}, {}),
- ?line ok = csemi2({45,-19.3}, {dum}),
- ?line ok = csemi2({45,-19.3}, {dum,dum}),
+ ok = csemi2({45,-19.3}, {}),
+ ok = csemi2({45,-19.3}, {dum}),
+ ok = csemi2({45,-19.3}, {dum,dum}),
- ?line error = csemi2({45}, {dum}),
- ?line error = csemi2([], {dum}),
- ?line error = csemi2({dum}, []),
- ?line error = csemi2([], []),
+ error = csemi2({45}, {dum}),
+ error = csemi2([], {dum}),
+ error = csemi2({dum}, []),
+ error = csemi2([], []),
%% 3
- ?line csemi3(fun csemi3a/4),
- ?line csemi3(fun csemi3b/4),
- ?line csemi3(fun csemi3c/4),
+ csemi3(fun csemi3a/4),
+ csemi3(fun csemi3b/4),
+ csemi3(fun csemi3c/4),
%% 4
- ?line csemi4(fun csemi4a/4),
- ?line csemi4(fun csemi4b/4),
- ?line csemi4(fun csemi4c/4),
- ?line csemi4(fun csemi4d/4),
+ csemi4(fun csemi4a/4),
+ csemi4(fun csemi4b/4),
+ csemi4(fun csemi4c/4),
+ csemi4(fun csemi4d/4),
%% 4, 'orelse' instead of 'or'
- ?line csemi4_orelse(fun csemi4_orelse_a/4),
- ?line csemi4_orelse(fun csemi4_orelse_b/4),
- ?line csemi4_orelse(fun csemi4_orelse_c/4),
- ?line csemi4_orelse(fun csemi4_orelse_d/4),
+ csemi4_orelse(fun csemi4_orelse_a/4),
+ csemi4_orelse(fun csemi4_orelse_b/4),
+ csemi4_orelse(fun csemi4_orelse_c/4),
+ csemi4_orelse(fun csemi4_orelse_d/4),
%% 5
- ?line error = csemi5(0, 0),
- ?line ok = csemi5(5, 0),
- ?line ok = csemi5(4, -4),
- ?line ok = csemi5(10, -4),
+ error = csemi5(0, 0),
+ ok = csemi5(5, 0),
+ ok = csemi5(4, -4),
+ ok = csemi5(10, -4),
%% 6
- ?line error = csemi6({a}, 0),
- ?line ok = csemi6({a,b}, 0),
- ?line ok = csemi6({}, 3),
- ?line ok = csemi6({a,b,c}, 3),
+ error = csemi6({a}, 0),
+ ok = csemi6({a,b}, 0),
+ ok = csemi6({}, 3),
+ ok = csemi6({a,b,c}, 3),
%% 7
error = csemi7(#{a=>1}, 1, 0),
@@ -342,6 +453,11 @@ complex_semicolon(Config) when is_list(Config) ->
ok = csemi7(#{a=>1}, 3, 3),
ok = csemi7(#{a=>1, b=>3}, 0, 0),
+ %% 8: Make sure that funs cannot be copied into guards.
+ ok = csemi8(true),
+ error = csemi8(false),
+ error = csemi8(42),
+
ok.
csemi1(Type, Val) when is_list(Val), Type == float;
@@ -427,7 +543,7 @@ csemi4_orelse(Test) ->
ok = Test({}, 2, blurf, 0),
ok = Test({}, 2, {1}, 2),
- ?line error = Test([], 1, {}, 0),
+ error = Test([], 1, {}, 0),
ok.
@@ -456,76 +572,83 @@ csemi6(_, _) -> error.
csemi7(A, B, C) when A#{a:=B} > #{a=>1}; abs(C) > 2 -> ok;
csemi7(_, _, _) -> error.
+csemi8(Together) ->
+ case fun csemi8/1 of
+ Typically when Together; Typically, Together -> ok;
+ _ -> error
+ end.
+
+
comma(Config) when is_list(Config) ->
%% ',' combinations of literal true/false.
- ?line check(fun() -> if true, false -> ok; true -> error end end, error),
- ?line check(fun() -> if false, true -> ok; true -> error end end, error),
- ?line check(fun() -> if true, true -> ok end end, ok),
- ?line check(fun() -> if false, false -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} =
- (catch if true, false -> ok;
- false, true -> ok;
- false, false -> ok
- end),
- exit
- end, exit),
+ check(fun() -> if true, false -> ok; true -> error end end, error),
+ check(fun() -> if false, true -> ok; true -> error end end, error),
+ check(fun() -> if true, true -> ok end end, ok),
+ check(fun() -> if false, false -> ok; true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} =
+ (catch if true, false -> ok;
+ false, true -> ok;
+ false, false -> ok
+ end),
+ exit
+ end, exit),
%% ',' combinations of true/false in variables.
True = id(true),
False = id(false),
- ?line check(fun() -> if True, False -> ok; true -> error end end, error),
- ?line check(fun() -> if False, True -> ok; true -> error end end, error),
- ?line check(fun() -> if True, True -> ok end end, ok),
- ?line check(fun() -> if False, False -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} =
- (catch if True, False -> ok;
- False, True -> ok;
- False, False -> ok
- end),
- exit
- end, exit),
+ check(fun() -> if True, False -> ok; true -> error end end, error),
+ check(fun() -> if False, True -> ok; true -> error end end, error),
+ check(fun() -> if True, True -> ok end end, ok),
+ check(fun() -> if False, False -> ok; true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} =
+ (catch if True, False -> ok;
+ False, True -> ok;
+ False, False -> ok
+ end),
+ exit
+ end, exit),
%% ',' combinations of true/false, and non-boolean in variables.
Glurf = id(glurf),
- ?line check(fun() -> if True, Glurf -> ok; true -> error end end, error),
- ?line check(fun() -> if Glurf, True -> ok; true -> error end end, error),
- ?line check(fun() -> if True, True -> ok end end, ok),
- ?line check(fun() -> if Glurf, Glurf -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} =
- (catch if True, Glurf -> ok;
- Glurf, True -> ok;
- Glurf, Glurf -> ok
- end),
- exit
- end, exit),
+ check(fun() -> if True, Glurf -> ok; true -> error end end, error),
+ check(fun() -> if Glurf, True -> ok; true -> error end end, error),
+ check(fun() -> if True, True -> ok end end, ok),
+ check(fun() -> if Glurf, Glurf -> ok; true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} =
+ (catch if True, Glurf -> ok;
+ Glurf, True -> ok;
+ Glurf, Glurf -> ok
+ end),
+ exit
+ end, exit),
%% ',' combinations of true/false with errors.
ATuple = id({a,b,c}),
- ?line check(fun() -> if True, element(42, ATuple) -> ok;
- true -> error end end, error),
- ?line check(fun() -> if element(42, ATuple), True -> ok;
- true -> error end end, error),
- ?line check(fun() -> if True, True -> ok end end, ok),
- ?line check(fun() -> if element(42, ATuple), element(42, ATuple) -> ok;
- true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} =
- (catch if True, element(42, ATuple) -> ok;
- element(42, ATuple), True -> ok;
- element(42, ATuple), element(42, ATuple) -> ok
- end),
- exit
- end, exit),
+ check(fun() -> if True, element(42, ATuple) -> ok;
+ true -> error end end, error),
+ check(fun() -> if element(42, ATuple), True -> ok;
+ true -> error end end, error),
+ check(fun() -> if True, True -> ok end end, ok),
+ check(fun() -> if element(42, ATuple), element(42, ATuple) -> ok;
+ true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} =
+ (catch if True, element(42, ATuple) -> ok;
+ element(42, ATuple), True -> ok;
+ element(42, ATuple), element(42, ATuple) -> ok
+ end),
+ exit
+ end, exit),
ok.
@@ -535,35 +658,35 @@ or_guard(Config) when is_list(Config) ->
Glurf = id(glurf),
%% 'or' combinations of literal true/false.
- ?line check(fun() -> if true or false -> ok end end, ok),
- ?line check(fun() -> if false or true -> ok end end, ok),
- ?line check(fun() -> if true or true -> ok end end, ok),
- ?line check(fun() -> if false or false -> ok; true -> error end end, error),
+ check(fun() -> if true or false -> ok end end, ok),
+ check(fun() -> if false or true -> ok end end, ok),
+ check(fun() -> if true or true -> ok end end, ok),
+ check(fun() -> if false or false -> ok; true -> error end end, error),
- ?line check(fun() -> if glurf or true -> ok; true -> error end end, error),
- ?line check(fun() -> if true or glurf -> ok; true -> error end end, error),
- ?line check(fun() -> if glurf or glurf -> ok; true -> error end end, error),
+ check(fun() -> if glurf or true -> ok; true -> error end end, error),
+ check(fun() -> if true or glurf -> ok; true -> error end end, error),
+ check(fun() -> if glurf or glurf -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} = (catch if false or false -> ok end),
- exit
- end, exit),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} = (catch if false or false -> ok end),
+ exit
+ end, exit),
%% 'or' combinations using variables containing true/false.
- ?line check(fun() -> if True or False -> ok end end, ok),
- ?line check(fun() -> if False or True -> ok end end, ok),
- ?line check(fun() -> if True or True -> ok end end, ok),
- ?line check(fun() -> if False or False -> ok; true -> error end end, error),
+ check(fun() -> if True or False -> ok end end, ok),
+ check(fun() -> if False or True -> ok end end, ok),
+ check(fun() -> if True or True -> ok end end, ok),
+ check(fun() -> if False or False -> ok; true -> error end end, error),
- ?line check(fun() -> if True or Glurf -> ok; true -> error end end, error),
- ?line check(fun() -> if Glurf or True -> ok; true -> error end end, error),
- ?line check(fun() -> if Glurf or Glurf -> ok; true -> error end end, error),
+ check(fun() -> if True or Glurf -> ok; true -> error end end, error),
+ check(fun() -> if Glurf or True -> ok; true -> error end end, error),
+ check(fun() -> if Glurf or Glurf -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} = (catch if False or False -> ok end),
- exit
- end, exit),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} = (catch if False or False -> ok end),
+ exit
+ end, exit),
ok.
@@ -572,142 +695,142 @@ more_or_guards(Config) when is_list(Config) ->
False = id(false),
ATuple = id({false,true,gurka}),
- ?line check(fun() ->
- if element(42, ATuple) or False -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if False or element(42, ATuple) -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if element(18, ATuple) or element(42, ATuple) -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if True or element(42, ATuple) -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if element(42, ATuple) or True -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if element(1, ATuple) or element(42, ATuple) or True -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if element(1, ATuple) or True or element(42, ATuple) -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if
- (<<False:8>> == <<0>>) or element(2, ATuple) -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if
- element(2, ATuple) or (<<True:8>> == <<1>>) -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if element(2, ATuple) or element(42, ATuple) -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if
- element(1, ATuple) or
- element(2, ATuple) or
- element(19, ATuple) -> ok;
- true -> error end
- end, error),
+ check(fun() ->
+ if element(42, ATuple) or False -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if False or element(42, ATuple) -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if element(18, ATuple) or element(42, ATuple) -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if True or element(42, ATuple) -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if element(42, ATuple) or True -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if element(1, ATuple) or element(42, ATuple) or True -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if element(1, ATuple) or True or element(42, ATuple) -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if
+ (<<False:8>> == <<0>>) or element(2, ATuple) -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if
+ element(2, ATuple) or (<<True:8>> == <<1>>) -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if element(2, ATuple) or element(42, ATuple) -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if
+ element(1, ATuple) or
+ element(2, ATuple) or
+ element(19, ATuple) -> ok;
+ true -> error end
+ end, error),
ok.
complex_or_guards(Config) when is_list(Config) ->
%% complex_or_1/2
- ?line ok = complex_or_1({a,b,c,d}, {1,2,3}),
- ?line ok = complex_or_1({a,b,c,d}, {1}),
- ?line ok = complex_or_1({a}, {1,2,3}),
- ?line error = complex_or_1({a}, {1}),
+ ok = complex_or_1({a,b,c,d}, {1,2,3}),
+ ok = complex_or_1({a,b,c,d}, {1}),
+ ok = complex_or_1({a}, {1,2,3}),
+ error = complex_or_1({a}, {1}),
- ?line error = complex_or_1(1, 2),
- ?line error = complex_or_1([], {a,b,c,d}),
- ?line error = complex_or_1({a,b,c,d}, []),
+ error = complex_or_1(1, 2),
+ error = complex_or_1([], {a,b,c,d}),
+ error = complex_or_1({a,b,c,d}, []),
%% complex_or_2/1
- ?line ok = complex_or_2({true,{}}),
- ?line ok = complex_or_2({false,{a}}),
- ?line ok = complex_or_2({false,{a,b,c}}),
- ?line ok = complex_or_2({true,{a,b,c,d}}),
+ ok = complex_or_2({true,{}}),
+ ok = complex_or_2({false,{a}}),
+ ok = complex_or_2({false,{a,b,c}}),
+ ok = complex_or_2({true,{a,b,c,d}}),
- ?line error = complex_or_2({blurf,{a,b,c}}),
+ error = complex_or_2({blurf,{a,b,c}}),
- ?line error = complex_or_2({true}),
- ?line error = complex_or_2({true,no_tuple}),
- ?line error = complex_or_2({true,[]}),
+ error = complex_or_2({true}),
+ error = complex_or_2({true,no_tuple}),
+ error = complex_or_2({true,[]}),
%% complex_or_3/2
- ?line ok = complex_or_3({true}, {}),
- ?line ok = complex_or_3({false}, {a}),
- ?line ok = complex_or_3({false}, {a,b,c}),
- ?line ok = complex_or_3({true}, {a,b,c,d}),
- ?line ok = complex_or_3({false}, <<1,2,3>>),
- ?line ok = complex_or_3({true}, <<1,2,3,4>>),
+ ok = complex_or_3({true}, {}),
+ ok = complex_or_3({false}, {a}),
+ ok = complex_or_3({false}, {a,b,c}),
+ ok = complex_or_3({true}, {a,b,c,d}),
+ ok = complex_or_3({false}, <<1,2,3>>),
+ ok = complex_or_3({true}, <<1,2,3,4>>),
- ?line error = complex_or_3(blurf, {a,b,c}),
+ error = complex_or_3(blurf, {a,b,c}),
- ?line error = complex_or_3({false}, <<1,2,3,4>>),
- ?line error = complex_or_3([], <<1,2>>),
- ?line error = complex_or_3({true}, 45),
- ?line error = complex_or_3(<<>>, <<>>),
+ error = complex_or_3({false}, <<1,2,3,4>>),
+ error = complex_or_3([], <<1,2>>),
+ error = complex_or_3({true}, 45),
+ error = complex_or_3(<<>>, <<>>),
%% complex_or_4/2
- ?line ok = complex_or_4(<<1,2,3>>, {true}),
- ?line ok = complex_or_4(<<1,2,3>>, {false}),
- ?line ok = complex_or_4(<<1,2,3>>, {true}),
- ?line ok = complex_or_4({1,2,3}, {true}),
- ?line error = complex_or_4({1,2,3,4}, {false}),
+ ok = complex_or_4(<<1,2,3>>, {true}),
+ ok = complex_or_4(<<1,2,3>>, {false}),
+ ok = complex_or_4(<<1,2,3>>, {true}),
+ ok = complex_or_4({1,2,3}, {true}),
+ error = complex_or_4({1,2,3,4}, {false}),
- ?line error = complex_or_4(<<1,2,3,4>>, []),
- ?line error = complex_or_4([], {true}),
+ error = complex_or_4(<<1,2,3,4>>, []),
+ error = complex_or_4([], {true}),
%% complex_or_5/2
- ?line ok = complex_or_5(<<1>>, {false}),
- ?line ok = complex_or_5(<<1,2,3>>, {true}),
- ?line ok = complex_or_5(<<1,2,3,4>>, {false}),
- ?line ok = complex_or_5({1,2,3}, {false}),
- ?line ok = complex_or_5({1,2,3,4}, {false}),
+ ok = complex_or_5(<<1>>, {false}),
+ ok = complex_or_5(<<1,2,3>>, {true}),
+ ok = complex_or_5(<<1,2,3,4>>, {false}),
+ ok = complex_or_5({1,2,3}, {false}),
+ ok = complex_or_5({1,2,3,4}, {false}),
- ?line error = complex_or_5(blurf, {false}),
- ?line error = complex_or_5(<<1>>, klarf),
- ?line error = complex_or_5(blurf, klarf),
+ error = complex_or_5(blurf, {false}),
+ error = complex_or_5(<<1>>, klarf),
+ error = complex_or_5(blurf, klarf),
%% complex_or_6/2
- ?line ok = complex_or_6({true,true}, {1,2,3,4}),
- ?line ok = complex_or_6({true,true}, <<1,2,3,4>>),
- ?line ok = complex_or_6({false,false}, <<1,2,3,4>>),
- ?line ok = complex_or_6({false,true}, <<1>>),
- ?line ok = complex_or_6({true,false}, {1}),
- ?line ok = complex_or_6({true,true}, {1}),
+ ok = complex_or_6({true,true}, {1,2,3,4}),
+ ok = complex_or_6({true,true}, <<1,2,3,4>>),
+ ok = complex_or_6({false,false}, <<1,2,3,4>>),
+ ok = complex_or_6({false,true}, <<1>>),
+ ok = complex_or_6({true,false}, {1}),
+ ok = complex_or_6({true,true}, {1}),
- ?line error = complex_or_6({false,false}, {1}),
+ error = complex_or_6({false,false}, {1}),
- ?line error = complex_or_6({true}, {1,2,3,4}),
- ?line error = complex_or_6({}, {1,2,3,4}),
- ?line error = complex_or_6([], {1,2,3,4}),
- ?line error = complex_or_6([], {1,2,3,4}),
- ?line error = complex_or_6({true,false}, klurf),
+ error = complex_or_6({true}, {1,2,3,4}),
+ error = complex_or_6({}, {1,2,3,4}),
+ error = complex_or_6([], {1,2,3,4}),
+ error = complex_or_6([], {1,2,3,4}),
+ error = complex_or_6({true,false}, klurf),
ok.
@@ -753,79 +876,79 @@ and_guard(Config) when is_list(Config) ->
%% 'and' combinations of literal true/false.
- ?line check(fun() -> if true and false -> ok; true -> error end end, error),
- ?line check(fun() -> if false and true -> ok; true -> error end end, error),
- ?line check(fun() -> if true and true -> ok end end, ok),
- ?line check(fun() -> if false and false -> ok; true -> error end end, error),
-
- ?line check(fun() -> if glurf and true -> ok; true -> error end end, error),
- ?line check(fun() -> if true and glurf -> ok; true -> error end end, error),
- ?line check(fun() -> if glurf and glurf -> ok; true -> error end end, error),
-
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} =
- (catch if true and false -> ok;
- false and true -> ok;
- false and false -> ok
- end),
- exit
- end, exit),
+ check(fun() -> if true and false -> ok; true -> error end end, error),
+ check(fun() -> if false and true -> ok; true -> error end end, error),
+ check(fun() -> if true and true -> ok end end, ok),
+ check(fun() -> if false and false -> ok; true -> error end end, error),
+
+ check(fun() -> if glurf and true -> ok; true -> error end end, error),
+ check(fun() -> if true and glurf -> ok; true -> error end end, error),
+ check(fun() -> if glurf and glurf -> ok; true -> error end end, error),
+
+ check(fun() ->
+ {'EXIT',{if_clause,_}} =
+ (catch if true and false -> ok;
+ false and true -> ok;
+ false and false -> ok
+ end),
+ exit
+ end, exit),
%% 'and' combinations of true/false in variables.
True = id(true),
False = id(false),
- ?line check(fun() -> if True and False -> ok; true -> error end end, error),
- ?line check(fun() -> if False and True -> ok; true -> error end end, error),
- ?line check(fun() -> if True and True -> ok end end, ok),
- ?line check(fun() -> if False and False -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} =
- (catch if True and False -> ok;
- False and True -> ok;
- False and False -> ok
- end),
- exit
- end, exit),
+ check(fun() -> if True and False -> ok; true -> error end end, error),
+ check(fun() -> if False and True -> ok; true -> error end end, error),
+ check(fun() -> if True and True -> ok end end, ok),
+ check(fun() -> if False and False -> ok; true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} =
+ (catch if True and False -> ok;
+ False and True -> ok;
+ False and False -> ok
+ end),
+ exit
+ end, exit),
%% 'and' combinations of true/false and a non-boolean in variables.
Glurf = id(glurf),
- ?line check(fun() -> if True and Glurf -> ok; true -> error end end, error),
- ?line check(fun() -> if Glurf and True -> ok; true -> error end end, error),
- ?line check(fun() -> if True and True -> ok end end, ok),
- ?line check(fun() -> if Glurf and Glurf -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} =
- (catch if True and Glurf -> ok;
- Glurf and True -> ok;
- Glurf and Glurf -> ok
- end),
- exit
- end, exit),
+ check(fun() -> if True and Glurf -> ok; true -> error end end, error),
+ check(fun() -> if Glurf and True -> ok; true -> error end end, error),
+ check(fun() -> if True and True -> ok end end, ok),
+ check(fun() -> if Glurf and Glurf -> ok; true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} =
+ (catch if True and Glurf -> ok;
+ Glurf and True -> ok;
+ Glurf and Glurf -> ok
+ end),
+ exit
+ end, exit),
%% 'and' combinations of true/false with errors.
ATuple = id({a,b,c}),
- ?line check(fun() -> if True and element(42, ATuple) -> ok;
- true -> error end end, error),
- ?line check(fun() -> if element(42, ATuple) and True -> ok;
- true -> error end end, error),
- ?line check(fun() -> if True and True -> ok end end, ok),
- ?line check(fun() -> if element(42, ATuple) and element(42, ATuple) -> ok;
- true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} =
- (catch if True and element(42, ATuple) -> ok;
- element(42, ATuple) and True -> ok;
- element(42, ATuple) and element(42, ATuple) -> ok
- end),
+ check(fun() -> if True and element(42, ATuple) -> ok;
+ true -> error end end, error),
+ check(fun() -> if element(42, ATuple) and True -> ok;
+ true -> error end end, error),
+ check(fun() -> if True and True -> ok end end, ok),
+ check(fun() -> if element(42, ATuple) and element(42, ATuple) -> ok;
+ true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} =
+ (catch if True and element(42, ATuple) -> ok;
+ element(42, ATuple) and True -> ok;
+ element(42, ATuple) and element(42, ATuple) -> ok
+ end),
exit
end, exit),
- ?line ok = relprod({'Set',a,b}, {'Set',a,b}),
+ ok = relprod({'Set',a,b}, {'Set',a,b}),
ok = and_same_var(42),
{'EXIT',{if_clause,_}} = (catch and_same_var(x)),
@@ -844,18 +967,18 @@ relprod(R1, R2) when (erlang:size(R1) =:= 3) and (erlang:element(1,R1) =:= 'Set'
xor_guard(Config) when is_list(Config) ->
%% 'xor' combinations of literal true/false.
- ?line check(fun() -> if true xor false -> ok end end, ok),
- ?line check(fun() -> if false xor true -> ok end end, ok),
- ?line check(fun() -> if true xor true -> ok; true -> error end end, error),
- ?line check(fun() -> if false xor false -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} = (catch if false xor false -> ok end),
- exit
- end, exit),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} = (catch if true xor true -> ok end),
- exit
- end, exit),
+ check(fun() -> if true xor false -> ok end end, ok),
+ check(fun() -> if false xor true -> ok end end, ok),
+ check(fun() -> if true xor true -> ok; true -> error end end, error),
+ check(fun() -> if false xor false -> ok; true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} = (catch if false xor false -> ok end),
+ exit
+ end, exit),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} = (catch if true xor true -> ok end),
+ exit
+ end, exit),
%% 'xor' combinations using variables containing true/false.
@@ -863,18 +986,18 @@ xor_guard(Config) when is_list(Config) ->
True = id(true),
False = id(false),
- ?line check(fun() -> if True xor False -> ok end end, ok),
- ?line check(fun() -> if False xor True -> ok end end, ok),
- ?line check(fun() -> if True xor True -> ok; true -> error end end, error),
- ?line check(fun() -> if False xor False -> ok; true -> error end end, error),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} = (catch if False xor False -> ok end),
- exit
- end, exit),
- ?line check(fun() ->
- {'EXIT',{if_clause,_}} = (catch if True xor True -> ok end),
- exit
- end, exit),
+ check(fun() -> if True xor False -> ok end end, ok),
+ check(fun() -> if False xor True -> ok end end, ok),
+ check(fun() -> if True xor True -> ok; true -> error end end, error),
+ check(fun() -> if False xor False -> ok; true -> error end end, error),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} = (catch if False xor False -> ok end),
+ exit
+ end, exit),
+ check(fun() ->
+ {'EXIT',{if_clause,_}} = (catch if True xor True -> ok end),
+ exit
+ end, exit),
ok.
@@ -883,53 +1006,53 @@ more_xor_guards(Config) when is_list(Config) ->
False = id(false),
ATuple = id({false,true,gurka}),
- ?line check(fun() ->
- if element(42, ATuple) xor False -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if False xor element(42, ATuple) xor False -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if element(18, ATuple) xor element(42, ATuple) -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if True xor element(42, ATuple) -> ok;
- true -> error end
- end, error),
-
- ?line check(fun() ->
- if element(42, ATuple) xor True -> ok;
- true -> error end
- end, error),
+ check(fun() ->
+ if element(42, ATuple) xor False -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if False xor element(42, ATuple) xor False -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if element(18, ATuple) xor element(42, ATuple) -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if True xor element(42, ATuple) -> ok;
+ true -> error end
+ end, error),
+
+ check(fun() ->
+ if element(42, ATuple) xor True -> ok;
+ true -> error end
+ end, error),
ok.
build_in_guard(Config) when is_list(Config) ->
SubBin = <<5.0/float>>,
- ?line B = <<1,SubBin/binary,3.5/float>>,
- ?line if
- B =:= <<1,SubBin/binary,3.5/float>> -> ok
- end.
+ B = <<1,SubBin/binary,3.5/float>>,
+ if
+ B =:= <<1,SubBin/binary,3.5/float>> -> ok
+ end.
old_guard_tests(Config) when list(Config) ->
%% Check that all the old guard tests are still recognized.
- ?line list = og(Config),
- ?line atom = og(an_atom),
- ?line binary = og(<<1,2>>),
- ?line float = og(3.14),
- ?line integer = og(43),
- ?line a_function = og(fun() -> ok end),
- ?line pid = og(self()),
- ?line reference = og(make_ref()),
- ?line tuple = og({}),
-
- ?line number = on(45.333),
- ?line number = on(-19),
+ list = og(Config),
+ atom = og(an_atom),
+ binary = og(<<1,2>>),
+ float = og(3.14),
+ integer = og(43),
+ a_function = og(fun() -> ok end),
+ pid = og(self()),
+ reference = og(make_ref()),
+ tuple = og({}),
+
+ number = on(45.333),
+ number = on(-19),
ok.
og(V) when atom(V) -> atom;
@@ -947,9 +1070,29 @@ og(_) -> what.
on(V) when number(V) -> number;
on(_) -> not_number.
+complex_guard(_Config) ->
+ _ = [true = do_complex_guard(X, Y, Z) ||
+ X <- [4,5], Y <- [4,5], Z <- [4,5]],
+ _ = [true = do_complex_guard(X, Y, Z) ||
+ X <- [1,2,3], Y <- [1,2,3], Z <- [1,2,3]],
+ _ = [catch do_complex_guard(X, Y, Z) ||
+ X <- [1,2,3,4,5], Y <- [0,6], Z <- [1,2,3,4,5]],
+ ok.
+
+do_complex_guard(X1, Y1, Z1) ->
+ if
+ ((X1 =:= 4) or (X1 =:= 5)) and
+ ((Y1 =:= 4) or (Y1 =:= 5)) and
+ ((Z1 =:= 4) or (Z1 =:= 5)) or
+ ((X1 =:= 1) or (X1 =:= 2) or (X1 =:= 3)) and
+ ((Y1 =:= 1) or (Y1 =:= 2) or (Y1 =:= 3)) and
+ ((Z1 =:= 1) or (Z1 =:= 2) or (Z1 =:= 3)) ->
+ true
+ end.
+
gbif(Config) when is_list(Config) ->
- ?line error = gbif_1(1, {false,true}),
- ?line ok = gbif_1(2, {false,true}),
+ error = gbif_1(1, {false,true}),
+ ok = gbif_1(2, {false,true}),
ok.
gbif_1(P, T) when element(P, T) -> ok;
@@ -957,57 +1100,57 @@ gbif_1(_, _) -> error.
t_is_boolean(Config) when is_list(Config) ->
- ?line true = is_boolean(true),
- ?line true = is_boolean(false),
- ?line true = is_boolean(id(true)),
- ?line true = is_boolean(id(false)),
-
- ?line false = is_boolean(glurf),
- ?line false = is_boolean(id(glurf)),
-
- ?line false = is_boolean([]),
- ?line false = is_boolean(id([])),
- ?line false = is_boolean(42),
- ?line false = is_boolean(id(-42)),
-
- ?line false = is_boolean(math:pi()),
- ?line false = is_boolean(384793478934378924978439789873478934897),
-
- ?line false = is_boolean(id(self())),
- ?line false = is_boolean(id({x,y,z})),
- ?line false = is_boolean(id([a,b,c])),
- ?line false = is_boolean(id(make_ref())),
- ?line false = is_boolean(id(<<1,2,3>>)),
- ?line false = is_boolean({id(x),y,z}),
- ?line false = is_boolean([id(a),b,c]),
-
- ?line ok = bool(true),
- ?line ok = bool(false),
- ?line ok = bool(id(true)),
- ?line ok = bool(id(false)),
-
- ?line error = bool(glurf),
- ?line error = bool(id(glurf)),
-
- ?line error = bool([]),
- ?line error = bool(id([])),
- ?line error = bool(42),
- ?line error = bool(id(-42)),
-
- ?line error = bool(math:pi()),
- ?line error = bool(384793478934378924978439789873478934897),
-
- ?line error = bool(id(self())),
- ?line error = bool(id({x,y,z})),
- ?line error = bool(id([a,b,c])),
- ?line error = bool(id(make_ref())),
- ?line error = bool(id(<<1,2,3>>)),
-
- ?line true = my_is_bool(true),
- ?line true = my_is_bool(false),
- ?line false = my_is_bool([]),
- ?line false = my_is_bool([1,2,3,4]),
- ?line false = my_is_bool({a,b,c}),
+ true = is_boolean(true),
+ true = is_boolean(false),
+ true = is_boolean(id(true)),
+ true = is_boolean(id(false)),
+
+ false = is_boolean(glurf),
+ false = is_boolean(id(glurf)),
+
+ false = is_boolean([]),
+ false = is_boolean(id([])),
+ false = is_boolean(42),
+ false = is_boolean(id(-42)),
+
+ false = is_boolean(math:pi()),
+ false = is_boolean(384793478934378924978439789873478934897),
+
+ false = is_boolean(id(self())),
+ false = is_boolean(id({x,y,z})),
+ false = is_boolean(id([a,b,c])),
+ false = is_boolean(id(make_ref())),
+ false = is_boolean(id(<<1,2,3>>)),
+ false = is_boolean({id(x),y,z}),
+ false = is_boolean([id(a),b,c]),
+
+ ok = bool(true),
+ ok = bool(false),
+ ok = bool(id(true)),
+ ok = bool(id(false)),
+
+ error = bool(glurf),
+ error = bool(id(glurf)),
+
+ error = bool([]),
+ error = bool(id([])),
+ error = bool(42),
+ error = bool(id(-42)),
+
+ error = bool(math:pi()),
+ error = bool(384793478934378924978439789873478934897),
+
+ error = bool(id(self())),
+ error = bool(id({x,y,z})),
+ error = bool(id([a,b,c])),
+ error = bool(id(make_ref())),
+ error = bool(id(<<1,2,3>>)),
+
+ true = my_is_bool(true),
+ true = my_is_bool(false),
+ false = my_is_bool([]),
+ false = my_is_bool([1,2,3,4]),
+ false = my_is_bool({a,b,c}),
ok.
@@ -1048,18 +1191,25 @@ is_function_2(Config) when is_list(Config) ->
end.
tricky(Config) when is_list(Config) ->
- ?line not_ok = tricky_1(1, 2),
- ?line not_ok = tricky_1(1, blurf),
- ?line not_ok = tricky_1(foo, 2),
- ?line not_ok = tricky_1(a, b),
-
- ?line error = tricky_2(0.5),
- ?line error = tricky_2(a),
- ?line error = tricky_2({a,b,c}),
-
- ?line false = rb(100000, [1], 42),
- ?line true = rb(100000, [], 42),
- ?line true = rb(555, [a,b,c], 19),
+ not_ok = tricky_1(1, 2),
+ not_ok = tricky_1(1, blurf),
+ not_ok = tricky_1(foo, 2),
+ not_ok = tricky_1(a, b),
+
+ error = tricky_2(0.5),
+ error = tricky_2(a),
+ error = tricky_2({a,b,c}),
+
+ false = rb(100000, [1], 42),
+ true = rb(100000, [], 42),
+ true = rb(555, [a,b,c], 19),
+
+ error = tricky_3(42),
+ error = tricky_3(42.0),
+ error = tricky_3(<<>>),
+ error = tricky_3(#{}),
+ error = tricky_3({a,b}),
+
ok.
tricky_1(X, Y) when abs((X == 1) or (Y == 2)) -> ok;
@@ -1068,6 +1218,15 @@ tricky_1(_, _) -> not_ok.
tricky_2(X) when float(X) or float(X) -> ok;
tricky_2(_) -> error.
+tricky_3(X)
+ when abs(X) or bit_size(X) or byte_size(X) or ceil(X) or
+ float(X) or floor(X) or length(X) or
+ map_size(X) or node() or node(X) or round(X) or
+ self() or size(X) or tl(X) or trunc(X) or tuple_size(X) ->
+ ok;
+tricky_3(_) ->
+ error.
+
%% From dets_v9:read_buckets/11, simplified.
rb(Size, ToRead, SoFar) when SoFar + Size < 81920; ToRead == [] -> true;
@@ -1097,40 +1256,40 @@ rb(_, _, _) -> false.
rel_ops(Config) when is_list(Config) ->
- ?line ?T(=/=, 1, 1.0),
- ?line ?F(=/=, 2, 2),
- ?line ?F(=/=, {a}, {a}),
+ ?T(=/=, 1, 1.0),
+ ?F(=/=, 2, 2),
+ ?F(=/=, {a}, {a}),
- ?line ?F(/=, a, a),
- ?line ?F(/=, 0, 0.0),
- ?line ?T(/=, 0, 1),
- ?line ?F(/=, {a}, {a}),
+ ?F(/=, a, a),
+ ?F(/=, 0, 0.0),
+ ?T(/=, 0, 1),
+ ?F(/=, {a}, {a}),
- ?line ?T(==, 1, 1.0),
- ?line ?F(==, a, {}),
+ ?T(==, 1, 1.0),
+ ?F(==, a, {}),
- ?line ?F(=:=, 1, 1.0),
- ?line ?T(=:=, 42.0, 42.0),
+ ?F(=:=, 1, 1.0),
+ ?T(=:=, 42.0, 42.0),
- ?line ?F(>, a, b),
- ?line ?T(>, 42, 1.0),
- ?line ?F(>, 42, 42.0),
+ ?F(>, a, b),
+ ?T(>, 42, 1.0),
+ ?F(>, 42, 42.0),
- ?line ?T(<, a, b),
- ?line ?F(<, 42, 1.0),
- ?line ?F(<, 42, 42.0),
+ ?T(<, a, b),
+ ?F(<, 42, 1.0),
+ ?F(<, 42, 42.0),
- ?line ?T(=<, 1.5, 5),
- ?line ?F(=<, -9, -100.344),
- ?line ?T(=<, 42, 42.0),
+ ?T(=<, 1.5, 5),
+ ?F(=<, -9, -100.344),
+ ?T(=<, 42, 42.0),
- ?line ?T(>=, 42, 42.0),
- ?line ?F(>=, a, b),
- ?line ?T(>=, 1.0, 0),
+ ?T(>=, 42, 42.0),
+ ?F(>=, a, b),
+ ?T(>=, 1.0, 0),
%% Coverage of beam_block:is_exact_eq_ok/1 and collect/1.
- ?line true = any_atom /= id(42),
- ?line true = [] /= id(42),
+ true = any_atom /= id(42),
+ true = [] /= id(42),
ok.
@@ -1371,35 +1530,35 @@ literal_type_tests(Config) when is_list(Config) ->
literal_type_tests_1(Config) ->
%% Generate an Erlang module with all different type of type tests.
- ?line Tests = make_test([{T,L} || T <- type_tests(), L <- literals()] ++
+ Tests = make_test([{T,L} || T <- type_tests(), L <- literals()] ++
[{is_function,L1,L2} ||
L1 <- literals(), L2 <- literals()]),
- ?line Mod = literal_test,
+ Mod = literal_test,
Anno = erl_anno:new(0),
Func = {function, Anno, test, 0, [{clause,Anno,[],[],Tests}]},
Form = [{attribute,Anno,module,Mod},
{attribute,Anno,compile,export_all},
- Func, {eof,Anno}],
+ Func, {eof,999}],
%% Print generated code for inspection.
- ?line lists:foreach(fun (F) -> io:put_chars([erl_pp:form(F),"\n"]) end, Form),
+ lists:foreach(fun (F) -> io:put_chars([erl_pp:form(F),"\n"]) end, Form),
%% Test compile:form/1. This implies full optimization (default).
- ?line {ok,Mod,Code1} = compile:forms(Form),
- ?line smoke_disasm(Config, Mod, Code1),
- ?line {module,Mod} = code:load_binary(Mod, Mod, Code1),
- ?line Mod:test(),
- ?line true = code:delete(Mod),
- ?line code:purge(Mod),
+ {ok,Mod,Code1} = compile:forms(Form),
+ smoke_disasm(Config, Mod, Code1),
+ {module,Mod} = code:load_binary(Mod, Mod, Code1),
+ Mod:test(),
+ true = code:delete(Mod),
+ code:purge(Mod),
%% Test compile:form/2. Turn off all optimizations.
- ?line {ok,Mod,Code2} = compile:forms(Form, [binary,report,time,
+ {ok,Mod,Code2} = compile:forms(Form, [binary,report,time,
no_copt,no_postopt]),
- ?line smoke_disasm(Config, Mod, Code2),
- ?line {module,Mod} = code:load_binary(Mod, Mod, Code2),
- ?line Mod:test(),
- ?line true = code:delete(Mod),
- ?line code:purge(Mod),
+ smoke_disasm(Config, Mod, Code2),
+ {module,Mod} = code:load_binary(Mod, Mod, Code2),
+ Mod:test(),
+ true = code:delete(Mod),
+ code:purge(Mod),
ok.
make_test([{T,L1,L2}|Ts]) ->
@@ -1427,7 +1586,7 @@ test(T, L1, L2) ->
{match,Anno,{atom,Anno,Val},hd(E)}.
smoke_disasm(Config, Mod, Bin) ->
- Priv = ?config(priv_dir, Config),
+ Priv = proplists:get_value(priv_dir, Config),
File = filename:join(Priv, atom_to_list(Mod)++".beam"),
ok = file:write_file(File, Bin),
test_lib:smoke_disasm(File).
@@ -1459,30 +1618,30 @@ type_tests() ->
is_function].
basic_andalso_orelse(Config) when is_list(Config) ->
- ?line T = id({type,integers,23,42}),
- ?line 65 = if
- ((element(1, T) =:= type) andalso (tuple_size(T) =:= 4) andalso
- element(2, T)) == integers ->
- element(3, T) + element(4, T);
- true -> error
- end,
- ?line 65 = case [] of
- [] when ((element(1, T) =:= type) andalso (tuple_size(T) =:= 4) andalso
- element(2, T)) == integers ->
- element(3, T) + element(4, T)
- end,
-
- ?line 42 = basic_rt({type,integers,40,2}),
- ?line 5.0 = basic_rt({vector,{3.0,4.0}}),
- ?line 20 = basic_rt(['+',3,7]),
- ?line {'Set',a,b} = basic_rt({{'Set',a,b},{'Set',a,b}}),
- ?line 12 = basic_rt({klurf,4}),
-
- ?line error = basic_rt({type,integers,40,2,3}),
- ?line error = basic_rt({kalle,integers,40,2}),
- ?line error = basic_rt({kalle,integers,40,2}),
- ?line error = basic_rt({1,2}),
- ?line error = basic_rt([]),
+ T = id({type,integers,23,42}),
+ 65 = if
+ ((element(1, T) =:= type) andalso (tuple_size(T) =:= 4) andalso
+ element(2, T)) == integers ->
+ element(3, T) + element(4, T);
+ true -> error
+ end,
+ 65 = case [] of
+ [] when ((element(1, T) =:= type) andalso (tuple_size(T) =:= 4) andalso
+ element(2, T)) == integers ->
+ element(3, T) + element(4, T)
+ end,
+
+ 42 = basic_rt({type,integers,40,2}),
+ 5.0 = basic_rt({vector,{3.0,4.0}}),
+ 20 = basic_rt(['+',3,7]),
+ {'Set',a,b} = basic_rt({{'Set',a,b},{'Set',a,b}}),
+ 12 = basic_rt({klurf,4}),
+
+ error = basic_rt({type,integers,40,2,3}),
+ error = basic_rt({kalle,integers,40,2}),
+ error = basic_rt({kalle,integers,40,2}),
+ error = basic_rt({1,2}),
+ error = basic_rt([]),
RelProdBody =
fun(R1, R2) ->
@@ -1493,7 +1652,7 @@ basic_andalso_orelse(Config) when is_list(Config) ->
end
end,
- ?line ok = RelProdBody({'Set',a,b}, {'Set',a,b}),
+ ok = RelProdBody({'Set',a,b}, {'Set',a,b}),
%% 'andalso'/'orelse' with calls known to fail already at compile time.
%% Used to crash the code generator.
@@ -1564,14 +1723,14 @@ traverse_dcd({Cont,Recs},Log,Fun) ->
check_qlc_hrl(Config) when is_list(Config) ->
St = {r1,false,dum},
- ?line foo = cqlc(qlc, q, [{lc,1,2,3}], St),
- ?line foo = cqlc(qlc, q, [{lc,1,2,3},b], St),
- ?line St = cqlc(qlc, q, [], St),
- ?line St = cqlc(qlc, blurf, [{lc,1,2,3},b], St),
- ?line St = cqlc(q, q, [{lc,1,2,3},b], St),
- ?line St = cqlc(qlc, q, [{lc,1,2,3},b,c], St),
- ?line St = cqlc(qlc, q, [a,b], St),
- ?line {r1,true,kalle} = cqlc(qlc, q, [{lc,1,2,3},b], {r1,true,kalle}),
+ foo = cqlc(qlc, q, [{lc,1,2,3}], St),
+ foo = cqlc(qlc, q, [{lc,1,2,3},b], St),
+ St = cqlc(qlc, q, [], St),
+ St = cqlc(qlc, blurf, [{lc,1,2,3},b], St),
+ St = cqlc(q, q, [{lc,1,2,3},b], St),
+ St = cqlc(qlc, q, [{lc,1,2,3},b,c], St),
+ St = cqlc(qlc, q, [a,b], St),
+ {r1,true,kalle} = cqlc(qlc, q, [{lc,1,2,3},b], {r1,true,kalle}),
ok.
%% From erl_lint.erl; original name was check_qlc_hrl/4.
@@ -1588,13 +1747,13 @@ cqlc(M, F, As, St) ->
%% OTP-7679: Thanks to Hunter Morris.
andalso_semi(Config) when is_list(Config) ->
- ?line ok = andalso_semi_foo(0),
- ?line ok = andalso_semi_foo(1),
- ?line fc(catch andalso_semi_foo(2)),
+ ok = andalso_semi_foo(0),
+ ok = andalso_semi_foo(1),
+ fc(catch andalso_semi_foo(2)),
- ?line ok = andalso_semi_bar([a,b,c]),
- ?line ok = andalso_semi_bar(1),
- ?line fc(catch andalso_semi_bar([a,b])),
+ ok = andalso_semi_bar([a,b,c]),
+ ok = andalso_semi_bar(1),
+ fc(catch andalso_semi_bar([a,b])),
ok.
andalso_semi_foo(Bar) when is_integer(Bar) andalso Bar =:= 0; Bar =:= 1 ->
@@ -1605,20 +1764,20 @@ andalso_semi_bar(Bar) when is_list(Bar) andalso length(Bar) =:= 3; Bar =:= 1 ->
t_tuple_size(Config) when is_list(Config) ->
- ?line 10 = do_tuple_size({1,2,3,4}),
- ?line fc(catch do_tuple_size({1,2,3})),
- ?line fc(catch do_tuple_size(42)),
+ 10 = do_tuple_size({1,2,3,4}),
+ fc(catch do_tuple_size({1,2,3})),
+ fc(catch do_tuple_size(42)),
- ?line error = ludicrous_tuple_size({a,b,c}),
- ?line error = ludicrous_tuple_size([a,b,c]),
+ error = ludicrous_tuple_size({a,b,c}),
+ error = ludicrous_tuple_size([a,b,c]),
%% Test the "unsafe case" - the register assigned the tuple size is
%% not killed.
- ?line DataDir = test_lib:get_data_dir(Config),
- ?line File = filename:join(DataDir, "guard_SUITE_tuple_size"),
- ?line {ok,Mod,Code} = compile:file(File, [from_asm,binary]),
- ?line code:load_binary(Mod, File, Code),
- ?line 14 = Mod:t({1,2,3,4}),
+ DataDir = test_lib:get_data_dir(Config),
+ File = filename:join(DataDir, "guard_SUITE_tuple_size"),
+ {ok,Mod,Code} = compile:file(File, [from_asm,binary]),
+ code:load_binary(Mod, File, Code),
+ 14 = Mod:t({1,2,3,4}),
_ = code:delete(Mod),
_ = code:purge(Mod),
@@ -1647,71 +1806,70 @@ mask_error({'EXIT',{Err,_}}) ->
mask_error(Else) ->
Else.
-binary_part(doc) ->
- ["Tests the binary_part/2,3 guard (GC) bif's"];
+%% Test the binary_part/2,3 guard (GC) BIFs.
binary_part(Config) when is_list(Config) ->
%% This is more or less a copy of what the guard_SUITE in emulator
%% does to cover the guard bif's
- ?line 1 = bptest(<<1,2,3>>),
- ?line 2 = bptest(<<2,1,3>>),
- ?line error = bptest(<<1>>),
- ?line error = bptest(<<>>),
- ?line error = bptest(apa),
- ?line 3 = bptest(<<2,3,3>>),
+ 1 = bptest(<<1,2,3>>),
+ 2 = bptest(<<2,1,3>>),
+ error = bptest(<<1>>),
+ error = bptest(<<>>),
+ error = bptest(apa),
+ 3 = bptest(<<2,3,3>>),
% With one variable (pos)
- ?line 1 = bptest(<<1,2,3>>,1),
- ?line 2 = bptest(<<2,1,3>>,1),
- ?line error = bptest(<<1>>,1),
- ?line error = bptest(<<>>,1),
- ?line error = bptest(apa,1),
- ?line 3 = bptest(<<2,3,3>>,1),
+ 1 = bptest(<<1,2,3>>,1),
+ 2 = bptest(<<2,1,3>>,1),
+ error = bptest(<<1>>,1),
+ error = bptest(<<>>,1),
+ error = bptest(apa,1),
+ 3 = bptest(<<2,3,3>>,1),
% With one variable (length)
- ?line 1 = bptesty(<<1,2,3>>,1),
- ?line 2 = bptesty(<<2,1,3>>,1),
- ?line error = bptesty(<<1>>,1),
- ?line error = bptesty(<<>>,1),
- ?line error = bptesty(apa,1),
- ?line 3 = bptesty(<<2,3,3>>,2),
+ 1 = bptesty(<<1,2,3>>,1),
+ 2 = bptesty(<<2,1,3>>,1),
+ error = bptesty(<<1>>,1),
+ error = bptesty(<<>>,1),
+ error = bptesty(apa,1),
+ 3 = bptesty(<<2,3,3>>,2),
% With one variable (whole tuple)
- ?line 1 = bptestx(<<1,2,3>>,{1,1}),
- ?line 2 = bptestx(<<2,1,3>>,{1,1}),
- ?line error = bptestx(<<1>>,{1,1}),
- ?line error = bptestx(<<>>,{1,1}),
- ?line error = bptestx(apa,{1,1}),
- ?line 3 = bptestx(<<2,3,3>>,{1,2}),
+ 1 = bptestx(<<1,2,3>>,{1,1}),
+ 2 = bptestx(<<2,1,3>>,{1,1}),
+ error = bptestx(<<1>>,{1,1}),
+ error = bptestx(<<>>,{1,1}),
+ error = bptestx(apa,{1,1}),
+ 3 = bptestx(<<2,3,3>>,{1,2}),
% With two variables
- ?line 1 = bptest(<<1,2,3>>,1,1),
- ?line 2 = bptest(<<2,1,3>>,1,1),
- ?line error = bptest(<<1>>,1,1),
- ?line error = bptest(<<>>,1,1),
- ?line error = bptest(apa,1,1),
- ?line 3 = bptest(<<2,3,3>>,1,2),
+ 1 = bptest(<<1,2,3>>,1,1),
+ 2 = bptest(<<2,1,3>>,1,1),
+ error = bptest(<<1>>,1,1),
+ error = bptest(<<>>,1,1),
+ error = bptest(apa,1,1),
+ 3 = bptest(<<2,3,3>>,1,2),
% Direct (autoimported) call, these will be evaluated by the compiler...
- ?line <<2>> = binary_part(<<1,2,3>>,1,1),
- ?line <<1>> = binary_part(<<2,1,3>>,1,1),
+ <<2>> = binary_part(<<1,2,3>>,1,1),
+ <<1>> = binary_part(<<2,1,3>>,1,1),
% Compiler warnings due to constant evaluation expected (3)
- ?line badarg = ?MASK_ERROR(binary_part(<<1>>,1,1)),
- ?line badarg = ?MASK_ERROR(binary_part(<<>>,1,1)),
- ?line badarg = ?MASK_ERROR(binary_part(apa,1,1)),
- ?line <<3,3>> = binary_part(<<2,3,3>>,1,2),
+ badarg = ?MASK_ERROR(binary_part(<<1>>,1,1)),
+ badarg = ?MASK_ERROR(binary_part(<<>>,1,1)),
+ badarg = ?MASK_ERROR(binary_part(apa,1,1)),
+ <<3,3>> = binary_part(<<2,3,3>>,1,2),
% Direct call through apply
- ?line <<2>> = apply(erlang,binary_part,[<<1,2,3>>,1,1]),
- ?line <<1>> = apply(erlang,binary_part,[<<2,1,3>>,1,1]),
+ <<2>> = apply(erlang,binary_part,[<<1,2,3>>,1,1]),
+ <<1>> = apply(erlang,binary_part,[<<2,1,3>>,1,1]),
% Compiler warnings due to constant evaluation expected (3)
- ?line badarg = ?MASK_ERROR(apply(erlang,binary_part,[<<1>>,1,1])),
- ?line badarg = ?MASK_ERROR(apply(erlang,binary_part,[<<>>,1,1])),
- ?line badarg = ?MASK_ERROR(apply(erlang,binary_part,[apa,1,1])),
- ?line <<3,3>> = apply(erlang,binary_part,[<<2,3,3>>,1,2]),
+ badarg = ?MASK_ERROR(apply(erlang,binary_part,[<<1>>,1,1])),
+ badarg = ?MASK_ERROR(apply(erlang,binary_part,[<<>>,1,1])),
+ badarg = ?MASK_ERROR(apply(erlang,binary_part,[apa,1,1])),
+ <<3,3>> = apply(erlang,binary_part,[<<2,3,3>>,1,2]),
% Constant propagation
- ?line Bin = <<1,2,3>>,
- ?line ok = if
+ Bin = <<1,2,3>>,
+ ok = if
binary_part(Bin,1,1) =:= <<2>> ->
ok;
%% Compiler warning, clause cannot match (expected)
true ->
error
end,
- ?line ok = if
+ ok = if
binary_part(Bin,{1,1}) =:= <<2>> ->
ok;
%% Compiler warning, clause cannot match (expected)
@@ -1778,24 +1936,24 @@ bptest(_,_,_) ->
-define(FAILING(C),
if
- C -> ?t:fail(should_fail);
+ C -> ct:fail(should_fail);
true -> ok
end,
if
- true, C -> ?t:fail(should_fail);
+ true, C -> ct:fail(should_fail);
true -> ok
end).
bad_constants(Config) when is_list(Config) ->
- ?line ?FAILING(false),
- ?line ?FAILING([]),
- ?line ?FAILING([a]),
- ?line ?FAILING([Config]),
- ?line ?FAILING({a,b}),
- ?line ?FAILING({a,Config}),
- ?line ?FAILING(<<1>>),
- ?line ?FAILING(42),
- ?line ?FAILING(3.14),
+ ?FAILING(false),
+ ?FAILING([]),
+ ?FAILING([a]),
+ ?FAILING([Config]),
+ ?FAILING({a,b}),
+ ?FAILING({a,Config}),
+ ?FAILING(<<1>>),
+ ?FAILING(42),
+ ?FAILING(3.14),
ok.
bad_guards(Config) when is_list(Config) ->
@@ -1815,6 +1973,8 @@ bad_guards(Config) when is_list(Config) ->
fc(catch bad_guards_3(not_a_map, [x])),
fc(catch bad_guards_3(42, [x])),
+ fc(catch bad_guards_4()),
+
ok.
%% beam_bool used to produce GC BIF instructions whose
@@ -1832,26 +1992,11 @@ bad_guards_2(M, [_]) when M#{a := 0, b => 0}, map_size(M) ->
bad_guards_3(M, [_]) when is_map(M) andalso M#{a := 0, b => 0}, length(M) ->
ok.
-%% beam_bool would remove the initialization of {y,0}.
-%% (Thanks to Thomas Arts and QuickCheck.)
+%% v3_codegen would generate a jump to the failure label, but
+%% without initializing x(0). The code at the failure label expected
+%% x(0) to be initialized.
-scotland(_Config) ->
- million = do_scotland(placed),
- {'EXIT',{{badmatch,placed},_}} = (catch do_scotland(false)),
- {'EXIT',{{badmatch,placed},_}} = (catch do_scotland(true)),
- {'EXIT',{{badmatch,placed},_}} = (catch do_scotland(echo)),
- ok.
-
-do_scotland(Echo) ->
- found(case Echo of
- Echo when true; Echo, Echo, Echo ->
- Echo;
- echo ->
- []
- end,
- Echo = placed).
-
-found(_, _) -> million.
+bad_guards_4() when not (error#{}); {not 0.0} -> freedom.
%% Building maps in a guard in a 'catch' would crash v3_codegen.
@@ -1905,6 +2050,155 @@ do_guard_in_catch_bin(From) ->
saint
end.
+%%%
+%%% The beam_bool pass has been eliminated. Here are the tests from
+%%% beam_bool_SUITE.
+%%%
+
+beam_bool_SUITE(_Config) ->
+ before_and_inside_if(),
+ scotland(),
+ y_registers(),
+ protected(),
+ maps(),
+ ok.
+
+before_and_inside_if() ->
+ no = before_and_inside_if([a], [b], delete),
+ no = before_and_inside_if([a], [b], x),
+ no = before_and_inside_if([a], [], delete),
+ no = before_and_inside_if([a], [], x),
+ no = before_and_inside_if([], [], delete),
+ yes = before_and_inside_if([], [], x),
+ yes = before_and_inside_if([], [b], delete),
+ yes = before_and_inside_if([], [b], x),
+
+ {ch1,ch2} = before_and_inside_if_2([a], [b], blah),
+ {ch1,ch2} = before_and_inside_if_2([a], [b], xx),
+ {ch1,ch2} = before_and_inside_if_2([a], [], blah),
+ {ch1,ch2} = before_and_inside_if_2([a], [], xx),
+ {no,no} = before_and_inside_if_2([], [b], blah),
+ {no,no} = before_and_inside_if_2([], [b], xx),
+ {ch1,no} = before_and_inside_if_2([], [], blah),
+ {no,ch2} = before_and_inside_if_2([], [], xx),
+ ok.
+
+%% Thanks to Simon Cornish and Kostis Sagonas.
+%% Used to crash beam_bool.
+before_and_inside_if(XDo1, XDo2, Do3) ->
+ Do1 = (XDo1 =/= []),
+ Do2 = (XDo2 =/= []),
+ if
+ %% This expression occurs in a try/catch (protected)
+ %% block, which cannot refer to variables outside of
+ %% the block that are boolean expressions.
+ Do1 =:= true;
+ Do1 =:= false, Do2 =:= false, Do3 =:= delete ->
+ no;
+ true ->
+ yes
+ end.
+
+%% Thanks to Simon Cornish.
+%% Used to generate code that would not set {y,0} on
+%% all paths before its use (and therefore fail
+%% validation by the beam_validator).
+before_and_inside_if_2(XDo1, XDo2, Do3) ->
+ Do1 = (XDo1 =/= []),
+ Do2 = (XDo2 =/= []),
+ CH1 = if Do1 == true;
+ Do1 == false,Do2==false,Do3 == blah ->
+ ch1;
+ true ->
+ no
+ end,
+ CH2 = if Do1 == true;
+ Do1 == false,Do2==false,Do3 == xx ->
+ ch2;
+ true ->
+ no
+ end,
+ {CH1,CH2}.
+
+
+%% beam_bool would remove the initialization of {y,0}.
+%% (Thanks to Thomas Arts and QuickCheck.)
+
+scotland() ->
+ million = do_scotland(placed),
+ {'EXIT',{{badmatch,placed},_}} = (catch do_scotland(false)),
+ {'EXIT',{{badmatch,placed},_}} = (catch do_scotland(true)),
+ {'EXIT',{{badmatch,placed},_}} = (catch do_scotland(echo)),
+ ok.
+
+do_scotland(Echo) ->
+ found(case Echo of
+ Echo when true; Echo, Echo, Echo ->
+ Echo;
+ echo ->
+ []
+ end,
+ Echo = placed).
+
+found(_, _) -> million.
+
+
+%% ERL-143: beam_bool could not handle Y registers as a destination.
+y_registers() ->
+ {'EXIT',{badarith,[_|_]}} = (catch baker(valentine)),
+ {'EXIT',{badarith,[_|_]}} = (catch baker(clementine)),
+
+ {not_ok,true} = potter([]),
+ {ok,false} = potter([{encoding,any}]),
+
+ ok.
+
+%% Thanks to Quickcheck.
+baker(Baker) ->
+ (valentine == Baker) +
+ case Baker of
+ Baker when Baker; Baker ->
+ Baker;
+ Baker ->
+ []
+ end.
+
+%% Thanks to Jose Valim.
+potter(Modes) ->
+ Raw = lists:keyfind(encoding, 1, Modes) == false,
+ Final = case Raw of
+ X when X == false; X == nil -> ok;
+ _ -> not_ok
+ end,
+ {Final,Raw}.
+
+protected() ->
+ {'EXIT',{if_clause,_}} = (catch photographs({1, surprise, true}, opinions)),
+
+ {{true}} = welcome({perfect, true}),
+ {'EXIT',{if_clause,_}} = (catch welcome({perfect, false})),
+ ok.
+
+photographs({_Violation, surprise, Deep}, opinions) ->
+ {if
+ 0; "here", Deep ->
+ Deep = Deep
+ end}.
+
+welcome({perfect, Profit}) ->
+ if
+ Profit, Profit, Profit; 0 ->
+ {id({Profit})}
+ end.
+
+maps() ->
+ ok = evidence(#{0 => 42}).
+
+%% Cover handling of put_map in in split_block_label_used/2.
+evidence(#{0 := Charge}) when 0; #{[] => Charge} == #{[] => 42} ->
+ ok.
+
+
%% Call this function to turn off constant propagation.
id(I) -> I.
@@ -1915,7 +2209,7 @@ check(F, Result) ->
Other ->
io:format("Expected: ~p\n", [Result]),
io:format(" Got: ~p\n", [Other]),
- test_server:fail()
+ ct:fail(check_failed)
end.
fc({'EXIT',{function_clause,_}}) -> ok;
diff --git a/lib/compiler/test/inline_SUITE.erl b/lib/compiler/test/inline_SUITE.erl
index 0b92a784de..ae59cc8026 100644
--- a/lib/compiler/test/inline_SUITE.erl
+++ b/lib/compiler/test/inline_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
-module(inline_SUITE).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
-compile(export_all).
-compile({inline,[badarg/2]}).
@@ -47,8 +47,8 @@ init_per_suite(Config) ->
[{testing_node,Node}|Config].
end_per_suite(Config) ->
- Node = ?config(testing_node, Config),
- ?t:stop_node(Node),
+ Node = proplists:get_value(testing_node, Config),
+ test_server:stop_node(Node),
ok.
init_per_group(_GroupName, Config) ->
@@ -60,16 +60,16 @@ end_per_group(_GroupName, Config) ->
attribute(Config) when is_list(Config) ->
Name = "attribute",
- ?line Src = filename:join(?config(data_dir, Config), Name),
- ?line Out = ?config(priv_dir,Config),
+ Src = filename:join(proplists:get_value(data_dir, Config), Name),
+ Out = proplists:get_value(priv_dir,Config),
- ?line {ok,attribute=Mod} = compile:file(Src, [{outdir,Out},report,time]),
- ?line Outfile = filename:join(Out, Name++".beam"),
- ?line {ok,{Mod,[{locals,Locals}]}} = beam_lib:chunks(Outfile, [locals]),
- ?line io:format("locals: ~p\n", [Locals]),
+ {ok,attribute=Mod} = compile:file(Src, [{outdir,Out},report,time]),
+ Outfile = filename:join(Out, Name++".beam"),
+ {ok,{Mod,[{locals,Locals}]}} = beam_lib:chunks(Outfile, [locals]),
+ io:format("locals: ~p\n", [Locals]),
%% The inliner should have removed all local functions.
- ?line [] = Locals,
+ [] = Locals,
ok.
@@ -89,48 +89,46 @@ attribute(Config) when is_list(Config) ->
?comp(maps_inline_test).
try_inline(Mod, Config) ->
- Node = ?config(testing_node, Config),
- ?line Src = filename:join(?config(data_dir, Config), atom_to_list(Mod)),
- ?line Out = ?config(priv_dir,Config),
+ Node = proplists:get_value(testing_node, Config),
+ Src = filename:join(proplists:get_value(data_dir, Config),
+ atom_to_list(Mod)),
+ Out = proplists:get_value(priv_dir,Config),
%% Normal compilation.
- ?line io:format("Compiling: ~s\n", [Src]),
- ?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,bin_opt_info,clint]),
+ io:format("Compiling: ~s\n", [Src]),
+ {ok,Mod} = compile:file(Src, [{outdir,Out},report,bin_opt_info,clint]),
- ?line Dog = test_server:timetrap(test_server:minutes(10)),
- ?line NormalResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
- ?line test_server:timetrap_cancel(Dog),
+ ct:timetrap({minutes,10}),
+ NormalResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
%% Inlining.
- ?line io:format("Compiling with old inliner: ~s\n", [Src]),
- ?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,bin_opt_info,
+ io:format("Compiling with old inliner: ~s\n", [Src]),
+ {ok,Mod} = compile:file(Src, [{outdir,Out},report,bin_opt_info,
{inline,1000},clint]),
%% Run inlined code.
- ?line Dog3 = test_server:timetrap(test_server:minutes(10)),
- ?line OldInlinedResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
- ?line test_server:timetrap_cancel(Dog3),
+ ct:timetrap({minutes,10}),
+ OldInlinedResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
%% Compare results.
- ?line compare(NormalResult, OldInlinedResult),
- ?line NormalResult = OldInlinedResult,
+ compare(NormalResult, OldInlinedResult),
+ NormalResult = OldInlinedResult,
%% Inlining.
- ?line io:format("Compiling with new inliner: ~s\n", [Src]),
- ?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,
+ io:format("Compiling with new inliner: ~s\n", [Src]),
+ {ok,Mod} = compile:file(Src, [{outdir,Out},report,
bin_opt_info,inline,clint]),
%% Run inlined code.
- ?line Dog4 = test_server:timetrap(test_server:minutes(10)),
- ?line InlinedResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
- ?line test_server:timetrap_cancel(Dog4),
+ ct:timetrap({minutes,10}),
+ InlinedResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
%% Compare results.
- ?line compare(NormalResult, InlinedResult),
- ?line NormalResult = InlinedResult,
+ compare(NormalResult, InlinedResult),
+ NormalResult = InlinedResult,
%% Delete Beam file.
- ?line ok = file:delete(filename:join(Out, atom_to_list(Mod)++code:objfile_extension())),
+ ok = file:delete(filename:join(Out, atom_to_list(Mod)++code:objfile_extension())),
ok.
@@ -142,24 +140,24 @@ compare([{X,Y,RGB1}|T1], [{X,Y,RGB2}|T2]) ->
compare(T1, T2);
compare([H1|_], [H2|_]) ->
io:format("Normal = ~p, Inlined = ~p\n", [H1,H2]),
- ?t:fail();
+ ct:fail(different);
compare([], []) -> ok.
start_node(Name, Args) ->
case test_server:start_node(Name, slave, [{args,Args}]) of
{ok,Node} -> {ok, Node};
- Error -> ?line test_server:fail(Error)
+ Error -> ct:fail(Error)
end.
load_and_call(Out, Module) ->
- ?line io:format("Loading...\n",[]),
- ?line code:purge(Module),
- ?line LoadRc = code:load_abs(filename:join(Out, Module)),
- ?line {module,Module} = LoadRc,
-
- ?line io:format("Calling...\n",[]),
- ?line {Time,CallResult} = timer:tc(Module, Module, []),
- ?line io:format("Time: ~p\n", [Time]),
+ io:format("Loading...\n",[]),
+ code:purge(Module),
+ LoadRc = code:load_abs(filename:join(Out, Module)),
+ {module,Module} = LoadRc,
+
+ io:format("Calling...\n",[]),
+ {Time,CallResult} = timer:tc(Module, Module, []),
+ io:format("Time: ~p\n", [Time]),
CallResult.
%% Macros used by lists/1 below.
@@ -195,69 +193,78 @@ load_and_call(Out, Module) ->
%% Note: This module must be compiled with the inline_lists_funcs option.
lists(Config) when is_list(Config) ->
- ?line List = lists:seq(1, 20),
+ List = lists:seq(1, 20),
%% lists:map/2
- ?line ?TestHighOrder_2(map, (fun(E) ->
- R = E band 16#ff,
- put(?MODULE, [E|get(?MODULE)]),
- R
- end), List),
+ ?TestHighOrder_2(map,
+ (fun(E) ->
+ R = E band 16#ff,
+ put(?MODULE, [E|get(?MODULE)]),
+ R
+ end), List),
%% lists:flatmap/2
- ?line ?TestHighOrder_2(flatmap, (fun(E) ->
- R = lists:duplicate(E, E),
- put(?MODULE, [E|get(?MODULE)]),
- R
- end), List),
+ ?TestHighOrder_2(flatmap,
+ (fun(E) ->
+ R = lists:duplicate(E, E),
+ put(?MODULE, [E|get(?MODULE)]),
+ R
+ end), List),
%% lists:foreach/2
- ?line ?TestHighOrder_2(foreach,
- (fun(E) ->
- put(?MODULE, [E bor 7|get(?MODULE)])
- end), List),
+ ?TestHighOrder_2(foreach,
+ (fun(E) ->
+ put(?MODULE, [E bor 7|get(?MODULE)])
+ end), List),
%% lists:filter/2
- ?line ?TestHighOrder_2(filter, (fun(E) ->
- put(?MODULE, [E|get(?MODULE)]),
- (E bsr 1) band 1 =/= 0
- end), List),
+ ?TestHighOrder_2(filter,
+ (fun(E) ->
+ put(?MODULE, [E|get(?MODULE)]),
+ (E bsr 1) band 1 =/= 0
+ end), List),
%% lists:any/2
- ?line ?TestHighOrder_2(any, (fun(E) ->
- put(?MODULE, [E|get(?MODULE)]),
- false %Force it to go through all.
- end), List),
+ ?TestHighOrder_2(any,
+ (fun(E) ->
+ put(?MODULE, [E|get(?MODULE)]),
+ false %Force it to go through all.
+ end), List),
%% lists:all/2
- ?line ?TestHighOrder_2(all, (fun(E) ->
- put(?MODULE, [E|get(?MODULE)]),
- true %Force it to go through all.
- end), List),
+ ?TestHighOrder_2(all,
+ (fun(E) ->
+ put(?MODULE, [E|get(?MODULE)]),
+ true %Force it to go through all.
+ end), List),
%% lists:foldl/3
- ?line ?TestHighOrder_3(foldl, (fun(E, A) ->
- put(?MODULE, [E|get(?MODULE)]),
- A bxor E
- end), 0, List),
+ ?TestHighOrder_3(foldl,
+ (fun(E, A) ->
+ put(?MODULE, [E|get(?MODULE)]),
+ A bxor E
+ end), 0, List),
%% lists:foldr/3
- ?line ?TestHighOrder_3(foldr, (fun(E, A) ->
- put(?MODULE, [E|get(?MODULE)]),
- A bxor (bnot E)
- end), 0, List),
+ ?TestHighOrder_3(foldr,
+ (fun(E, A) ->
+ put(?MODULE, [E|get(?MODULE)]),
+ A bxor (bnot E)
+ end), 0, List),
%% lists:mapfoldl/3
- ?line ?TestHighOrder_3(mapfoldl, (fun(E, A) ->
- put(?MODULE, [E|get(?MODULE)]),
- {bnot E,A bxor (bnot E)}
- end), 0, List),
+ ?TestHighOrder_3(mapfoldl,
+ (fun(E, A) ->
+ put(?MODULE, [E|get(?MODULE)]),
+ {bnot E,A bxor (bnot E)}
+ end), 0, List),
%% lists:mapfoldr/3
- ?line ?TestHighOrder_3(mapfoldr, (fun(E, A) ->
- put(?MODULE, [E|get(?MODULE)]),
- {bnot E,A bxor (bnot E)}
- end), 0, List),
+ ?TestHighOrder_3(mapfoldr,
+ (fun(E, A) ->
+ put(?MODULE, [E|get(?MODULE)]),
+ {bnot E,A bxor (bnot E)}
+ end), 0, List),
%% Cleanup.
erase(?MODULE),
@@ -330,7 +337,7 @@ badarg(Reply, _A) ->
Reply.
otp_7223(Config) when is_list(Config) ->
- ?line {'EXIT', {{case_clause,{1}},_}} = (catch otp_7223_1(1)),
+ {'EXIT', {{case_clause,{1}},_}} = (catch otp_7223_1(1)),
ok.
-compile({inline,[{otp_7223_1,1}]}).
@@ -343,7 +350,7 @@ otp_7223_2({a}) ->
coverage(Config) when is_list(Config) ->
Mod = bsdecode,
- Src = filename:join(?config(data_dir, Config), Mod),
+ Src = filename:join(proplists:get_value(data_dir, Config), Mod),
{ok,Mod,_} = compile:file(Src, [binary,report,{inline,0},clint]),
{ok,Mod,_} = compile:file(Src, [binary,report,{inline,20},
verbose,clint]),
diff --git a/lib/compiler/test/inline_SUITE_data/attribute.erl b/lib/compiler/test/inline_SUITE_data/attribute.erl
index 08ef230c47..4bd9d65032 100644
--- a/lib/compiler/test/inline_SUITE_data/attribute.erl
+++ b/lib/compiler/test/inline_SUITE_data/attribute.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/inline_SUITE_data/bsdecode.erl b/lib/compiler/test/inline_SUITE_data/bsdecode.erl
index e72d5ec73d..f6419b33d1 100644
--- a/lib/compiler/test/inline_SUITE_data/bsdecode.erl
+++ b/lib/compiler/test/inline_SUITE_data/bsdecode.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/inline_SUITE_data/bsdes.erl b/lib/compiler/test/inline_SUITE_data/bsdes.erl
index a9717219d1..43d941f144 100644
--- a/lib/compiler/test/inline_SUITE_data/bsdes.erl
+++ b/lib/compiler/test/inline_SUITE_data/bsdes.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/inline_SUITE_data/decode1.erl b/lib/compiler/test/inline_SUITE_data/decode1.erl
index e89b5305a5..f390a32061 100644
--- a/lib/compiler/test/inline_SUITE_data/decode1.erl
+++ b/lib/compiler/test/inline_SUITE_data/decode1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/inline_SUITE_data/fname.erl b/lib/compiler/test/inline_SUITE_data/fname.erl
index 90da1d17ac..5df8ee6b8c 100644
--- a/lib/compiler/test/inline_SUITE_data/fname.erl
+++ b/lib/compiler/test/inline_SUITE_data/fname.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-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.
diff --git a/lib/compiler/test/inline_SUITE_data/itracer.erl b/lib/compiler/test/inline_SUITE_data/itracer.erl
index 66122e33b5..a6df21f233 100644
--- a/lib/compiler/test/inline_SUITE_data/itracer.erl
+++ b/lib/compiler/test/inline_SUITE_data/itracer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/inline_SUITE_data/maps_inline_test.erl b/lib/compiler/test/inline_SUITE_data/maps_inline_test.erl
index 83ac8b2084..776a1a5950 100644
--- a/lib/compiler/test/inline_SUITE_data/maps_inline_test.erl
+++ b/lib/compiler/test/inline_SUITE_data/maps_inline_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-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.
diff --git a/lib/compiler/test/lc_SUITE.erl b/lib/compiler/test/lc_SUITE.erl
index d10839ccf2..9ad417b09b 100644
--- a/lib/compiler/test/lc_SUITE.erl
+++ b/lib/compiler/test/lc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2017. 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.
@@ -19,22 +19,24 @@
%%
-module(lc_SUITE).
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
+-export([all/0, suite/0, groups/0, init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
basic/1,deeply_nested/1,no_generator/1,
empty_generator/1,no_export/1,shadow/1,
effect/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,1}}].
-all() ->
+all() ->
test_lib:recompile(?MODULE),
[{group,p}].
-groups() ->
+groups() ->
[{p,test_lib:parallel(),
[basic,
deeply_nested,
@@ -59,12 +61,9 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = test_server:timetrap(?t:minutes(1)),
- [{watchdog,Dog}|Config].
+ Config.
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
ok.
basic(Config) when is_list(Config) ->
@@ -90,6 +89,18 @@ basic(Config) when is_list(Config) ->
%% Filter expressions with andalso/orelse.
"abc123" = alphanum("?abc123.;"),
+ %% Aliased patterns.
+ [] = [t || {C=D}={_,_} <- []],
+ [] = [X || {X,{Y}={X,X}} <- []],
+ [t] = [t || "a"++"b" = "ab" <- ["ab"]],
+
+ %% Strange filter block.
+ [] = [{X,Y} || {X} <- [], begin Y = X, Y =:= X end],
+ [{a,a}] = [{X,Y} || {X} <- [{a}], begin Y = X, Y =:= X end],
+
+ %% Not matching.
+ [] = [3 || {3=4} <- []],
+
%% Error cases.
[] = [{xx,X} || X <- L0, element(2, X) == no_no_no],
{'EXIT',_} = (catch [X || X <- L1, list_to_atom(X) == dum]),
@@ -171,7 +182,7 @@ no_gen_verify(Res, A, B) ->
ShouldBe -> ok;
_ ->
io:format("A = ~p; B = ~p; Expected = ~p, actual = ~p", [A,B,ShouldBe,Res]),
- ?t:fail()
+ ct:fail(failed)
end.
no_gen_eval(Fun, Res) ->
@@ -203,6 +214,7 @@ shadow(Config) when is_list(Config) ->
ok.
effect(Config) when is_list(Config) ->
+ ct:timetrap({minutes,10}),
[{42,{a,b,c}}] =
do_effect(fun(F, L) ->
[F({V1,V2}) ||
@@ -215,7 +227,7 @@ effect(Config) when is_list(Config) ->
lc_SUITE ->
_ = [{'EXIT',{badarg,_}} =
(catch binary_to_atom(<<C/utf8>>, utf8)) ||
- C <- lists:seq(16#10000, 16#FFFFF)];
+ C <- lists:seq(16#FF10000, 16#FFFFFFF)];
_ ->
ok
end,
@@ -229,7 +241,7 @@ do_effect(Lc, L) ->
lists:reverse(erase(?MODULE)).
id(I) -> I.
-
+
fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Args,_}|_]}}) -> ok;
fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Arity,_}|_]}})
when length(Args) =:= Arity ->
diff --git a/lib/compiler/test/lfe-core.patch b/lib/compiler/test/lfe-core.patch
new file mode 100644
index 0000000000..756d131e2c
--- /dev/null
+++ b/lib/compiler/test/lfe-core.patch
@@ -0,0 +1,97 @@
+Date: Sun, 13 Nov 2016 10:11:11 +0100
+Subject: [PATCH] Fix invalid variable names
+
+---
+ test/lfe_andor_SUITE.core | 16 ++++++++--------
+ test/lfe_guard_SUITE.core | 14 +++++++-------
+ 2 files changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/test/lfe_andor_SUITE.core b/test/lfe_andor_SUITE.core
+index 96ff765..df58b39 100644
+--- a/test/lfe_andor_SUITE.core
++++ b/test/lfe_andor_SUITE.core
+@@ -288,19 +288,19 @@ module 'lfe_andor_SUITE' ['$handle_undefined_function'/2,
+ 'lc$^0'/1 =
+ fun (_2) ->
+ case <_2> of
+- <[_x|_|-0-|]> when 'true' ->
++ <[_x|_lfe0]> when 'true' ->
+ letrec
+ 'lc$^1'/1 =
+ fun (_3) ->
+ case <_3> of
+- <[_y|_|-1-|]> when 'true' ->
++ <[_y|_lfe1]> when 'true' ->
+ let <_4> =
+ apply 'lc$^1'/1
+- (_|-1-|)
++ (_lfe1)
+ in [{_x,_y}|_4]
+ <[]> when 'true' ->
+ apply 'lc$^0'/1
+- (_|-0-|)
++ (_lfe0)
+ ( <_5> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_5})
+@@ -455,19 +455,19 @@ module 'lfe_andor_SUITE' ['$handle_undefined_function'/2,
+ 'lc$^2'/1 =
+ fun (_2) ->
+ case <_2> of
+- <[_x|_|-2-|]> when 'true' ->
++ <[_x|_lfe2]> when 'true' ->
+ letrec
+ 'lc$^3'/1 =
+ fun (_3) ->
+ case <_3> of
+- <[_y|_|-3-|]> when 'true' ->
++ <[_y|_lfe3]> when 'true' ->
+ let <_4> =
+ apply 'lc$^3'/1
+- (_|-3-|)
++ (_lfe3)
+ in [{_x,_y}|_4]
+ <[]> when 'true' ->
+ apply 'lc$^2'/1
+- (_|-2-|)
++ (_lfe2)
+ ( <_5> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_5})
+diff --git a/test/lfe_guard_SUITE.core b/test/lfe_guard_SUITE.core
+index 38f1d99..920be82 100644
+--- a/test/lfe_guard_SUITE.core
++++ b/test/lfe_guard_SUITE.core
+@@ -2857,22 +2857,22 @@ module 'lfe_guard_SUITE' ['$handle_undefined_function'/2,
+ 'false' ->
+ case <_t> of
+ <{_a,_b,_c,_d}> when 'true' ->
+- let <_|-0-|> =
++ let <_lfe0> =
+ <_a>
+- in let <_|-1-|> =
++ in let <_lfe1> =
+ <_b>
+- in let <_|-2-|> =
++ in let <_lfe2> =
+ <_c>
+- in let <_|-3-|> =
++ in let <_lfe3> =
+ <_d>
+ in let <_4> =
+ let <_3> =
+ call 'erlang':'+'
+- (_|-0-|, _|-1-|)
++ (_lfe0, _lfe1)
+ in call 'erlang':'+'
+- (_3, _|-2-|)
++ (_3, _lfe2)
+ in call 'erlang':'+'
+- (_4, _|-3-|)
++ (_4, _lfe3)
+ ( <_5> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_5}})
+--
+2.7.4 (Apple Git-66)
+
diff --git a/lib/compiler/test/lfe-source.patch b/lib/compiler/test/lfe-source.patch
new file mode 100644
index 0000000000..cbd6748bc9
--- /dev/null
+++ b/lib/compiler/test/lfe-source.patch
@@ -0,0 +1,117 @@
+Date: Sun, 13 Nov 2016 09:40:36 +0100
+Subject: [PATCH] Rename and fix up LFE test suites
+
+---
+ test/{andor_SUITE.lfe => lfe_andor_SUITE.lfe} | 16 ++++++++--------
+ test/{guard_SUITE.lfe => lfe_guard_SUITE.lfe} | 8 ++++----
+ 2 files changed, 12 insertions(+), 12 deletions(-)
+ rename test/{andor_SUITE.lfe => lfe_andor_SUITE.lfe} (97%)
+ rename test/{guard_SUITE.lfe => lfe_guard_SUITE.lfe} (99%)
+
+diff --git a/test/andor_SUITE.lfe b/test/lfe_andor_SUITE.lfe
+similarity index 97%
+rename from test/andor_SUITE.lfe
+rename to test/lfe_andor_SUITE.lfe
+index 64feddd..1802b3f 100644
+--- a/test/andor_SUITE.lfe
++++ b/test/lfe_andor_SUITE.lfe
+@@ -26,14 +26,14 @@
+
+ (include-file "test_server.lfe")
+
+-(defmodule andor_SUITE
++(defmodule lfe_andor_SUITE
+ (export (all 0) (suite 0) (groups 0) (init_per_suite 1) (end_per_suite 1)
+ (init_per_group 2) (end_per_group 2)
+ (t_case 1) (t_and_or 1) (t_andalso 1) (t_orelse 1) (inside 1)
+ (overlap 1) (combined 1) (in_case 1) (before_and_inside_if 1)
+ ))
+
+-(defmacro MODULE () `'andor_SUITE)
++(defmacro MODULE () `'lfe_andor_SUITE)
+
+ (defun all ()
+ ;; (: test_lib recompile (MODULE))
+@@ -206,7 +206,7 @@
+
+ (defun t-andalso-1
+ ([(tuple x y)]
+- (: lfe_io format '"(andalso ~w ~w): " (list x y))
++ (: io format '"(andalso ~w ~w): " (list x y))
+ (let* ((v0 (andalso (echo x) (echo y)))
+ (v1 (when (=:= v0 v1))
+ (eif (andalso x y) 'true 'true 'false)))
+@@ -248,7 +248,7 @@
+
+ (defun t-orelse-1
+ ([(tuple x y)]
+- (: lfe_io format '"(orelse ~w ~w): " (list x y))
++ (: io format '"(orelse ~w ~w): " (list x y))
+ (let* ((v0 (orelse (echo x) (echo y)))
+ (v1 (when (=:= v0 v1))
+ (eif (orelse x y) 'true 'true 'false)))
+@@ -289,7 +289,7 @@
+ (when (=:= r1 r2) (=:= xm xm2) (=:= ym ym2) (=:= x x2)
+ (=:= y y2) (=:= w w2) (=:= h h2))
+ (inside-guard xm ym x y w h)))
+- (: lfe_io fwrite
++ (: io fwrite
+ '"(andalso (=< ~p ~p) (< ~p ~p) (=< ~p ~p) (< ~p ~p)) ==> ~p\n"
+ (list x xm xm (+ x w) y ym ym (+ y h) r1)))
+ r1))
+@@ -499,12 +499,12 @@
+ ;; Utilities
+
+ (defun check (v1 v0)
+- (eif (/= v1 v0) (progn (: lfe_io fwrite '"error: ~w.\n" (list v1))
++ (eif (/= v1 v0) (progn (: io fwrite '"error: ~w.\n" (list v1))
+ (exit 'suite_failed))
+- 'true (: lfe_io fwrite '"ok: ~w.\n" (list v1))))
++ 'true (: io fwrite '"ok: ~w.\n" (list v1))))
+
+ (defun echo (x)
+- (: lfe_io fwrite '"(eval ~w); " (list x))
++ (: io fwrite '"(eval ~w); " (list x))
+ x)
+
+ ;; Call this function to turn off constant propagation.
+diff --git a/test/guard_SUITE.lfe b/test/lfe_guard_SUITE.lfe
+similarity index 99%
+rename from test/guard_SUITE.lfe
+rename to test/lfe_guard_SUITE.lfe
+index 33b1344..2eeb1a6 100644
+--- a/test/guard_SUITE.lfe
++++ b/test/lfe_guard_SUITE.lfe
+@@ -26,7 +26,7 @@
+
+ (include-file "test_server.lfe")
+
+-(defmodule guard_SUITE
++(defmodule lfe_guard_SUITE
+ (export (all 0) (suite 0) (groups 0) (init_per_suite 1) (end_per_suite 1)
+ (init_per_group 2) (end_per_group 2)
+ (misc 1) (const_cond 1) (basic_not 1) (complex_not 1) (nested_nots 1)
+@@ -42,7 +42,7 @@
+ (check_qlc_hrl 1) (andalso_semi 1) (t_tuple_size 1) (binary_part 1)
+ ))
+
+-(defmacro MODULE () `'guard_SUITE)
++(defmacro MODULE () `'lfe_guard_SUITE)
+
+ (defun all ()
+ ;; (: test_lib recompile (MODULE))
+@@ -764,9 +764,9 @@
+
+ (defun is_function_2
+ ([config] (when (is_list config))
+- (line (test-pat 'true (is_function (id (function guard_SUITE all 1)) 1)))
++ (line (test-pat 'true (is_function (id (function lfe_guard_SUITE all 1)) 1)))
+ (line (test-pat 'true (is_function (id (lambda () 'ok)) 0)))
+- (line (test-pat 'false (is_function (id (function guard_SUITE all 1)) 0)))
++ (line (test-pat 'false (is_function (id (function lfe_guard_SUITE all 1)) 0)))
+ (line (test-pat 'false (is_function (id (lambda () 'ok)) 1)))
+
+ (let ((F (lambda (_) 'ok)))
+--
+2.7.4 (Apple Git-66)
+
diff --git a/lib/compiler/test/lfe.readme b/lib/compiler/test/lfe.readme
new file mode 100644
index 0000000000..2fc88e0252
--- /dev/null
+++ b/lib/compiler/test/lfe.readme
@@ -0,0 +1,31 @@
+Creating the LFE-derived test suites
+====================================
+
+Here is how to create `lfe_andor_SUITE.core` and `lfe_guard_SUITE.core`
+files.
+
+First clone and build LFE.
+
+ git clone https://github.com/rvirding/lfe.git
+ cd lfe
+ git checkout v1.2.0
+ MAKEFLAGS='' make compile
+ export PATH=$(pwd)/bin:$PATH
+
+Apply the source patch to rename and fix up the LFE source code:
+
+ cd test
+ git apply $ERL_TOP/lib/compiler/test/lfe-source.patch
+ git reset --hard HEAD
+
+Compile the modules to Core Erlang:
+
+ lfec +to-core0 lfe*.lfe
+
+Apply the core patch to correct some invalid variable names:
+
+ git apply $ERL_TOP/lib/compiler/test/lfe-core.patch
+
+Copy the patched .core file to the test suite:
+
+ cp lfe*.core $ERL_TOP/lib/compiler/test
diff --git a/lib/compiler/test/lfe_andor_SUITE.core b/lib/compiler/test/lfe_andor_SUITE.core
new file mode 100644
index 0000000000..df58b39ae6
--- /dev/null
+++ b/lib/compiler/test/lfe_andor_SUITE.core
@@ -0,0 +1,2014 @@
+module 'lfe_andor_SUITE' ['$handle_undefined_function'/2,
+ 'LFE-EXPAND-EXPORTED-MACRO'/3,
+ 'all'/0,
+ 'before_and_inside_if'/1,
+ 'combined'/1,
+ 'end_per_group'/2,
+ 'end_per_suite'/1,
+ 'groups'/0,
+ 'in_case'/1,
+ 'init_per_group'/2,
+ 'init_per_suite'/1,
+ 'inside'/1,
+ 'module_info'/0,
+ 'module_info'/1,
+ 'overlap'/1,
+ 'suite'/0,
+ 't_and_or'/1,
+ 't_andalso'/1,
+ 't_case'/1,
+ 't_orelse'/1]
+ attributes []
+'all'/0 =
+ %% Line 38
+ fun () ->
+ ['t_case'|['t_and_or'|['t_andalso'|['t_orelse'|['inside'|['overlap'|['combined'|['in_case'|['before_and_inside_if']]]]]]]]]
+'suite'/0 =
+ %% Line 44
+ fun () ->
+ []
+'groups'/0 =
+ %% Line 46
+ fun () ->
+ []
+'init_per_suite'/1 =
+ %% Line 48
+ fun (_config) ->
+ _config
+'end_per_suite'/1 =
+ %% Line 50
+ fun (_config) ->
+ 'ok'
+'init_per_group'/2 =
+ %% Line 52
+ fun (_name,_config) ->
+ _config
+'end_per_group'/2 =
+ %% Line 54
+ fun (_name,_config) ->
+ _config
+'t_case'/1 =
+ %% Line 56
+ fun (_0) ->
+ case <_0> of
+ <'suite'> when 'true' ->
+ []
+ <'doc'> when 'true' ->
+ [84|[101|[115|[116|[32|[105|[110|[32|[99|[97|[115|[101|[46]]]]]]]]]]]]]
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_andor_SUITE',['test-pat'|[['quote'|['less']]|[['t-case-a'|[1|[2]]]]]]})
+ let <_val> =
+ <apply 't-case-a'/2
+ (1, 2)>
+ in case <_val> of
+ <'less'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_25> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_25})
+ -| [{'function_name',{'t_case',1}}] )
+ -| ['compiler_generated'] )
+ end
+'t-case-a'/2 =
+ %% Line 94
+ fun (_a,_b) ->
+ case call 'erlang':'<'
+ (_a, _b) of
+ <[_0|_1]> when 'true' ->
+ 'ok'
+ <'true'> when 'true' ->
+ 'less'
+ <'false'> when 'true' ->
+ 'not_less'
+ <{'a','b','c'}> when 'true' ->
+ 'ok'
+ <_2> when 'true' ->
+ 'ok'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'t-case-b'/2 =
+ %% Line 102
+ fun (_a,_b) ->
+ case call 'erlang':'=:='
+ (_a, _b) of
+ <'blurf'> when 'true' ->
+ 'ok'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'t-case-c'/2 =
+ %% Line 106
+ fun (_a,_b) ->
+ case let <_0> =
+ call 'erlang':'=:='
+ (_a, _b)
+ in call 'erlang':'not'
+ (_0) of
+ <'true'> when 'true' ->
+ 'ne'
+ <'false'> when 'true' ->
+ 'eq'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'t-case-d'/3 =
+ %% Line 111
+ fun (_a,_b,_x) ->
+ case let <_0> =
+ call 'erlang':'=:='
+ (_a, _b)
+ in call 'erlang':'and'
+ (_0, _x) of
+ <'true'> when 'true' ->
+ 't'
+ <'false'> when 'true' ->
+ 'f'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'t-case-e'/2 =
+ %% Line 116
+ fun (_a,_b) ->
+ case call 'erlang':'=:='
+ (_a, _b) of
+ <_bool>
+ when try
+ let <_0> =
+ call 'erlang':'is_tuple'
+ (_a)
+ in _0
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ apply 'id'/1
+ (_bool)
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'t-case-xy'/3 =
+ %% Line 120
+ fun (_x,_y,_z) ->
+ let <_r0> =
+ <apply 't-case-x'/3
+ (_x, _y, _z)>
+ in case <apply 't-case-y'/3
+ (_x, _y, _z)> of
+ <_res>
+ when try
+ let <_0> =
+ call 'erlang':'=:='
+ (_res, _r0)
+ in _0
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ _res
+ ( <_1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_1}})
+ -| ['compiler_generated'] )
+ end
+'t-case-x'/3 =
+ %% Line 125
+ fun (_x,_y,_z) ->
+ case let <_0> =
+ call 'erlang':'abs'
+ (_x)
+ in call 'erlang':'=:='
+ (_0, 42) of
+ <'true'> when 'true' ->
+ call 'erlang':'=:='
+ (_y, 100)
+ <'false'> when 'true' ->
+ call 'erlang':'=:='
+ (_z, 700)
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'t-case-y'/3 =
+ %% Line 130
+ fun (_x,_y,_z) ->
+ case let <_0> =
+ call 'erlang':'abs'
+ (_x)
+ in call 'erlang':'=:='
+ (_0, 42) of
+ <'false'> when 'true' ->
+ call 'erlang':'=:='
+ (_z, 700)
+ <'true'> when 'true' ->
+ call 'erlang':'=:='
+ (_y, 100)
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'t_and_or'/1 =
+ %% Line 135
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_andor_SUITE',['test-pat'|[['quote'|['true']]|[['and'|[['quote'|['true']]|[['quote'|['true']]]]]]]]})
+ let <_val> =
+ <call 'erlang':'and'
+ ('true', 'true')>
+ in case <_val> of
+ <'true'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_42> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_42})
+ -| [{'function_name',{'t_and_or',1}}] )
+ -| ['compiler_generated'] )
+ end
+'t_andalso'/1 =
+ %% Line 172
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do let <_bs> =
+ <['true'|['false']]>
+ in let <_ps> =
+ <letrec
+ 'lc$^0'/1 =
+ fun (_2) ->
+ case <_2> of
+ <[_x|_lfe0]> when 'true' ->
+ letrec
+ 'lc$^1'/1 =
+ fun (_3) ->
+ case <_3> of
+ <[_y|_lfe1]> when 'true' ->
+ let <_4> =
+ apply 'lc$^1'/1
+ (_lfe1)
+ in [{_x,_y}|_4]
+ <[]> when 'true' ->
+ apply 'lc$^0'/1
+ (_lfe0)
+ ( <_5> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_5})
+ -| [{'function_name',{'t_andalso',1}}] )
+ -| ['compiler_generated'] )
+ end
+ in apply 'lc$^1'/1
+ (_bs)
+ <[]> when 'true' ->
+ []
+ ( <_6> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_6})
+ -| [{'function_name',{'t_andalso',1}}] )
+ -| ['compiler_generated'] )
+ end
+ in apply 'lc$^0'/1
+ (_bs)>
+ in let <_7> =
+ fun (_p) ->
+ apply 't-andalso-1'/1
+ (_p)
+ in call 'lists':'foreach'
+ (_7, _ps)
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_andor_SUITE',['test-pat'|[['quote'|['true']]|[['andalso'|[['quote'|['true']]|[['quote'|['true']]]]]]]]})
+ let <_val> =
+ <case 'true' of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end>
+ in case <_val> of
+ <'true'> when 'true' ->
+ _val
+ ( <_8> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_8}})
+ -| ['compiler_generated'] )
+ end
+ ( <_57> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_57})
+ -| [{'function_name',{'t_andalso',1}}] )
+ -| ['compiler_generated'] )
+ end
+'t-andalso-1'/1 =
+ %% Line 207
+ fun (_0) ->
+ case <_0> of
+ <{_x,_y}> when 'true' ->
+ do call 'io':'format'
+ ([40|[97|[110|[100|[97|[108|[115|[111|[32|[126|[119|[32|[126|[119|[41|[58|[32]]]]]]]]]]]]]]]]], [_x,_y])
+ let <_v0> =
+ <case apply 'echo'/1
+ (_x) of
+ <'true'> when 'true' ->
+ apply 'echo'/1
+ (_y)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end>
+ in case <case 1 of
+ <_1>
+ when try
+ let <_3> =
+ let <_2> =
+ case _x of
+ <'true'> when 'true' ->
+ _y
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_2, 'true')
+ -| ['compiler_generated'] )
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_4>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <_v1>
+ when try
+ let <_5> =
+ call 'erlang':'=:='
+ (_v0, _v1)
+ in _5
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_6> =
+ call 'erlang':'and'
+ (_x, _y)
+ in apply 'check'/2
+ (_v1, _6)
+ ( <_7> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_7}})
+ -| ['compiler_generated'] )
+ end
+ ( <_8> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_8})
+ -| [{'function_name',{'t-andalso-1',1}}] )
+ -| ['compiler_generated'] )
+ end
+'t_orelse'/1 =
+ %% Line 215
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do let <_bs> =
+ <['true'|['false']]>
+ in let <_ps> =
+ <letrec
+ 'lc$^2'/1 =
+ fun (_2) ->
+ case <_2> of
+ <[_x|_lfe2]> when 'true' ->
+ letrec
+ 'lc$^3'/1 =
+ fun (_3) ->
+ case <_3> of
+ <[_y|_lfe3]> when 'true' ->
+ let <_4> =
+ apply 'lc$^3'/1
+ (_lfe3)
+ in [{_x,_y}|_4]
+ <[]> when 'true' ->
+ apply 'lc$^2'/1
+ (_lfe2)
+ ( <_5> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_5})
+ -| [{'function_name',{'t_orelse',1}}] )
+ -| ['compiler_generated'] )
+ end
+ in apply 'lc$^3'/1
+ (_bs)
+ <[]> when 'true' ->
+ []
+ ( <_6> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_6})
+ -| [{'function_name',{'t_orelse',1}}] )
+ -| ['compiler_generated'] )
+ end
+ in apply 'lc$^2'/1
+ (_bs)>
+ in let <_7> =
+ fun (_p) ->
+ apply 't-orelse-1'/1
+ (_p)
+ in call 'lists':'foreach'
+ (_7, _ps)
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_andor_SUITE',['test-pat'|[['quote'|['true']]|[['orelse'|[['quote'|['true']]|[['quote'|['true']]]]]]]]})
+ let <_val> =
+ <case 'true' of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ 'true'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end>
+ in case <_val> of
+ <'true'> when 'true' ->
+ _val
+ ( <_8> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_8}})
+ -| ['compiler_generated'] )
+ end
+ ( <_57> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_57})
+ -| [{'function_name',{'t_orelse',1}}] )
+ -| ['compiler_generated'] )
+ end
+'t-orelse-1'/1 =
+ %% Line 249
+ fun (_0) ->
+ case <_0> of
+ <{_x,_y}> when 'true' ->
+ do call 'io':'format'
+ ([40|[111|[114|[101|[108|[115|[101|[32|[126|[119|[32|[126|[119|[41|[58|[32]]]]]]]]]]]]]]]], [_x,_y])
+ let <_v0> =
+ <case apply 'echo'/1
+ (_x) of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ apply 'echo'/1
+ (_y)
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end>
+ in case <case 1 of
+ <_1>
+ when try
+ let <_3> =
+ let <_2> =
+ case _x of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ _y
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_2, 'true')
+ -| ['compiler_generated'] )
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_4>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <_v1>
+ when try
+ let <_5> =
+ call 'erlang':'=:='
+ (_v0, _v1)
+ in _5
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_6> =
+ call 'erlang':'or'
+ (_x, _y)
+ in apply 'check'/2
+ (_v1, _6)
+ ( <_7> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_7}})
+ -| ['compiler_generated'] )
+ end
+ ( <_8> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_8})
+ -| [{'function_name',{'t-orelse-1',1}}] )
+ -| ['compiler_generated'] )
+ end
+'inside'/1 =
+ %% Line 257
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_andor_SUITE',['test-pat'|[['quote'|['true']]|[['inside'|[-8|[1]]]]]]})
+ let <_val> =
+ <apply 'inside'/2
+ (-8, 1)>
+ in case <_val> of
+ <'true'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_12> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_12})
+ -| [{'function_name',{'inside',1}}] )
+ -| ['compiler_generated'] )
+ end
+'inside'/2 =
+ %% Line 272
+ fun (_xm,_ym) ->
+ let <_x> =
+ <-1.00000000000000000000e+01>
+ in let <_y> =
+ <-2.00000000000000000000e+00>
+ in let <_w> =
+ <2.00000000000000000000e+01>
+ in let <_h> =
+ <4.00000000000000000000e+00>
+ in let <_r0> =
+ <apply 'inside'/6
+ (_xm, _ym, _x, _y, _w, _h)>
+ in case <case 1 of
+ <_0>
+ when try
+ let <_4> =
+ let <_3> =
+ case call 'erlang':'=<'
+ (_x, _xm) of
+ <'true'> when 'true' ->
+ case let <_1> =
+ call 'erlang':'+'
+ (_x, _w)
+ in call 'erlang':'<'
+ (_xm, _1) of
+ <'true'> when 'true' ->
+ case call 'erlang':'=<'
+ (_y, _ym) of
+ <'true'> when 'true' ->
+ let <_2> =
+ call 'erlang':'+'
+ (_y, _h)
+ in call 'erlang':'<'
+ (_ym, _2)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_3, 'true')
+ -| ['compiler_generated'] )
+ in _4
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_5>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <_r1>
+ when try
+ let <_6> =
+ call 'erlang':'=:='
+ (_r0, _r1)
+ in _6
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do case let <_7> =
+ apply 'id'/1
+ (_r1)
+ in call 'erlang':'not'
+ (_7) of
+ <_o0> when 'true' ->
+ case <case 1 of
+ <_8>
+ when try
+ let <_12> =
+ let <_11> =
+ case call 'erlang':'=<'
+ (_x, _xm) of
+ <'true'> when 'true' ->
+ case let <_9> =
+ call 'erlang':'+'
+ (_x, _w)
+ in call 'erlang':'<'
+ (_xm, _9) of
+ <'true'> when 'true' ->
+ case call 'erlang':'=<'
+ (_y, _ym) of
+ <'true'> when 'true' ->
+ let <_10> =
+ call 'erlang':'+'
+ (_y, _h)
+ in call 'erlang':'<'
+ (_ym, _10)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in call 'erlang':'not'
+ (_11)
+ in _12
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_13>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <_o1>
+ when try
+ let <_14> =
+ call 'erlang':'=:='
+ (_o0, _o1)
+ in _14
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ _o1
+ ( <_15> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_15}})
+ -| ['compiler_generated'] )
+ end
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ do case <apply 'inside-guard'/6
+ (_xm, _ym, _x, _y, _w, _h)> of
+ <{_r2,_xm2,_ym2,_x2,_y2,_w2,_h2}>
+ when try
+ let <_16> =
+ call 'erlang':'=:='
+ (_r1, _r2)
+ in let <_17> =
+ call 'erlang':'=:='
+ (_xm, _xm2)
+ in let <_18> =
+ call 'erlang':'=:='
+ (_ym, _ym2)
+ in let <_19> =
+ call 'erlang':'=:='
+ (_x, _x2)
+ in let <_20> =
+ call 'erlang':'=:='
+ (_y, _y2)
+ in let <_21> =
+ call 'erlang':'=:='
+ (_w, _w2)
+ in let <_22> =
+ call 'erlang':'=:='
+ (_h, _h2)
+ in let <_23> =
+ call 'erlang':'and'
+ (_16, _17)
+ in let <_24> =
+ call 'erlang':'and'
+ (_23, _18)
+ in let <_25> =
+ call 'erlang':'and'
+ (_24, _19)
+ in let <_26> =
+ call 'erlang':'and'
+ (_25, _20)
+ in let <_27> =
+ call 'erlang':'and'
+ (_26, _21)
+ in call 'erlang':'and'
+ (_27, _22)
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_30> =
+ let <_28> =
+ call 'erlang':'+'
+ (_x, _w)
+ in let <_29> =
+ call 'erlang':'+'
+ (_y, _h)
+ in [_x,_xm,_xm,_28,_y,_ym,_ym,_29,_r1]
+ in call 'io':'fwrite'
+ ([40|[97|[110|[100|[97|[108|[115|[111|[32|[40|[61|[60|[32|[126|[112|[32|[126|[112|[41|[32|[40|[60|[32|[126|[112|[32|[126|[112|[41|[32|[40|[61|[60|[32|[126|[112|[32|[126|[112|[41|[32|[40|[60|[32|[126|[112|[32|[126|[112|[41|[41|[32|[61|[61|[62|[32|[126|[112|[10]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], _30)
+ ( <_31> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_31}})
+ -| ['compiler_generated'] )
+ end
+ _r1
+ ( <_32> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_32}})
+ -| ['compiler_generated'] )
+ end
+'inside'/6 =
+ %% Line 297
+ fun (_xm,_ym,_x,_y,_w,_h) ->
+ case call 'erlang':'=<'
+ (_x, _xm) of
+ <'true'> when 'true' ->
+ case let <_0> =
+ call 'erlang':'+'
+ (_x, _w)
+ in call 'erlang':'<'
+ (_xm, _0) of
+ <'true'> when 'true' ->
+ case call 'erlang':'=<'
+ (_y, _ym) of
+ <'true'> when 'true' ->
+ let <_1> =
+ call 'erlang':'+'
+ (_y, _h)
+ in call 'erlang':'<'
+ (_ym, _1)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end
+'inside-guard'/6 =
+ %% Line 300
+ fun (_5,_4,_3,_2,_1,_0) ->
+ case <_5,_4,_3,_2,_1,_0> of
+ <_xm,_ym,_x,_y,_w,_h>
+ when try
+ let <_9> =
+ let <_8> =
+ case call 'erlang':'=<'
+ (_x, _xm) of
+ <'true'> when 'true' ->
+ case let <_6> =
+ call 'erlang':'+'
+ (_x, _w)
+ in call 'erlang':'<'
+ (_xm, _6) of
+ <'true'> when 'true' ->
+ case call 'erlang':'=<'
+ (_y, _ym) of
+ <'true'> when 'true' ->
+ let <_7> =
+ call 'erlang':'+'
+ (_y, _h)
+ in call 'erlang':'<'
+ (_ym, _7)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_8, 'true')
+ -| ['compiler_generated'] )
+ in _9
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ {'true',_xm,_ym,_x,_y,_w,_h}
+ <_xm,_ym,_x,_y,_w,_h> when 'true' ->
+ {'false',_xm,_ym,_x,_y,_w,_h}
+ ( <_15,_14,_13,_12,_11,_10> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_15,_14,_13,_12,_11,_10})
+ -| [{'function_name',{'inside-guard',6}}] )
+ -| ['compiler_generated'] )
+ end
+'overlap'/1 =
+ %% Line 307
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_andor_SUITE',['test-pat'|[['quote'|['true']]|[['overlap'|[7.00000000000000000000e+00|[2.00000000000000000000e+00|[8.00000000000000000000e+00|[5.00000000000000000000e-01]]]]]]]]})
+ let <_val> =
+ <apply 'overlap'/4
+ (7.00000000000000000000e+00, 2.00000000000000000000e+00, 8.00000000000000000000e+00, 5.00000000000000000000e-01)>
+ in case <_val> of
+ <'true'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_10> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_10})
+ -| [{'function_name',{'overlap',1}}] )
+ -| ['compiler_generated'] )
+ end
+'overlap'/4 =
+ %% Line 321
+ fun (_pos1,_len1,_pos2,_len2) ->
+ let <_r0> =
+ <case _pos1 of
+ <_pos1>
+ when try
+ let <_3> =
+ let <_2> =
+ case case call 'erlang':'=<'
+ (_pos2, _pos1) of
+ <'true'> when 'true' ->
+ let <_0> =
+ call 'erlang':'+'
+ (_pos2, _len2)
+ in call 'erlang':'<'
+ (_pos1, _0)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ case call 'erlang':'=<'
+ (_pos1, _pos2) of
+ <'true'> when 'true' ->
+ let <_1> =
+ call 'erlang':'+'
+ (_pos1, _len1)
+ in call 'erlang':'<'
+ (_pos2, _1)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_2, 'true')
+ -| ['compiler_generated'] )
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_pos1> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end>
+ in case <case case call 'erlang':'=<'
+ (_pos2, _pos1) of
+ <'true'> when 'true' ->
+ let <_4> =
+ call 'erlang':'+'
+ (_pos2, _len2)
+ in call 'erlang':'<'
+ (_pos1, _4)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ case call 'erlang':'=<'
+ (_pos1, _pos2) of
+ <'true'> when 'true' ->
+ let <_5> =
+ call 'erlang':'+'
+ (_pos1, _len1)
+ in call 'erlang':'<'
+ (_pos2, _5)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end> of
+ <_r1>
+ when try
+ let <_6> =
+ call 'erlang':'=:='
+ (_r0, _r1)
+ in _6
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ case <case _pos1 of
+ <_pos1>
+ when try
+ let <_10> =
+ let <_9> =
+ case case call 'erlang':'=<'
+ (_pos2, _pos1) of
+ <'true'> when 'true' ->
+ let <_7> =
+ call 'erlang':'+'
+ (_pos2, _len2)
+ in call 'erlang':'<'
+ (_pos1, _7)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ case call 'erlang':'=<'
+ (_pos1, _pos2) of
+ <'true'> when 'true' ->
+ let <_8> =
+ call 'erlang':'+'
+ (_pos1, _len1)
+ in call 'erlang':'<'
+ (_pos2, _8)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_9, 'true')
+ -| ['compiler_generated'] )
+ in _10
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_pos1> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <_r2>
+ when try
+ let <_11> =
+ call 'erlang':'=:='
+ (_r2, _r1)
+ in _11
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ apply 'id'/1
+ (_r2)
+ ( <_12> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_12}})
+ -| ['compiler_generated'] )
+ end
+ ( <_13> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_13}})
+ -| ['compiler_generated'] )
+ end
+'combined'/1 =
+ %% Line 348
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_andor_SUITE',['test-pat'|[['quote'|['false']]|[['comb'|[['quote'|['false']]|[['quote'|['false']]|[['quote'|['false']]]]]]]]]})
+ let <_val> =
+ <apply 'comb'/3
+ ('false', 'false', 'false')>
+ in case <_val> of
+ <'false'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_26> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_26})
+ -| [{'function_name',{'combined',1}}] )
+ -| ['compiler_generated'] )
+ end
+'comb'/3 =
+ %% Line 383
+ fun (_a,_b,_c) ->
+ let <_r0> =
+ <case case _a of
+ <'true'> when 'true' ->
+ _b
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ _c
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end>
+ in case <case 1 of
+ <_0>
+ when try
+ let <_2> =
+ let <_1> =
+ case case _a of
+ <'true'> when 'true' ->
+ _b
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ _c
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_1, 'true')
+ -| ['compiler_generated'] )
+ in _2
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_3>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <_r1>
+ when try
+ let <_4> =
+ call 'erlang':'=:='
+ (_r0, _r1)
+ in _4
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_n0> =
+ <case 1 of
+ <_5>
+ when try
+ let <_7> =
+ let <_6> =
+ case case _a of
+ <'true'> when 'true' ->
+ _b
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ _c
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in call 'erlang':'not'
+ (_6)
+ in _7
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_8>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end>
+ in case <let <_9> =
+ call 'erlang':'not'
+ (_r1)
+ in apply 'id'/1
+ (_9)> of
+ <_n1>
+ when try
+ let <_10> =
+ call 'erlang':'=:='
+ (_n0, _n1)
+ in _10
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ case <case case _a of
+ <'true'> when 'true' ->
+ _b
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ _c
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end> of
+ <_r2>
+ when try
+ let <_11> =
+ call 'erlang':'=:='
+ (_r1, _r2)
+ in _11
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ case <case 1 of
+ <_12>
+ when try
+ let <_14> =
+ let <_13> =
+ case case _a of
+ <'true'> when 'true' ->
+ _b
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ _c
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_13, 'true')
+ -| ['compiler_generated'] )
+ in _14
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_15>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <_r3>
+ when try
+ let <_16> =
+ call 'erlang':'=:='
+ (_r2, _r3)
+ in _16
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ case <let <_17> =
+ call 'erlang':'not'
+ (_r3)
+ in apply 'id'/1
+ (_17)> of
+ <_n2>
+ when try
+ let <_18> =
+ call 'erlang':'=:='
+ (_n1, _n2)
+ in _18
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ case <case 1 of
+ <_19>
+ when try
+ let <_21> =
+ let <_20> =
+ case case _a of
+ <'true'> when 'true' ->
+ _b
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ _c
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_20, 'true')
+ -| ['compiler_generated'] )
+ in _21
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_22>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <_r4>
+ when try
+ let <_23> =
+ call 'erlang':'=:='
+ (_r3, _r4)
+ in _23
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ apply 'id'/1
+ (_r4)
+ ( <_24> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_24}})
+ -| ['compiler_generated'] )
+ end
+ ( <_25> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_25}})
+ -| ['compiler_generated'] )
+ end
+ ( <_26> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_26}})
+ -| ['compiler_generated'] )
+ end
+ ( <_27> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_27}})
+ -| ['compiler_generated'] )
+ end
+ ( <_28> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_28}})
+ -| ['compiler_generated'] )
+ end
+ ( <_29> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_29}})
+ -| ['compiler_generated'] )
+ end
+'in_case'/1 =
+ %% Line 402
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_andor_SUITE',['test-pat'|[['quote'|['edge_rings']]|[['in-case-1'|[1|[1|[1|[1|[1]]]]]]]]]})
+ let <_val> =
+ <apply 'in-case-1'/5
+ (1, 1, 1, 1, 1)>
+ in case <_val> of
+ <'edge_rings'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_13> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_13})
+ -| [{'function_name',{'in_case',1}}] )
+ -| ['compiler_generated'] )
+ end
+'in-case-1'/5 =
+ %% Line 419
+ fun (_lenup,_lendw,_lenn,_rot,_count) ->
+ let <_r0> =
+ <apply 'in-case-1-body'/5
+ (_lenup, _lendw, _lenn, _rot, _count)>
+ in case <apply 'in-case-1-guard'/5
+ (_lenup, _lendw, _lenn, _rot, _count)> of
+ <_res>
+ when try
+ let <_0> =
+ call 'erlang':'=:='
+ (_r0, _res)
+ in _0
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ _res
+ ( <_1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_1}})
+ -| ['compiler_generated'] )
+ end
+'in-case-1-body'/5 =
+ %% Line 425
+ fun (_lenup,_lendw,_lenn,_rot,_count) ->
+ case let <_5> =
+ let <_2> =
+ let <_0> =
+ call 'erlang':'/'
+ (_lenup, _count)
+ in call 'erlang':'>'
+ (_0, 7.06999999999999961808e-01)
+ in let <_3> =
+ let <_1> =
+ call 'erlang':'/'
+ (_lenn, _count)
+ in call 'erlang':'>'
+ (_1, 7.06999999999999961808e-01)
+ in call 'erlang':'and'
+ (_2, _3)
+ in let <_6> =
+ let <_4> =
+ call 'erlang':'abs'
+ (_rot)
+ in call 'erlang':'>'
+ (_4, 7.06999999999999961808e-01)
+ in call 'erlang':'and'
+ (_5, _6) of
+ <'true'> when 'true' ->
+ 'edge_rings'
+ <'false'> when 'true' ->
+ case let <_11> =
+ let <_9> =
+ let <_7> =
+ call 'erlang':'>='
+ (_lenup, 1)
+ in let <_8> =
+ call 'erlang':'>='
+ (_lendw, 1)
+ in call 'erlang':'or'
+ (_7, _8)
+ in let <_10> =
+ call 'erlang':'=<'
+ (_lenn, 1)
+ in call 'erlang':'or'
+ (_9, _10)
+ in let <_12> =
+ call 'erlang':'>'
+ (_count, 4)
+ in call 'erlang':'or'
+ (_11, _12) of
+ <'true'> when 'true' ->
+ 'not_loop'
+ <'false'> when 'true' ->
+ 'loop'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'in-case-1-guard'/5 =
+ %% Line 435
+ fun (_lenup,_lendw,_lenn,_rot,_count) ->
+ case case let <_0> =
+ call 'erlang':'/'
+ (_lenup, _count)
+ in call 'erlang':'>'
+ (_0, 7.06999999999999961808e-01) of
+ <'true'> when 'true' ->
+ case let <_1> =
+ call 'erlang':'/'
+ (_lenn, _count)
+ in call 'erlang':'>'
+ (_1, 7.06999999999999961808e-01) of
+ <'true'> when 'true' ->
+ let <_2> =
+ call 'erlang':'abs'
+ (_rot)
+ in call 'erlang':'>'
+ (_2, 7.06999999999999961808e-01)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ('if_clause')
+ -| ['compiler_generated'] )
+ end of
+ <'true'> when 'true' ->
+ 'edge_rings'
+ <'false'>
+ when try
+ let <_4> =
+ let <_3> =
+ case call 'erlang':'>='
+ (_lenup, 1) of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ case call 'erlang':'>='
+ (_lendw, 1) of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ case call 'erlang':'=<'
+ (_lenn, 1) of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ call 'erlang':'<'
+ (_count, 4)
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_3, 'true')
+ -| ['compiler_generated'] )
+ in _4
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'not_loop'
+ <'false'> when 'true' ->
+ 'loop'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'before_and_inside_if'/1 =
+ %% Line 443
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_andor_SUITE',['test-pat'|[['quote'|['no']]|[['before-and-inside-if'|[['quote'|[['a']]]|[['quote'|[['b']]]|[['quote'|['delete']]]]]]]]]})
+ let <_val> =
+ <apply 'before-and-inside-if'/3
+ (['a'], ['b'], 'delete')>
+ in case <_val> of
+ <'no'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_18> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_18})
+ -| [{'function_name',{'before_and_inside_if',1}}] )
+ -| ['compiler_generated'] )
+ end
+'before-and-inside-if'/3 =
+ %% Line 468
+ fun (XDo1,XDo2,Do3) ->
+ let <Do1> =
+ <call 'erlang':'=/='
+ (XDo1, [])>
+ in let <Do2> =
+ <call 'erlang':'=/='
+ (XDo2, [])>
+ in case 1 of
+ <_0>
+ when try
+ let <_7> =
+ let <_5> =
+ call 'erlang':'=:='
+ (Do1, 'true')
+ in let <_6> =
+ let <_3> =
+ let <_1> =
+ call 'erlang':'=:='
+ (Do1, 'false')
+ in let <_2> =
+ call 'erlang':'=:='
+ (Do2, 'false')
+ in call 'erlang':'and'
+ (_1, _2)
+ in let <_4> =
+ call 'erlang':'=:='
+ (Do3, 'delete')
+ in call 'erlang':'and'
+ (_3, _4)
+ in call 'erlang':'or'
+ (_5, _6)
+ in _7
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'no'
+ <_8>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'yes'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'before-and-inside-if-2'/3 =
+ %% Line 484
+ fun (XDo1,XDo2,Do3) ->
+ let <Do1> =
+ <call 'erlang':'=/='
+ (XDo1, [])>
+ in let <Do2> =
+ <call 'erlang':'=/='
+ (XDo2, [])>
+ in let <CH1> =
+ <case 1 of
+ <_0>
+ when try
+ let <_7> =
+ let <_5> =
+ call 'erlang':'=='
+ (Do1, 'true')
+ in let <_6> =
+ let <_3> =
+ let <_1> =
+ call 'erlang':'=='
+ (Do1, 'false')
+ in let <_2> =
+ call 'erlang':'=='
+ (Do2, 'false')
+ in call 'erlang':'and'
+ (_1, _2)
+ in let <_4> =
+ call 'erlang':'=='
+ (Do3, 'blah')
+ in call 'erlang':'and'
+ (_3, _4)
+ in call 'erlang':'or'
+ (_5, _6)
+ in _7
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ch1'
+ <_8>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'no'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end>
+ in let <CH2> =
+ <case 1 of
+ <_9>
+ when try
+ let <_16> =
+ let <_14> =
+ call 'erlang':'=='
+ (Do1, 'true')
+ in let <_15> =
+ let <_12> =
+ let <_10> =
+ call 'erlang':'=='
+ (Do1, 'false')
+ in let <_11> =
+ call 'erlang':'=='
+ (Do2, 'false')
+ in call 'erlang':'and'
+ (_10, _11)
+ in let <_13> =
+ call 'erlang':'=='
+ (Do3, 'xx')
+ in call 'erlang':'and'
+ (_12, _13)
+ in call 'erlang':'or'
+ (_14, _15)
+ in _16
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ch2'
+ <_17>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'no'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end>
+ in {CH1,CH2}
+'check'/2 =
+ %% Line 501
+ fun (_v1,_v0) ->
+ case 1 of
+ <_0>
+ when try
+ let <_1> =
+ call 'erlang':'/='
+ (_v1, _v0)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'io':'fwrite'
+ ([101|[114|[114|[111|[114|[58|[32|[126|[119|[46|[10]]]]]]]]]]], [_v1])
+ call 'erlang':'exit'
+ ('suite_failed')
+ <_2>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ call 'io':'fwrite'
+ ([111|[107|[58|[32|[126|[119|[46|[10]]]]]]]], [_v1])
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'echo'/1 =
+ %% Line 506
+ fun (_x) ->
+ do call 'io':'fwrite'
+ ([40|[101|[118|[97|[108|[32|[126|[119|[41|[59|[32]]]]]]]]]]], [_x])
+ _x
+'id'/1 =
+ %% Line 511
+ fun (_i) ->
+ _i
+'$handle_undefined_function'/2 =
+ %% Line 29
+ fun (_f,_as) ->
+ case let <_0> =
+ call 'lfe_env':'new'
+ ()
+ in apply 'LFE-EXPAND-EXPORTED-MACRO'/3
+ (_f, _as, _0) of
+ <{'yes',_exp}> when 'true' ->
+ call 'lfe_eval':'expr'
+ (_exp)
+ <'no'> when 'true' ->
+ let <_a,_b> =
+ <_f,_as>
+ in call 'error_handler':'raise_undef_exception'
+ ('lfe_andor_SUITE', _a, _b)
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'LFE-EXPAND-EXPORTED-MACRO'/3 =
+ %% Line 29
+ fun (_2,_1,_0) ->
+ 'no'
+'module_info'/0 =
+ fun () ->
+ call 'erlang':'get_module_info'
+ ('lfe_andor_SUITE')
+'module_info'/1 =
+ fun (_x) ->
+ call 'erlang':'get_module_info'
+ ('lfe_andor_SUITE', _x)
+end
diff --git a/lib/compiler/test/lfe_guard_SUITE.core b/lib/compiler/test/lfe_guard_SUITE.core
new file mode 100644
index 0000000000..920be82f61
--- /dev/null
+++ b/lib/compiler/test/lfe_guard_SUITE.core
@@ -0,0 +1,3438 @@
+module 'lfe_guard_SUITE' ['$handle_undefined_function'/2,
+ 'LFE-EXPAND-EXPORTED-MACRO'/3,
+ 'all'/0,
+ 'and_guard'/1,
+ 'andalso_semi'/1,
+ 'basic_andalso_orelse'/1,
+ 'basic_not'/1,
+ 'binary_part'/1,
+ 'build_in_guard'/1,
+ 'check_qlc_hrl'/1,
+ 'comma'/1,
+ 'complex_not'/1,
+ 'complex_or_guards'/1,
+ 'complex_semicolon'/1,
+ 'const_cond'/1,
+ 'end_per_group'/2,
+ 'end_per_suite'/1,
+ 'gbif'/1,
+ 'groups'/0,
+ 'init_per_group'/2,
+ 'init_per_suite'/1,
+ 'is_function_2'/1,
+ 'literal_type_tests'/1,
+ 'misc'/1,
+ 'module_info'/0,
+ 'module_info'/1,
+ 'more_or_guards'/1,
+ 'more_xor_guards'/1,
+ 'nested_nots'/1,
+ 'old_guard_tests'/1,
+ 'or_guard'/1,
+ 'rel_ops'/1,
+ 'semicolon'/1,
+ 'suite'/0,
+ 't_is_boolean'/1,
+ 't_tuple_size'/1,
+ 'traverse_dcd'/1,
+ 'tricky'/1,
+ 'xor_guard'/1]
+ attributes []
+'all'/0 =
+ %% Line 47
+ fun () ->
+ ['misc'|['const_cond'|['basic_not'|['complex_not'|['nested_nots'|['semicolon'|['complex_semicolon'|['comma'|['or_guard'|['more_or_guards'|['complex_or_guards'|['and_guard'|['xor_guard'|['more_xor_guards'|['build_in_guard'|['old_guard_tests'|['gbif'|['t_is_boolean'|['is_function_2'|['tricky'|['rel_ops'|['literal_type_tests'|['basic_andalso_orelse'|['traverse_dcd'|['check_qlc_hrl'|['andalso_semi'|['t_tuple_size'|['binary_part']]]]]]]]]]]]]]]]]]]]]]]]]]]]
+'suite'/0 =
+ %% Line 58
+ fun () ->
+ []
+'groups'/0 =
+ %% Line 60
+ fun () ->
+ []
+'init_per_suite'/1 =
+ %% Line 62
+ fun (_config) ->
+ _config
+'end_per_suite'/1 =
+ %% Line 64
+ fun (_config) ->
+ 'ok'
+'init_per_group'/2 =
+ %% Line 66
+ fun (_name,_config) ->
+ _config
+'end_per_group'/2 =
+ %% Line 68
+ fun (_name,_config) ->
+ _config
+'misc'/1 =
+ %% Line 70
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[42|[['case'|[['id'|[42]]|[['x'|[['when'|[['-'|['x']]]]|[['quote'|['ok']]]]]|[['x'|['x']]]]]]]]]})
+ let <_val> =
+ <case apply 'id'/1
+ (42) of
+ <_x>
+ when try
+ let <_3> =
+ let <_2> =
+ call 'erlang':'-'
+ (_x)
+ in ( call 'erlang':'=:='
+ (_2, 'true')
+ -| ['compiler_generated'] )
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_x> when 'true' ->
+ _x
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end>
+ in case <_val> of
+ <42> when 'true' ->
+ _val
+ ( <_4> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_4}})
+ -| ['compiler_generated'] )
+ end
+ ( <_17> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_17})
+ -| [{'function_name',{'misc',1}}] )
+ -| ['compiler_generated'] )
+ end
+'misc-1'/1 =
+ %% Line 93
+ fun (_0) ->
+ case <_0> of
+ <[{_w},{_x},{_y},{_z}]> when 'true' ->
+ case 1 of
+ <_1>
+ when try
+ let <_4> =
+ let <_3> =
+ case call 'erlang':'>'
+ (_x, _y) of
+ <'true'> when 'true' ->
+ let <_2> =
+ call 'erlang':'abs'
+ (_z)
+ in call 'erlang':'=:='
+ (_2, 2)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_3, 'true')
+ -| ['compiler_generated'] )
+ in _4
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ apply 'id'/1
+ (_w)
+ <_5>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'none'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ ( <_6> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_6})
+ -| [{'function_name',{'misc-1',1}}] )
+ -| ['compiler_generated'] )
+ end
+'get-data'/3 =
+ %% Line 99
+ fun (_2,_1,_0) ->
+ case <_2,_1,_0> of
+ <{'o',_active,_raw},_bytes,_buffer>
+ when try
+ let <_5> =
+ let <_3> =
+ call 'erlang':'=:='
+ (_raw, 'raw')
+ in let <_4> =
+ call 'erlang':'=:='
+ (_raw, 0)
+ in call 'erlang':'or'
+ (_3, _4)
+ in _5
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ case 1 of
+ <_6>
+ when try
+ let <_8> =
+ let <_7> =
+ case call 'erlang':'=/='
+ (_active, 'false') of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ call 'erlang':'=:='
+ (_bytes, 0)
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_7, 'true')
+ -| ['compiler_generated'] )
+ in _8
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ {'ok',_buffer,#{}#}
+ <_9>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ ( <_12,_11,_10> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_12,_11,_10})
+ -| [{'function_name',{'get-data',3}}] )
+ -| ['compiler_generated'] )
+ end
+'const_cond'/1 =
+ %% Line 104
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[['quote'|['ok']]|[['const-cond'|[{}|[0]]]]]]})
+ let <_val> =
+ <apply 'const-cond'/2
+ ({}, 0)>
+ in case <_val> of
+ <'ok'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_7> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_7})
+ -| [{'function_name',{'const_cond',1}}] )
+ -| ['compiler_generated'] )
+ end
+'const-cond'/2 =
+ %% Line 113
+ fun (_t,_sz) ->
+ case _t of
+ <_0>
+ when try
+ 'false'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'never'
+ <_1>
+ when try
+ let <_3> =
+ call 'erlang':'is_tuple'
+ (_t)
+ in let <_4> =
+ call 'erlang':'=='
+ ('eq', 'eq')
+ in let <_5> =
+ let <_2> =
+ call 'erlang':'tuple_size'
+ (_t)
+ in call 'erlang':'=='
+ (_2, _sz)
+ in let <_6> =
+ call 'erlang':'and'
+ (_3, _4)
+ in call 'erlang':'and'
+ (_6, _5)
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_7>
+ when try
+ let <_9> =
+ call 'erlang':'is_tuple'
+ (_t)
+ in let <_10> =
+ call 'erlang':'=='
+ ('eq', 'leq')
+ in let <_11> =
+ let <_8> =
+ call 'erlang':'tuple_size'
+ (_t)
+ in call 'erlang':'=='
+ (_8, _sz)
+ in let <_12> =
+ call 'erlang':'and'
+ (_9, _10)
+ in call 'erlang':'and'
+ (_12, _11)
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_13> when 'true' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'basic_not'/1 =
+ %% Line 120
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_true> =
+ <apply 'id'/1
+ ('true')>
+ in let <_false> =
+ <apply 'id'/1
+ ('false')>
+ in let <_glurf> =
+ <apply 'id'/1
+ ('glurf')>
+ in let <_a> =
+ <apply 'id'/1
+ (5)>
+ in let <_b> =
+ <apply 'id'/1
+ (3.75000000000000000000e+01)>
+ in let <_c> =
+ <apply 'id'/1
+ (-1)>
+ in let <_d> =
+ <apply 'id'/1
+ (5)>
+ in let <_atuple> =
+ <{_false,_true,_glurf}>
+ in do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['check'|[['lambda'|[[]|[['eif'|[['not'|[['quote'|['false']]]]|[['quote'|['ok']]|[['quote'|['true']]|[['quote'|['error']]]]]]]]]]|[['quote'|['ok']]]]]})
+ let <_5> =
+ fun () ->
+ case 1 of
+ <_2>
+ when try
+ let <_3> =
+ call 'erlang':'not'
+ ('false')
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_4>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ in apply 'check'/2
+ (_5, 'ok')
+ ( <_128> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_128})
+ -| [{'function_name',{'basic_not',1}}] )
+ -| ['compiler_generated'] )
+ end
+'complex_not'/1 =
+ %% Line 164
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_atuple> =
+ <apply 'id'/1
+ ({'false','true','gurka'})>
+ in do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['check'|[['lambda'|[[]|[['eif'|[['not'|[['element'|[1|['atuple']]]]]|[['quote'|['ok']]|[['quote'|['true']]|[['quote'|['error']]]]]]]]]]|[['quote'|['ok']]]]]})
+ let <_6> =
+ fun () ->
+ case 1 of
+ <_2>
+ when try
+ let <_4> =
+ let <_3> =
+ call 'erlang':'element'
+ (1, _atuple)
+ in call 'erlang':'not'
+ (_3)
+ in _4
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_5>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ in apply 'check'/2
+ (_6, 'ok')
+ ( <_50> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_50})
+ -| [{'function_name',{'complex_not',1}}] )
+ -| ['compiler_generated'] )
+ end
+'nested_nots'/1 =
+ %% Line 191
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[['quote'|['true']]|[['nested-not-1'|[0|[0]]]]]]})
+ let <_val> =
+ <apply 'nested-not-1'/2
+ (0, 0)>
+ in case <_val> of
+ <'true'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_18> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_18})
+ -| [{'function_name',{'nested_nots',1}}] )
+ -| ['compiler_generated'] )
+ end
+'nested-not-1'/2 =
+ %% Line 213
+ fun (_1,_0) ->
+ case <_1,_0> of
+ <_x,_y>
+ when try
+ let <_10> =
+ let <_9> =
+ let <_7> =
+ let <_3> =
+ call 'erlang':'>'
+ (_x, _y)
+ in let <_4> =
+ let <_2> =
+ call 'erlang':'is_atom'
+ (_x)
+ in call 'erlang':'not'
+ (_2)
+ in call 'erlang':'or'
+ (_3, _4)
+ in let <_8> =
+ let <_5> =
+ call 'erlang':'is_atom'
+ (_y)
+ in let <_6> =
+ call 'erlang':'=='
+ (_x, 3.39999999999999991118e+00)
+ in call 'erlang':'or'
+ (_5, _6)
+ in call 'erlang':'and'
+ (_7, _8)
+ in call 'erlang':'not'
+ (_9)
+ in _10
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_11,_12> when 'true' ->
+ 'false'
+ ( <_14,_13> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_14,_13})
+ -| [{'function_name',{'nested-not-1',2}}] )
+ -| ['compiler_generated'] )
+ end
+'nested-not-2'/3 =
+ %% Line 219
+ fun (_x,_y,_z) ->
+ apply 'nested-not-2'/4
+ (_x, _y, _z, 'true')
+'nested-not-2'/4 =
+ %% Line 222
+ fun (_3,_2,_1,_0) ->
+ case <_3,_2,_1,_0> of
+ <_x,_y,_z,_true>
+ when try
+ let <_12> =
+ let <_11> =
+ let <_10> =
+ let <_9> =
+ let <_7> =
+ let <_4> =
+ call 'erlang':'not'
+ (_x)
+ in let <_5> =
+ call 'erlang':'not'
+ (_y)
+ in call 'erlang':'and'
+ (_4, _5)
+ in let <_8> =
+ let <_6> =
+ call 'erlang':'is_atom'
+ (_z)
+ in call 'erlang':'not'
+ (_6)
+ in call 'erlang':'or'
+ (_7, _8)
+ in call 'erlang':'not'
+ (_9)
+ in call 'erlang':'and'
+ (_true, _10)
+ in call 'erlang':'not'
+ (_11)
+ in _12
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_13,_14,_15,_16> when 'true' ->
+ 'false'
+ ( <_20,_19,_18,_17> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_20,_19,_18,_17})
+ -| [{'function_name',{'nested-not-2',4}}] )
+ -| ['compiler_generated'] )
+ end
+'semicolon'/1 =
+ %% Line 228
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ ( <_2> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_2})
+ -| [{'function_name',{'semicolon',1}}] )
+ -| ['compiler_generated'] )
+ end
+'complex_semicolon'/1 =
+ %% Line 233
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ ( <_2> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_2})
+ -| [{'function_name',{'complex_semicolon',1}}] )
+ -| ['compiler_generated'] )
+ end
+'comma'/1 =
+ %% Line 239
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['check'|[['lambda'|[[]|[['eif'|[['progn'|[['quote'|['true']]|[['quote'|['false']]]]]|[['quote'|['ok']]|[['quote'|['true']]|[['quote'|['error']]]]]]]]]]|[['quote'|['error']]]]]})
+ let <_6> =
+ fun () ->
+ case 1 of
+ <_2>
+ when try
+ let <_4> =
+ let <_3> =
+ call 'erlang':'and'
+ ('true', 'false')
+ in ( call 'erlang':'=:='
+ (_3, 'true')
+ -| ['compiler_generated'] )
+ in _4
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_5>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ in apply 'check'/2
+ (_6, 'error')
+ ( <_181> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_181})
+ -| [{'function_name',{'comma',1}}] )
+ -| ['compiler_generated'] )
+ end
+'or_guard'/1 =
+ %% Line 305
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do let <_true,_false,_glurf> =
+ <apply 'id'/1
+ ('true'),apply 'id'/1
+ ('false'),apply 'id'/1
+ ('glurf')>
+ in do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['check'|[['lambda'|[[]|[['eif'|[['or'|[['quote'|['true']]|[['quote'|['false']]]]]|[['quote'|['ok']]]]]]]]|[['quote'|['ok']]]]]})
+ let <_4> =
+ fun () ->
+ case 1 of
+ <_2>
+ when try
+ let <_3> =
+ call 'erlang':'or'
+ ('true', 'false')
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ in apply 'check'/2
+ (_4, 'ok')
+ 'ok'
+ ( <_64> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_64})
+ -| [{'function_name',{'or_guard',1}}] )
+ -| ['compiler_generated'] )
+ end
+'more_or_guards'/1 =
+ %% Line 346
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do let <_true> =
+ <apply 'id'/1
+ ('true')>
+ in let <_false> =
+ <apply 'id'/1
+ ('false')>
+ in let <_atuple> =
+ <apply 'id'/1
+ ({'false','true','gurks'})>
+ in do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['check'|[['lambda'|[[]|[['eif'|[['or'|[['element'|[42|['atuple']]]|['false']]]|[['quote'|['ok']]|[['quote'|['true']]|[['quote'|['error']]]]]]]]]]|[['quote'|['error']]]]]})
+ let <_6> =
+ fun () ->
+ case 1 of
+ <_2>
+ when try
+ let <_4> =
+ let <_3> =
+ call 'erlang':'element'
+ (42, _atuple)
+ in call 'erlang':'or'
+ (_3, _false)
+ in _4
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_5>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ in apply 'check'/2
+ (_6, 'error')
+ 'ok'
+ ( <_68> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_68})
+ -| [{'function_name',{'more_or_guards',1}}] )
+ -| ['compiler_generated'] )
+ end
+'complex_or_guards'/1 =
+ %% Line 409
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[['quote'|['ok']]|[['complex-or-1'|[{'a','b','c','d'}|[{1,2,3}]]]]]]})
+ let <_val> =
+ <apply 'complex-or-1'/2
+ ({'a','b','c','d'}, {1,2,3})>
+ in case <_val> of
+ <'ok'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_55> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_55})
+ -| [{'function_name',{'complex_or_guards',1}}] )
+ -| ['compiler_generated'] )
+ end
+'complex-or-1'/2 =
+ %% Line 487
+ fun (_a,_b) ->
+ case 1 of
+ <_0>
+ when try
+ let <_11> =
+ let <_9> =
+ let <_3> =
+ let <_1> =
+ call 'erlang':'tuple_size'
+ (_a)
+ in call 'erlang':'<'
+ (3, _1)
+ in let <_4> =
+ let <_2> =
+ call 'erlang':'tuple_size'
+ (_a)
+ in call 'erlang':'<'
+ (_2, 9)
+ in call 'erlang':'and'
+ (_3, _4)
+ in let <_10> =
+ let <_7> =
+ let <_5> =
+ call 'erlang':'tuple_size'
+ (_b)
+ in call 'erlang':'<'
+ (2, _5)
+ in let <_8> =
+ let <_6> =
+ call 'erlang':'tuple_size'
+ (_b)
+ in call 'erlang':'<'
+ (_6, 7)
+ in call 'erlang':'and'
+ (_7, _8)
+ in call 'erlang':'or'
+ (_9, _10)
+ in _11
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_12>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'complex-or-2'/1 =
+ %% Line 492
+ fun (_tuple) ->
+ case 1 of
+ <_0>
+ when try
+ let <_6> =
+ let <_4> =
+ call 'erlang':'element'
+ (1, _tuple)
+ in let <_5> =
+ let <_3> =
+ let <_2> =
+ let <_1> =
+ call 'erlang':'element'
+ (2, _tuple)
+ in call 'erlang':'tuple_size'
+ (_1)
+ in call 'erlang':'>'
+ (_2, 3)
+ in call 'erlang':'not'
+ (_3)
+ in call 'erlang':'or'
+ (_4, _5)
+ in _6
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_7>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'complex-or-3'/2 =
+ %% Line 496
+ fun (_a,_b) ->
+ case 1 of
+ <_0>
+ when try
+ let <_5> =
+ let <_3> =
+ let <_2> =
+ let <_1> =
+ call 'erlang':'size'
+ (_b)
+ in call 'erlang':'>'
+ (_1, 3)
+ in call 'erlang':'not'
+ (_2)
+ in let <_4> =
+ call 'erlang':'element'
+ (1, _a)
+ in call 'erlang':'or'
+ (_3, _4)
+ in _5
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_6>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'complex-or-4'/2 =
+ %% Line 499
+ fun (_a,_b) ->
+ case 1 of
+ <_0>
+ when try
+ let <_7> =
+ let <_5> =
+ let <_4> =
+ let <_2> =
+ call 'erlang':'is_tuple'
+ (_a)
+ in let <_3> =
+ let <_1> =
+ call 'erlang':'size'
+ (_a)
+ in call 'erlang':'>'
+ (_1, 3)
+ in call 'erlang':'and'
+ (_2, _3)
+ in call 'erlang':'not'
+ (_4)
+ in let <_6> =
+ call 'erlang':'element'
+ (1, _b)
+ in call 'erlang':'or'
+ (_5, _6)
+ in _7
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_8>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'complex-or-5'/2 =
+ %% Line 503
+ fun (_a,_b) ->
+ case 1 of
+ <_0>
+ when try
+ let <_8> =
+ let <_6> =
+ let <_4> =
+ let <_2> =
+ call 'erlang':'is_tuple'
+ (_a)
+ in let <_3> =
+ let <_1> =
+ call 'erlang':'size'
+ (_a)
+ in call 'erlang':'>'
+ (_1, 3)
+ in call 'erlang':'and'
+ (_2, _3)
+ in call 'erlang':'not'
+ (_4)
+ in let <_7> =
+ let <_5> =
+ call 'erlang':'element'
+ (1, _b)
+ in call 'erlang':'not'
+ (_5)
+ in call 'erlang':'or'
+ (_6, _7)
+ in _8
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_9>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'complex-or-6'/2 =
+ %% Line 507
+ fun (_a,_b) ->
+ case 1 of
+ <_0>
+ when try
+ let <_11> =
+ let <_9> =
+ let <_5> =
+ let <_3> =
+ let <_1> =
+ call 'erlang':'element'
+ (1, _a)
+ in call 'erlang':'not'
+ (_1)
+ in let <_4> =
+ let <_2> =
+ call 'erlang':'element'
+ (2, _a)
+ in call 'erlang':'not'
+ (_2)
+ in call 'erlang':'and'
+ (_3, _4)
+ in call 'erlang':'not'
+ (_5)
+ in let <_10> =
+ let <_8> =
+ let <_7> =
+ let <_6> =
+ call 'erlang':'size'
+ (_b)
+ in call 'erlang':'>'
+ (_6, 3)
+ in call 'erlang':'not'
+ (_7)
+ in call 'erlang':'not'
+ (_8)
+ in call 'erlang':'or'
+ (_9, _10)
+ in _11
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_12>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'and_guard'/1 =
+ %% Line 512
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['check'|[['lambda'|[[]|[['eif'|[['and'|[['quote'|['true']]|[['quote'|['false']]]]]|[['quote'|['ok']]|[['quote'|['true']]|[['quote'|['error']]]]]]]]]]|[['quote'|['error']]]]]})
+ let <_5> =
+ fun () ->
+ case 1 of
+ <_2>
+ when try
+ let <_3> =
+ call 'erlang':'and'
+ ('true', 'false')
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_4>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ in apply 'check'/2
+ (_5, 'error')
+ ( <_120> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_120})
+ -| [{'function_name',{'and_guard',1}}] )
+ -| ['compiler_generated'] )
+ end
+'relprod'/2 =
+ %% Line 588
+ fun (_1,_0) ->
+ case <_1,_0> of
+ <_r1,_r2>
+ when try
+ let <_10> =
+ let <_4> =
+ let <_2> =
+ call 'erlang':'size'
+ (_r1)
+ in call 'erlang':'=:='
+ (_2, 3)
+ in let <_5> =
+ let <_3> =
+ call 'erlang':'element'
+ (1, _r1)
+ in call 'erlang':'=:='
+ (_3, 'Set')
+ in call 'erlang':'and'
+ (_4, _5)
+ in let <_11> =
+ let <_8> =
+ let <_6> =
+ call 'erlang':'size'
+ (_r2)
+ in call 'erlang':'=:='
+ (_6, 3)
+ in let <_9> =
+ let <_7> =
+ call 'erlang':'element'
+ (1, _r2)
+ in call 'erlang':'=:='
+ (_7, 'Set')
+ in call 'erlang':'and'
+ (_8, _9)
+ in call 'erlang':'and'
+ (_10, _11)
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ ( <_13,_12> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_13,_12})
+ -| [{'function_name',{'relprod',2}}] )
+ -| ['compiler_generated'] )
+ end
+'xor_guard'/1 =
+ %% Line 595
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['check'|[['lambda'|[[]|[['eif'|[['xor'|[['quote'|['true']]|[['quote'|['false']]]]]|[['quote'|['ok']]]]]]]]|[['quote'|['ok']]]]]})
+ let <_4> =
+ fun () ->
+ case 1 of
+ <_2>
+ when try
+ let <_3> =
+ call 'erlang':'xor'
+ ('true', 'false')
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ in apply 'check'/2
+ (_4, 'ok')
+ ( <_54> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_54})
+ -| [{'function_name',{'xor_guard',1}}] )
+ -| ['compiler_generated'] )
+ end
+'more_xor_guards'/1 =
+ %% Line 636
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_true,_false,_atuple> =
+ <apply 'id'/1
+ ('true'),apply 'id'/1
+ ('false'),apply 'id'/1
+ ({'false','true','gurka'})>
+ in do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['check'|[['lambda'|[[]|[['eif'|[['xor'|[['element'|[42|['atuple']]]|['false']]]|[['quote'|['ok']]|[['quote'|['true']]|[['quote'|['error']]]]]]]]]]|[['quote'|['error']]]]]})
+ let <_6> =
+ fun () ->
+ case 1 of
+ <_2>
+ when try
+ let <_4> =
+ let <_3> =
+ call 'erlang':'element'
+ (42, _atuple)
+ in call 'erlang':'xor'
+ (_3, _false)
+ in _4
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_5>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ in apply 'check'/2
+ (_6, 'error')
+ ( <_29> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_29})
+ -| [{'function_name',{'more_xor_guards',1}}] )
+ -| ['compiler_generated'] )
+ end
+'build_in_guard'/1 =
+ %% Line 666
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_subbin> =
+ <#{#<64>(8,1,'integer',['unsigned'|['big']]),
+ #<20>(8,1,'integer',['unsigned'|['big']]),
+ #<0>(8,1,'integer',['unsigned'|['big']]),
+ #<0>(8,1,'integer',['unsigned'|['big']]),
+ #<0>(8,1,'integer',['unsigned'|['big']]),
+ #<0>(8,1,'integer',['unsigned'|['big']]),
+ #<0>(8,1,'integer',['unsigned'|['big']]),
+ #<0>(8,1,'integer',['unsigned'|['big']])}#>
+ in let <_b> =
+ <#{#<1>(8,1,'integer',['unsigned'|['big']]),
+ #<_subbin>('all',8,'binary',['unsigned'|['big']]),
+ #<3.50000000000000000000e+00>(64,1,'float',['unsigned'|['big']])}#>
+ in do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[['quote'|['ok']]|[['eif'|[['=:='|['b'|[['binary'|[1|[['subbin'|['binary']]|[[3.50000000000000000000e+00|['float']]]]]]]]]|[['quote'|['ok']]]]]]]]})
+ let <_val> =
+ <case 1 of
+ <_2>
+ when try
+ let <_3> =
+ call 'erlang':'=:='
+ (_b, #{#<1>(8,1,'integer',['unsigned'|['big']]),
+ #<_subbin>('all',8,'binary',['unsigned'|['big']]),
+ #<3.50000000000000000000e+00>(64,1,'float',['unsigned'|['big']])}#)
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end>
+ in case <_val> of
+ <'ok'> when 'true' ->
+ _val
+ ( <_4> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_4}})
+ -| ['compiler_generated'] )
+ end
+ ( <_5> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_5})
+ -| [{'function_name',{'build_in_guard',1}}] )
+ -| ['compiler_generated'] )
+ end
+'old_guard_tests'/1 =
+ %% Line 674
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ ( <_2> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_2})
+ -| [{'function_name',{'old_guard_tests',1}}] )
+ -| ['compiler_generated'] )
+ end
+'gbif'/1 =
+ %% Line 679
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[['quote'|['error']]|[['gbif-1'|[1|[{'false','true'}]]]]]]})
+ let <_val> =
+ <apply 'gbif-1'/2
+ (1, {'false','true'})>
+ in case <_val> of
+ <'error'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_4> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_4})
+ -| [{'function_name',{'gbif',1}}] )
+ -| ['compiler_generated'] )
+ end
+'gbif-1'/2 =
+ %% Line 685
+ fun (_1,_0) ->
+ case <_1,_0> of
+ <_p,_t>
+ when try
+ let <_3> =
+ let <_2> =
+ call 'erlang':'element'
+ (_p, _t)
+ in ( call 'erlang':'=:='
+ (_2, 'true')
+ -| ['compiler_generated'] )
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_4,_5> when 'true' ->
+ 'error'
+ ( <_7,_6> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_7,_6})
+ -| [{'function_name',{'gbif-1',2}}] )
+ -| ['compiler_generated'] )
+ end
+'t_is_boolean'/1 =
+ %% Line 690
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[['quote'|['true']]|[['is_boolean'|[['quote'|['true']]]]]]]})
+ let <_val> =
+ <call 'erlang':'is_boolean'
+ ('true')>
+ in case <_val> of
+ <'true'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_70> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_70})
+ -| [{'function_name',{'t_is_boolean',1}}] )
+ -| ['compiler_generated'] )
+ end
+'bool'/1 =
+ %% Line 744
+ fun (_0) ->
+ case <_0> of
+ <_x>
+ when try
+ let <_1> =
+ call 'erlang':'is_boolean'
+ (_x)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_2> when 'true' ->
+ 'error'
+ ( <_3> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_3})
+ -| [{'function_name',{'bool',1}}] )
+ -| ['compiler_generated'] )
+ end
+'my-is-bool'/1 =
+ %% Line 748
+ fun (_v) ->
+ let <_r0> =
+ <apply 'my-is-bool-a'/1
+ (_v)>
+ in case <apply 'my-is-bool-b'/1
+ (_v)> of
+ <_res>
+ when try
+ let <_0> =
+ call 'erlang':'=:='
+ (_res, _r0)
+ in _0
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ _res
+ ( <_1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_1}})
+ -| ['compiler_generated'] )
+ end
+'my-is-bool-a'/1 =
+ %% Line 753
+ fun (_v) ->
+ case _v of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ 'true'
+ <_0> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'my-is-bool-b'/1 =
+ %% Line 759
+ fun (_v) ->
+ case _v of
+ <'false'> when 'true' ->
+ 'true'
+ <'true'> when 'true' ->
+ 'true'
+ <_0> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'is_function_2'/1 =
+ %% Line 765
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[['quote'|['true']]|[['is_function'|[['id'|[['function'|['lfe_guard_SUITE'|['all'|[1]]]]]]|[1]]]]]]})
+ let <_val> =
+ <let <_3> =
+ let <_2> =
+ call 'erlang':'make_fun'
+ ('lfe_guard_SUITE', 'all', 1)
+ in apply 'id'/1
+ (_2)
+ in call 'erlang':'is_function'
+ (_3, 1)>
+ in case <_val> of
+ <'true'> when 'true' ->
+ _val
+ ( <_4> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_4}})
+ -| ['compiler_generated'] )
+ end
+ ( <_17> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_17})
+ -| [{'function_name',{'is_function_2',1}}] )
+ -| ['compiler_generated'] )
+ end
+'tricky'/1 =
+ %% Line 775
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[['quote'|['not_ok']]|[['tricky-1'|[1|[2]]]]]]})
+ let <_val> =
+ <apply 'tricky-1'/2
+ (1, 2)>
+ in case <_val> of
+ <'not_ok'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_12> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_12})
+ -| [{'function_name',{'tricky',1}}] )
+ -| ['compiler_generated'] )
+ end
+'tricky-1'/2 =
+ %% Line 791
+ fun (_1,_0) ->
+ case <_1,_0> of
+ <_x,_y>
+ when try
+ let <_6> =
+ let <_5> =
+ let <_4> =
+ let <_2> =
+ call 'erlang':'=='
+ (_x, 1)
+ in let <_3> =
+ call 'erlang':'=='
+ (_y, 2)
+ in call 'erlang':'or'
+ (_2, _3)
+ in call 'erlang':'abs'
+ (_4)
+ in ( call 'erlang':'=:='
+ (_5, 'true')
+ -| ['compiler_generated'] )
+ in _6
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_7,_8> when 'true' ->
+ 'not_ok'
+ ( <_10,_9> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_10,_9})
+ -| [{'function_name',{'tricky-1',2}}] )
+ -| ['compiler_generated'] )
+ end
+'tricky-2'/1 =
+ %% Line 795
+ fun (_0) ->
+ case <_0> of
+ <_x>
+ when try
+ let <_3> =
+ let <_1> =
+ call 'erlang':'float'
+ (_x)
+ in let <_2> =
+ call 'erlang':'float'
+ (_x)
+ in call 'erlang':'or'
+ (_1, _2)
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_4> when 'true' ->
+ 'error'
+ ( <_5> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_5})
+ -| [{'function_name',{'tricky-2',1}}] )
+ -| ['compiler_generated'] )
+ end
+'rb'/3 =
+ %% Line 801
+ fun (_2,_1,_0) ->
+ case <_2,_1,_0> of
+ <_size,_toread,_sofar>
+ when try
+ let <_6> =
+ let <_4> =
+ let <_3> =
+ call 'erlang':'+'
+ (_sofar, _size)
+ in call 'erlang':'<'
+ (_3, 81920)
+ in let <_5> =
+ call 'erlang':'=='
+ (_toread, [])
+ in call 'erlang':'or'
+ (_4, _5)
+ in _6
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'true'
+ <_7,_8,_9> when 'true' ->
+ 'false'
+ ( <_12,_11,_10> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_12,_11,_10})
+ -| [{'function_name',{'rb',3}}] )
+ -| ['compiler_generated'] )
+ end
+'rel_ops'/1 =
+ %% Line 830
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['T'|['=/='|[1|[1.00000000000000000000e+00]]]]})
+ case <case 1 of
+ <_2>
+ when try
+ let <_3> =
+ call 'erlang':'=/='
+ (1, 1.00000000000000000000e+00)
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_4>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <'ok'> when 'true' ->
+ case <case 1 of
+ <_5>
+ when try
+ let <_7> =
+ let <_6> =
+ call 'erlang':'=/='
+ (1, 1.00000000000000000000e+00)
+ in call 'erlang':'not'
+ (_6)
+ in _7
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ <_8>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <'ok'> when 'true' ->
+ let <_x,_y,_true,_false> =
+ <apply 'id'/1
+ (1),apply 'id'/1
+ (1.00000000000000000000e+00),apply 'id'/1
+ ('true'),apply 'id'/1
+ ('false')>
+ in case <case 1 of
+ <_9>
+ when try
+ let <_10> =
+ call 'erlang':'=/='
+ (_x, _y)
+ in _10
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_11>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <'ok'> when 'true' ->
+ case <case 1 of
+ <_12>
+ when try
+ let <_15> =
+ let <_14> =
+ let <_13> =
+ call 'erlang':'=/='
+ (_x, _y)
+ in call 'erlang':'or'
+ (_false, _13)
+ in call 'erlang':'or'
+ (_14, _false)
+ in _15
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_16>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <'ok'> when 'true' ->
+ case <case 1 of
+ <_17>
+ when try
+ let <_19> =
+ let <_18> =
+ call 'erlang':'=/='
+ (_x, _y)
+ in call 'erlang':'and'
+ (_18, _true)
+ in _19
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_20>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <'ok'> when 'true' ->
+ case <case 1 of
+ <_21>
+ when try
+ let <_23> =
+ let <_22> =
+ call 'erlang':'=/='
+ (_x, _y)
+ in call 'erlang':'not'
+ (_22)
+ in _23
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ <_24>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <'ok'> when 'true' ->
+ case <case 1 of
+ <_25>
+ when try
+ let <_29> =
+ let <_28> =
+ let <_27> =
+ let <_26> =
+ call 'erlang':'=/='
+ (_x, _y)
+ in call 'erlang':'not'
+ (_26)
+ in call 'erlang':'or'
+ (_false, _27)
+ in call 'erlang':'or'
+ (_28, _false)
+ in _29
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ <_30>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end> of
+ <'ok'> when 'true' ->
+ 'ok'
+ ( <_31> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_31}})
+ -| ['compiler_generated'] )
+ end
+ ( <_32> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_32}})
+ -| ['compiler_generated'] )
+ end
+ ( <_33> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_33}})
+ -| ['compiler_generated'] )
+ end
+ ( <_34> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_34}})
+ -| ['compiler_generated'] )
+ end
+ ( <_35> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_35}})
+ -| ['compiler_generated'] )
+ end
+ ( <_36> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_36}})
+ -| ['compiler_generated'] )
+ end
+ ( <_37> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_37}})
+ -| ['compiler_generated'] )
+ end
+ ( <_769> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_769})
+ -| [{'function_name',{'rel_ops',1}}] )
+ -| ['compiler_generated'] )
+ end
+'literal_type_tests'/1 =
+ %% Line 873
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ case 'guard_suite' of
+ <'guard_suite'> when 'true' ->
+ apply 'literal-type-tests-1'/1
+ (_config)
+ <_2> when 'true' ->
+ {'skip',[69|[110|[111|[117|[103|[104|[32|[116|[111|[32|[114|[117|[110|[32|[116|[104|[105|[115|[32|[99|[97|[115|[101|[32|[111|[110|[99|[101|[46]]]]]]]]]]]]]]]]]]]]]]]]]]]]]}
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ ( <_3> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_3})
+ -| [{'function_name',{'literal_type_tests',1}}] )
+ -| ['compiler_generated'] )
+ end
+'literal-type-tests-1'/1 =
+ %% Line 879
+ fun (_config) ->
+ 'ok'
+'basic_andalso_orelse'/1 =
+ %% Line 967
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_t> =
+ <apply 'id'/1
+ ({'type','integers',23,42})>
+ in do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[65|[['eif'|[['andalso'|[['=:='|[['element'|[1|['t']]]|[['quote'|['type']]]]]|[['=:='|[['tuple_size'|['t']]|[4]]]|[['=:='|[['element'|[2|['t']]]|[['quote'|['integers']]]]]]]]]|[['+'|[['element'|[3|['t']]]|[['element'|[4|['t']]]]]]|[['quote'|['true']]|[['quote'|['error']]]]]]]]]]})
+ let <_val> =
+ <case 1 of
+ <_2>
+ when try
+ let <_7> =
+ let <_6> =
+ case let <_3> =
+ call 'erlang':'element'
+ (1, _t)
+ in call 'erlang':'=:='
+ (_3, 'type') of
+ <'true'> when 'true' ->
+ case let <_4> =
+ call 'erlang':'tuple_size'
+ (_t)
+ in call 'erlang':'=:='
+ (_4, 4) of
+ <'true'> when 'true' ->
+ let <_5> =
+ call 'erlang':'element'
+ (2, _t)
+ in call 'erlang':'=:='
+ (_5, 'integers')
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_6, 'true')
+ -| ['compiler_generated'] )
+ in _7
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_8> =
+ call 'erlang':'element'
+ (3, _t)
+ in let <_9> =
+ call 'erlang':'element'
+ (4, _t)
+ in call 'erlang':'+'
+ (_8, _9)
+ <_10>
+ when try
+ 'true'
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'error'
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end>
+ in case <_val> of
+ <65> when 'true' ->
+ _val
+ ( <_11> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_11}})
+ -| ['compiler_generated'] )
+ end
+ ( <_47> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_47})
+ -| [{'function_name',{'basic_andalso_orelse',1}}] )
+ -| ['compiler_generated'] )
+ end
+'basic-rt'/1 =
+ %% Line 1020
+ fun (_0) ->
+ case <_0> of
+ <_t>
+ when try
+ let <_5> =
+ let <_4> =
+ case call 'erlang':'is_tuple'
+ (_t) of
+ <'true'> when 'true' ->
+ case let <_1> =
+ call 'erlang':'tuple_size'
+ (_t)
+ in call 'erlang':'=:='
+ (_1, 4) of
+ <'true'> when 'true' ->
+ case let <_2> =
+ call 'erlang':'element'
+ (1, _t)
+ in call 'erlang':'=:='
+ (_2, 'type') of
+ <'true'> when 'true' ->
+ let <_3> =
+ call 'erlang':'element'
+ (2, _t)
+ in call 'erlang':'=='
+ (_3, 'integers')
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_4, 'true')
+ -| ['compiler_generated'] )
+ in _5
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_6> =
+ call 'erlang':'element'
+ (3, _t)
+ in let <_7> =
+ call 'erlang':'element'
+ (4, _t)
+ in call 'erlang':'+'
+ (_6, _7)
+ <_t>
+ when try
+ let <_11> =
+ let <_10> =
+ case call 'erlang':'is_tuple'
+ (_t) of
+ <'true'> when 'true' ->
+ case let <_8> =
+ call 'erlang':'tuple_size'
+ (_t)
+ in call 'erlang':'=:='
+ (_8, 2) of
+ <'true'> when 'true' ->
+ let <_9> =
+ call 'erlang':'element'
+ (1, _t)
+ in call 'erlang':'=:='
+ (_9, 'vector')
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_10, 'true')
+ -| ['compiler_generated'] )
+ in _11
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ case <call 'erlang':'element'
+ (2, _t)> of
+ <{_x,_y}> when 'true' ->
+ case 1 of
+ <_12>
+ when try
+ let <_16> =
+ let <_15> =
+ let <_13> =
+ call 'erlang':'is_float'
+ (_x)
+ in let <_14> =
+ call 'erlang':'is_float'
+ (_y)
+ in call 'erlang':'and'
+ (_13, _14)
+ in ( call 'erlang':'=:='
+ (_15, 'true')
+ -| ['compiler_generated'] )
+ in _16
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_19> =
+ let <_17> =
+ call 'erlang':'*'
+ (_x, _x)
+ in let <_18> =
+ call 'erlang':'*'
+ (_y, _y)
+ in call 'erlang':'+'
+ (_17, _18)
+ in call 'math':'sqrt'
+ (_19)
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+ ( <_20> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_20}})
+ -| ['compiler_generated'] )
+ end
+ <['+',_a,_b]> when 'true' ->
+ let <_22> =
+ let <_21> =
+ call 'erlang':'+'
+ (_a, _b)
+ in apply 'id'/1
+ (_21)
+ in call 'erlang':'*'
+ (_22, 2)
+ <{_r1,_r2}>
+ when try
+ let <_28> =
+ let <_27> =
+ case let <_23> =
+ call 'erlang':'size'
+ (_r1)
+ in call 'erlang':'=:='
+ (_23, 3) of
+ <'true'> when 'true' ->
+ case let <_24> =
+ call 'erlang':'element'
+ (1, _r1)
+ in call 'erlang':'=:='
+ (_24, 'Set') of
+ <'true'> when 'true' ->
+ case let <_25> =
+ call 'erlang':'size'
+ (_r2)
+ in call 'erlang':'=:='
+ (_25, 3) of
+ <'true'> when 'true' ->
+ let <_26> =
+ call 'erlang':'element'
+ (1, _r2)
+ in call 'erlang':'=:='
+ (_26, 'Set')
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_27, 'true')
+ -| ['compiler_generated'] )
+ in _28
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_r1> =
+ <apply 'id'/1
+ (_r1)>
+ in let <_r2> =
+ <apply 'id'/1
+ (_r2)>
+ in _r1
+ <_t>
+ when try
+ let <_32> =
+ let <_31> =
+ case call 'erlang':'is_tuple'
+ (_t) of
+ <'true'> when 'true' ->
+ case let <_29> =
+ call 'erlang':'tuple_size'
+ (_t)
+ in call 'erlang':'=:='
+ (_29, 2) of
+ <'true'> when 'true' ->
+ let <_30> =
+ call 'erlang':'element'
+ (1, _t)
+ in call 'erlang':'=:='
+ (_30, 'klurf')
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_31, 'true')
+ -| ['compiler_generated'] )
+ in _32
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_34> =
+ let <_33> =
+ call 'erlang':'element'
+ (2, _t)
+ in apply 'id'/1
+ (_33)
+ in call 'erlang':'*'
+ (3, _34)
+ <_35> when 'true' ->
+ 'error'
+ ( <_36> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_36})
+ -| [{'function_name',{'basic-rt',1}}] )
+ -| ['compiler_generated'] )
+ end
+'traverse_dcd'/1 =
+ %% Line 1043
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_l0> =
+ <[{'log_header','dcd_log',[49|[46|[48]]],'a','b','c'}|[{'log_header','dcd_log',[50|[46|[48]]],'a','b','c'}|[{'log_header','dcd_log',[48|[46|[48]]],'a','b','c'}|['blurf']]]]>
+ in case <apply 'traverse-dcd'/3
+ ({'cont',_l0}, 'log', 'funny')> of
+ <{'cont',[{'log_header','dcd_log',[48|[46|[48]]],'a','b','c'}|['blurf']],'log','funny'}> when 'true' ->
+ let <_l1> =
+ <[{'log_header','dcd_log',[49|[46|[48]]]}]>
+ in case <apply 'traverse-dcd'/3
+ ({'cont',_l1}, 'log', 'funny')> of
+ <{'cont',_l1,'log','funny'}> when 'true' ->
+ let <_l2> =
+ <[{'a','tuple'}]>
+ in case <apply 'traverse-dcd'/3
+ ({'cont',_l2}, 'log', 'funny')> of
+ <{'cont',_l2,'log','funny'}> when 'true' ->
+ 'ok'
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_3> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_3}})
+ -| ['compiler_generated'] )
+ end
+ ( <_4> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_4}})
+ -| ['compiler_generated'] )
+ end
+ ( <_5> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_5})
+ -| [{'function_name',{'traverse_dcd',1}}] )
+ -| ['compiler_generated'] )
+ end
+'traverse-dcd'/3 =
+ %% Line 1066
+ fun (_2,_1,_0) ->
+ case <_2,_1,_0> of
+ <{_cont,[_logh|_rest]},_log,_fun>
+ when try
+ let <_11> =
+ let <_6> =
+ case call 'erlang':'is_tuple'
+ (_logh) of
+ <'true'> when 'true' ->
+ case let <_3> =
+ call 'erlang':'tuple_size'
+ (_logh)
+ in call 'erlang':'=:='
+ (_3, 6) of
+ <'true'> when 'true' ->
+ case let <_4> =
+ call 'erlang':'element'
+ (1, _logh)
+ in call 'erlang':'=:='
+ (_4, 'log_header') of
+ <'true'> when 'true' ->
+ let <_5> =
+ call 'erlang':'element'
+ (2, _logh)
+ in call 'erlang':'=='
+ (_5, 'dcd_log')
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_6, 'true')
+ -| ['compiler_generated'] )
+ in let <_12> =
+ let <_10> =
+ case call 'erlang':'is_tuple'
+ (_logh) of
+ <'true'> when 'true' ->
+ case let <_7> =
+ call 'erlang':'tuple_size'
+ (_logh)
+ in call 'erlang':'=:='
+ (_7, 6) of
+ <'true'> when 'true' ->
+ case let <_8> =
+ call 'erlang':'element'
+ (1, _logh)
+ in call 'erlang':'=:='
+ (_8, 'log_header') of
+ <'true'> when 'true' ->
+ let <_9> =
+ call 'erlang':'element'
+ (3, _logh)
+ in call 'erlang':'>='
+ (_9, [49|[46|[48]]])
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in ( call 'erlang':'=:='
+ (_10, 'true')
+ -| ['compiler_generated'] )
+ in call 'erlang':'and'
+ (_11, _12)
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ apply 'traverse-dcd'/3
+ ({_cont,_rest}, _log, _fun)
+ <{_cont,_recs},_log,_fun> when 'true' ->
+ {_cont,_recs,_log,_fun}
+ ( <_15,_14,_13> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_15,_14,_13})
+ -| [{'function_name',{'traverse-dcd',3}}] )
+ -| ['compiler_generated'] )
+ end
+'check_qlc_hrl'/1 =
+ %% Line 1078
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ let <_st> =
+ <{'r1','false','dum'}>
+ in do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[['quote'|['foo']]|[['cqlc'|[['quote'|['qlc']]|[['quote'|['q']]|[['quote'|[[{'lc',1,2,3}]]]|['st']]]]]]]]})
+ let <_val> =
+ <apply 'cqlc'/4
+ ('qlc', 'q', [{'lc',1,2,3}], _st)>
+ in case <_val> of
+ <'foo'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_5> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_5})
+ -| [{'function_name',{'check_qlc_hrl',1}}] )
+ -| ['compiler_generated'] )
+ end
+'cqlc'/4 =
+ %% Line 1094
+ fun (_m,_f,_as,_st) ->
+ let <_arity> =
+ <call 'erlang':'length'
+ (_as)>
+ in case _as of
+ <[{'lc',_0,_1,_2}|_3]>
+ when try
+ let <_11> =
+ call 'erlang':'=:='
+ (_m, 'qlc')
+ in let <_12> =
+ call 'erlang':'=:='
+ (_f, 'q')
+ in let <_13> =
+ call 'erlang':'<'
+ (_arity, 3)
+ in let <_14> =
+ let <_10> =
+ let <_8> =
+ case let <_4> =
+ call 'erlang':'element'
+ (1, _st)
+ in call 'erlang':'=:='
+ (_4, 'r1') of
+ <'true'> when 'true' ->
+ 'true'
+ <'false'> when 'true' ->
+ 'fail'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in let <_9> =
+ let <_6> =
+ let <_5> =
+ call 'erlang':'tuple_size'
+ (_st)
+ in call 'erlang':'=:='
+ (_5, 3)
+ in let <_7> =
+ call 'erlang':'element'
+ (2, _st)
+ in call 'erlang':'and'
+ (_6, _7)
+ in call 'erlang':'and'
+ (_8, _9)
+ in call 'erlang':'not'
+ (_10)
+ in let <_15> =
+ call 'erlang':'and'
+ (_11, _12)
+ in let <_16> =
+ call 'erlang':'and'
+ (_15, _13)
+ in call 'erlang':'and'
+ (_16, _14)
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'foo'
+ <_17> when 'true' ->
+ _st
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'andalso_semi'/1 =
+ %% Line 1106
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[['quote'|['ok']]|[['andalso-semi-foo'|[0]]]]]})
+ let <_val> =
+ <apply 'andalso-semi-foo'/1
+ (0)>
+ in case <_val> of
+ <'ok'> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_8> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_8})
+ -| [{'function_name',{'andalso_semi',1}}] )
+ -| ['compiler_generated'] )
+ end
+'andalso-semi-foo'/1 =
+ %% Line 1117
+ fun (_0) ->
+ case <_0> of
+ <_bar>
+ when try
+ let <_3> =
+ let <_1> =
+ case call 'erlang':'is_integer'
+ (_bar) of
+ <'true'> when 'true' ->
+ call 'erlang':'=:='
+ (_bar, 0)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in let <_2> =
+ call 'erlang':'=:='
+ (_bar, 1)
+ in call 'erlang':'or'
+ (_1, _2)
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ ( <_4> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_4})
+ -| [{'function_name',{'andalso-semi-foo',1}}] )
+ -| ['compiler_generated'] )
+ end
+'andalso-semi-bar'/1 =
+ %% Line 1121
+ fun (_0) ->
+ case <_0> of
+ <_bar>
+ when try
+ let <_4> =
+ let <_2> =
+ case call 'erlang':'is_list'
+ (_bar) of
+ <'true'> when 'true' ->
+ let <_1> =
+ call 'erlang':'length'
+ (_bar)
+ in call 'erlang':'=:='
+ (_1, 3)
+ <'false'> when 'true' ->
+ 'false'
+ ( <_omega> when 'true' ->
+ _omega
+ -| ['compiler_generated'] )
+ end
+ in let <_3> =
+ call 'erlang':'=:='
+ (_bar, 1)
+ in call 'erlang':'or'
+ (_2, _3)
+ in _4
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ ( <_5> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_5})
+ -| [{'function_name',{'andalso-semi-bar',1}}] )
+ -| ['compiler_generated'] )
+ end
+'t_tuple_size'/1 =
+ %% Line 1125
+ fun (_0) ->
+ case <_0> of
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat'|[10|[['do-tuple-size'|[{1,2,3,4}]]]]]})
+ let <_val> =
+ <apply 'do-tuple-size'/1
+ ({1,2,3,4})>
+ in case <_val> of
+ <10> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_7> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_7})
+ -| [{'function_name',{'t_tuple_size',1}}] )
+ -| ['compiler_generated'] )
+ end
+'do-tuple-size'/1 =
+ %% Line 1139
+ fun (_0) ->
+ case <_0> of
+ <_t>
+ when try
+ let <_2> =
+ let <_1> =
+ call 'erlang':'tuple_size'
+ (_t)
+ in call 'erlang':'=:='
+ (_1, 4)
+ in _2
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ case <_t> of
+ <{_a,_b,_c,_d}> when 'true' ->
+ let <_lfe0> =
+ <_a>
+ in let <_lfe1> =
+ <_b>
+ in let <_lfe2> =
+ <_c>
+ in let <_lfe3> =
+ <_d>
+ in let <_4> =
+ let <_3> =
+ call 'erlang':'+'
+ (_lfe0, _lfe1)
+ in call 'erlang':'+'
+ (_3, _lfe2)
+ in call 'erlang':'+'
+ (_4, _lfe3)
+ ( <_5> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_5}})
+ -| ['compiler_generated'] )
+ end
+ ( <_6> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_6})
+ -| [{'function_name',{'do-tuple-size',1}}] )
+ -| ['compiler_generated'] )
+ end
+'ludicrous-tuple-size'/1 =
+ %% Line 1144
+ fun (_0) ->
+ case <_0> of
+ <_t>
+ when try
+ let <_2> =
+ let <_1> =
+ call 'erlang':'tuple_size'
+ (_t)
+ in call 'erlang':'=:='
+ (_1, 40652400101488115101757819767848575661943)
+ in _2
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_t>
+ when try
+ let <_4> =
+ let <_3> =
+ call 'erlang':'tuple_size'
+ (_t)
+ in call 'erlang':'=:='
+ (_3, 18446744073709551616)
+ in _4
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_t>
+ when try
+ let <_8> =
+ let <_6> =
+ call 'erlang':'tuple_size'
+ (_t)
+ in let <_7> =
+ let <_5> =
+ call 'erlang':'bsl'
+ (1, 64)
+ in call 'erlang':'-'
+ (_5, 1)
+ in call 'erlang':'=:='
+ (_6, _7)
+ in _8
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_t>
+ when try
+ let <_10> =
+ let <_9> =
+ call 'erlang':'tuple_size'
+ (_t)
+ in call 'erlang':'=:='
+ (_9, 18446744073709551615)
+ in _10
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_11> when 'true' ->
+ 'error'
+ ( <_12> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_12})
+ -| [{'function_name',{'ludicrous-tuple-size',1}}] )
+ -| ['compiler_generated'] )
+ end
+'mask-error'/1 =
+ %% Line 1152
+ fun (_0) ->
+ case <_0> of
+ <{'EXIT',{_err,_1}}> when 'true' ->
+ _err
+ <_else> when 'true' ->
+ _else
+ ( <_2> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_2})
+ -| [{'function_name',{'mask-error',1}}] )
+ -| ['compiler_generated'] )
+ end
+'binary_part'/1 =
+ %% Line 1156
+ fun (_0) ->
+ case <_0> of
+ <'doc'> when 'true' ->
+ [84|[101|[115|[116|[115|[32|[116|[104|[101|[32|[98|[105|[110|[97|[114|[121|[95|[112|[97|[114|[116|[47|[50|[44|[51|[32|[103|[117|[97|[114|[100|[32|[40|[71|[67|[41|[32|[98|[105|[102|[39|[115]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
+ <_config>
+ when try
+ let <_1> =
+ call 'erlang':'is_list'
+ (_config)
+ in _1
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ do call 'erlang':'put'
+ ('test_server_loc', {'lfe_guard_SUITE',['test-pat',1,['bp-test',#{#<1>(8,1,'integer',['unsigned'|['big']]),
+ #<2>(8,1,'integer',['unsigned'|['big']]),
+ #<3>(8,1,'integer',['unsigned'|['big']])}#]]})
+ let <_val> =
+ <apply 'bp-test'/1
+ (#{#<1>(8,1,'integer',['unsigned'|['big']]),
+ #<2>(8,1,'integer',['unsigned'|['big']]),
+ #<3>(8,1,'integer',['unsigned'|['big']])}#)>
+ in case <_val> of
+ <1> when 'true' ->
+ _val
+ ( <_2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',{_2}})
+ -| ['compiler_generated'] )
+ end
+ ( <_53> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_53})
+ -| [{'function_name',{'binary_part',1}}] )
+ -| ['compiler_generated'] )
+ end
+'bp-test'/1 =
+ %% Line 1225
+ fun (_0) ->
+ case <_0> of
+ <_b>
+ when try
+ let <_2> =
+ let <_1> =
+ call 'erlang':'length'
+ (_b)
+ in call 'erlang':'=:='
+ (_1, 137)
+ in _2
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 1
+ <_b>
+ when try
+ let <_4> =
+ let <_3> =
+ call 'erlang':'binary_part'
+ (_b, {1,1})
+ in call 'erlang':'=:='
+ (_3, #{#<2>(8,1,'integer',['unsigned'|['big']])}#)
+ in _4
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 1
+ <_b>
+ when try
+ let <_6> =
+ let <_5> =
+ call 'erlang':'binary_part'
+ (_b, 1, 1)
+ in call 'erlang':'=:='
+ (_5, #{#<1>(8,1,'integer',['unsigned'|['big']])}#)
+ in _6
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 2
+ <_b>
+ when try
+ let <_8> =
+ let <_7> =
+ call 'erlang':'binary_part'
+ (_b, {1,2})
+ in call 'erlang':'=:='
+ (_7, #{#<3>(8,1,'integer',['unsigned'|['big']]),
+ #<3>(8,1,'integer',['unsigned'|['big']])}#)
+ in _8
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 3
+ <_9> when 'true' ->
+ 'error'
+ ( <_10> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_10})
+ -| [{'function_name',{'bp-test',1}}] )
+ -| ['compiler_generated'] )
+ end
+'bp-test'/2 =
+ %% Line 1232
+ fun (_1,_0) ->
+ case <_1,_0> of
+ <_b,_a>
+ when try
+ let <_3> =
+ let <_2> =
+ call 'erlang':'length'
+ (_b)
+ in call 'erlang':'=:='
+ (_2, _a)
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 1
+ <_b,_a>
+ when try
+ let <_5> =
+ let <_4> =
+ call 'erlang':'binary_part'
+ (_b, {_a,1})
+ in call 'erlang':'=:='
+ (_4, #{#<2>(8,1,'integer',['unsigned'|['big']])}#)
+ in _5
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 1
+ <_b,_a>
+ when try
+ let <_7> =
+ let <_6> =
+ call 'erlang':'binary_part'
+ (_b, _a, 1)
+ in call 'erlang':'=:='
+ (_6, #{#<1>(8,1,'integer',['unsigned'|['big']])}#)
+ in _7
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 2
+ <_b,_a>
+ when try
+ let <_9> =
+ let <_8> =
+ call 'erlang':'binary_part'
+ (_b, {_a,2})
+ in call 'erlang':'=:='
+ (_8, #{#<3>(8,1,'integer',['unsigned'|['big']]),
+ #<3>(8,1,'integer',['unsigned'|['big']])}#)
+ in _9
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 3
+ <_10,_11> when 'true' ->
+ 'error'
+ ( <_13,_12> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_13,_12})
+ -| [{'function_name',{'bp-test',2}}] )
+ -| ['compiler_generated'] )
+ end
+'bp-test-x'/2 =
+ %% Line 1239
+ fun (_1,_0) ->
+ case <_1,_0> of
+ <_b,_a>
+ when try
+ let <_3> =
+ let <_2> =
+ call 'erlang':'length'
+ (_b)
+ in call 'erlang':'=:='
+ (_2, _a)
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 1
+ <_b,_a>
+ when try
+ let <_5> =
+ let <_4> =
+ call 'erlang':'binary_part'
+ (_b, _a)
+ in call 'erlang':'=:='
+ (_4, #{#<2>(8,1,'integer',['unsigned'|['big']])}#)
+ in _5
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 1
+ <_b,_a>
+ when try
+ let <_7> =
+ let <_6> =
+ call 'erlang':'binary_part'
+ (_b, _a)
+ in call 'erlang':'=:='
+ (_6, #{#<1>(8,1,'integer',['unsigned'|['big']])}#)
+ in _7
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 2
+ <_b,_a>
+ when try
+ let <_9> =
+ let <_8> =
+ call 'erlang':'binary_part'
+ (_b, _a)
+ in call 'erlang':'=:='
+ (_8, #{#<3>(8,1,'integer',['unsigned'|['big']]),
+ #<3>(8,1,'integer',['unsigned'|['big']])}#)
+ in _9
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 3
+ <_10,_11> when 'true' ->
+ 'error'
+ ( <_13,_12> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_13,_12})
+ -| [{'function_name',{'bp-test-x',2}}] )
+ -| ['compiler_generated'] )
+ end
+'bp-test-y'/2 =
+ %% Line 1246
+ fun (_1,_0) ->
+ case <_1,_0> of
+ <_b,_a>
+ when try
+ let <_3> =
+ let <_2> =
+ call 'erlang':'length'
+ (_b)
+ in call 'erlang':'=:='
+ (_2, _a)
+ in _3
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 1
+ <_b,_a>
+ when try
+ let <_5> =
+ let <_4> =
+ call 'erlang':'binary_part'
+ (_b, {1,_a})
+ in call 'erlang':'=:='
+ (_4, #{#<2>(8,1,'integer',['unsigned'|['big']])}#)
+ in _5
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 1
+ <_b,_a>
+ when try
+ let <_7> =
+ let <_6> =
+ call 'erlang':'binary_part'
+ (_b, 1, _a)
+ in call 'erlang':'=:='
+ (_6, #{#<1>(8,1,'integer',['unsigned'|['big']])}#)
+ in _7
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 2
+ <_b,_a>
+ when try
+ let <_9> =
+ let <_8> =
+ call 'erlang':'binary_part'
+ (_b, {1,_a})
+ in call 'erlang':'=:='
+ (_8, #{#<3>(8,1,'integer',['unsigned'|['big']]),
+ #<3>(8,1,'integer',['unsigned'|['big']])}#)
+ in _9
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 3
+ <_10,_11> when 'true' ->
+ 'error'
+ ( <_13,_12> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_13,_12})
+ -| [{'function_name',{'bp-test-y',2}}] )
+ -| ['compiler_generated'] )
+ end
+'bp-test'/3 =
+ %% Line 1253
+ fun (_2,_1,_0) ->
+ case <_2,_1,_0> of
+ <_b,_a,_3>
+ when try
+ let <_5> =
+ let <_4> =
+ call 'erlang':'length'
+ (_b)
+ in call 'erlang':'=:='
+ (_4, _a)
+ in _5
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 1
+ <_b,_a,_c>
+ when try
+ let <_7> =
+ let <_6> =
+ call 'erlang':'binary_part'
+ (_b, {_a,_c})
+ in call 'erlang':'=:='
+ (_6, #{#<2>(8,1,'integer',['unsigned'|['big']])}#)
+ in _7
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 1
+ <_b,_a,_c>
+ when try
+ let <_9> =
+ let <_8> =
+ call 'erlang':'binary_part'
+ (_b, _a, _c)
+ in call 'erlang':'=:='
+ (_8, #{#<1>(8,1,'integer',['unsigned'|['big']])}#)
+ in _9
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 2
+ <_b,_a,_c>
+ when try
+ let <_11> =
+ let <_10> =
+ call 'erlang':'binary_part'
+ (_b, {_a,_c})
+ in call 'erlang':'=:='
+ (_10, #{#<3>(8,1,'integer',['unsigned'|['big']]),
+ #<3>(8,1,'integer',['unsigned'|['big']])}#)
+ in _11
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 3
+ <_12,_13,_14> when 'true' ->
+ 'error'
+ ( <_17,_16,_15> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_17,_16,_15})
+ -| [{'function_name',{'bp-test',3}}] )
+ -| ['compiler_generated'] )
+ end
+'id'/1 =
+ %% Line 1262
+ fun (_i) ->
+ _i
+'check'/2 =
+ %% Line 1264
+ fun (_f,_result) ->
+ case apply _f
+ () of
+ <_r>
+ when try
+ let <_0> =
+ call 'erlang':'=:='
+ (_r, _result)
+ in _0
+ of <Try> ->
+ Try
+ catch <T,R> ->
+ 'false' ->
+ 'ok'
+ <_other> when 'true' ->
+ do call 'lfe_io':'format'
+ ([69|[120|[112|[101|[99|[116|[101|[100|[58|[32|[126|[112|[10]]]]]]]]]]]]], [_result])
+ do call 'lfe_io':'format'
+ ([32|[32|[32|[32|[32|[71|[111|[116|[58|[32|[126|[112|[10]]]]]]]]]]]]], [_other])
+ call 'test_server':'fail'
+ ()
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'fc'/1 =
+ %% Line 1272
+ fun (_0) ->
+ case <_0> of
+ <{'EXIT',{'function_clause'}}> when 'true' ->
+ 'ok'
+ <{'EXIT',{{'case_clause',_1},_2}}> when 'true' ->
+ 'ok'
+ ( <_3> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_3})
+ -| [{'function_name',{'fc',1}}] )
+ -| ['compiler_generated'] )
+ end
+'$handle_undefined_function'/2 =
+ %% Line 29
+ fun (_f,_as) ->
+ case let <_0> =
+ call 'lfe_env':'new'
+ ()
+ in apply 'LFE-EXPAND-EXPORTED-MACRO'/3
+ (_f, _as, _0) of
+ <{'yes',_exp}> when 'true' ->
+ call 'lfe_eval':'expr'
+ (_exp)
+ <'no'> when 'true' ->
+ let <_a,_b> =
+ <_f,_as>
+ in call 'error_handler':'raise_undef_exception'
+ ('lfe_guard_SUITE', _a, _b)
+ ( <_omega> when 'true' ->
+ primop 'match_fail'
+ ({'case_clause',_omega})
+ -| ['compiler_generated'] )
+ end
+'LFE-EXPAND-EXPORTED-MACRO'/3 =
+ %% Line 29
+ fun (_2,_1,_0) ->
+ 'no'
+'module_info'/0 =
+ fun () ->
+ call 'erlang':'get_module_info'
+ ('lfe_guard_SUITE')
+'module_info'/1 =
+ fun (_x) ->
+ call 'erlang':'get_module_info'
+ ('lfe_guard_SUITE', _x)
+end
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index cff3b5deb4..5e90b79aa2 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -66,7 +66,9 @@
t_export/1,
%% errors in 18
- t_register_corruption/1
+ t_register_corruption/1,
+ t_bad_update/1
+
]).
suite() -> [].
@@ -117,7 +119,8 @@ all() ->
t_export,
%% errors in 18
- t_register_corruption
+ t_register_corruption,
+ t_bad_update
].
groups() -> [].
@@ -1284,6 +1287,7 @@ t_guard_update(Config) when is_list(Config) ->
first = map_guard_update(#{}, #{x=>first}),
second = map_guard_update(#{y=>old}, #{x=>second,y=>old}),
third = map_guard_update(#{x=>old,y=>old}, #{x=>third,y=>old}),
+ bad_map_guard_update(),
ok.
t_guard_update_large(Config) when is_list(Config) ->
@@ -1350,6 +1354,29 @@ map_guard_update(M1, M2) when M1#{x=>second} =:= M2 -> second;
map_guard_update(M1, M2) when M1#{x:=third} =:= M2 -> third;
map_guard_update(_, _) -> error.
+bad_map_guard_update() ->
+ do_bad_map_guard_update(fun burns/1),
+ do_bad_map_guard_update(fun turns/1),
+ ok.
+
+do_bad_map_guard_update(Fun) ->
+ do_bad_map_guard_update_1(Fun, #{}),
+ do_bad_map_guard_update_1(Fun, #{true=>1}),
+ ok.
+
+do_bad_map_guard_update_1(Fun, Value) ->
+ %% Note: The business with the seemingly redundant fun
+ %% disables inlining, which would otherwise change the
+ %% EXIT reason.
+ {'EXIT',{function_clause,_}} = (catch Fun(Value)),
+ ok.
+
+burns(Richmond) when not (Richmond#{true := 0}); [Richmond] ->
+ specification.
+
+turns(Richmond) when not (Richmond#{true => 0}); [Richmond] ->
+ specification.
+
t_guard_receive(Config) when is_list(Config) ->
M0 = #{ id => 0 },
Pid = spawn_link(fun() -> guard_receive_loop() end),
@@ -1479,7 +1506,7 @@ t_guard_fun(Config) when is_list(Config) ->
{'EXIT', {function_clause,[{?MODULE,_,[#{s:=none,v:=none}],_}|_]}} -> ok;
{'EXIT', {{case_clause,_},_}} -> {comment,inlined};
Other ->
- test_server:fail({no_match, Other})
+ ct:fail({no_match, Other})
end.
@@ -1532,7 +1559,6 @@ t_warn_pair_key_overloaded(Config) when is_list(Config) ->
"hi2" => lists:subtract([1,2],[1]),
"hi3" => +3,
"hi1" => erlang:min(1,2),
- "hi1" => erlang:hash({1,2},35),
"hi1" => erlang:phash({1,2},33),
"hi1" => erlang:phash2({1,2},34),
"hi1" => erlang:integer_to_binary(1337),
@@ -1565,7 +1591,7 @@ t_build_and_match_empty_val(Config) when is_list(Config) ->
{'EXIT',{function_clause,_}} -> ok;
{'EXIT', {{case_clause,_},_}} -> {comment,inlined};
Other ->
- test_server:fail({no_match, Other})
+ ct:fail({no_match, Other})
end.
t_build_and_match_val(Config) when is_list(Config) ->
@@ -1583,7 +1609,7 @@ t_build_and_match_val(Config) when is_list(Config) ->
{'EXIT',{function_clause,_}} -> ok;
{'EXIT', {{case_clause,_},_}} -> {comment,inlined};
Other ->
- test_server:fail({no_match, Other})
+ ct:fail({no_match, Other})
end.
t_build_and_match_nil(Config) when is_list(Config) ->
@@ -1885,7 +1911,7 @@ register_corruption_dummy_call(A,B,C) -> {A,B,C}.
t_frequency_table(Config) when is_list(Config) ->
- random:seed({13,1337,54}), % pseudo random
+ rand:seed(exsplus, {13,1337,54}), % pseudo random
N = 100000,
Ts = rand_terms(N),
#{ n:=N, tf := Tf } = frequency_table(Ts,#{ n=>0, tf => #{}}),
@@ -1922,13 +1948,26 @@ validate_frequency([{T,C}|Fs],Tf) ->
validate_frequency([], _) -> ok.
+t_bad_update(_Config) ->
+ {#{0.0:=Id},#{}} = properly(#{}),
+ 42 = Id(42),
+ {'EXIT',{{badmap,_},_}} = (catch increase(0)),
+ ok.
+
+properly(Item) ->
+ {Item#{0.0 => fun id/1},Item}.
+
+increase(Allows) ->
+ catch fun() -> Allows end#{[] => +Allows, "warranty" => fun id/1}.
+
+
%% aux
rand_terms(0) -> [];
rand_terms(N) -> [rand_term()|rand_terms(N-1)].
rand_term() ->
- case random:uniform(6) of
+ case rand:uniform(6) of
1 -> rand_binary();
2 -> rand_number();
3 -> rand_atom();
@@ -1938,21 +1977,21 @@ rand_term() ->
end.
rand_binary() ->
- case random:uniform(3) of
+ case rand:uniform(3) of
1 -> <<>>;
2 -> <<"hi">>;
3 -> <<"message text larger than 64 bytes. yep, message text larger than 64 bytes.">>
end.
rand_number() ->
- case random:uniform(3) of
- 1 -> random:uniform(5);
- 2 -> float(random:uniform(5));
- 3 -> 1 bsl (63 + random:uniform(3))
+ case rand:uniform(3) of
+ 1 -> rand:uniform(5);
+ 2 -> float(rand:uniform(5));
+ 3 -> 1 bsl (63 + rand:uniform(3))
end.
rand_atom() ->
- case random:uniform(3) of
+ case rand:uniform(3) of
1 -> hi;
2 -> some_atom;
3 -> some_other_atom
@@ -1960,21 +1999,21 @@ rand_atom() ->
rand_tuple() ->
- case random:uniform(3) of
+ case rand:uniform(3) of
1 -> {ok, rand_term()}; % careful
2 -> {1, 2, 3};
3 -> {<<"yep">>, 1337}
end.
rand_list() ->
- case random:uniform(3) of
+ case rand:uniform(3) of
1 -> "hi";
2 -> [1,rand_term()]; % careful
3 -> [improper|list]
end.
rand_map() ->
- case random:uniform(3) of
+ case rand:uniform(3) of
1 -> #{ hi => 3 };
2 -> #{ wat => rand_term(), other => 3 }; % careful
3 -> #{ hi => 42, other => 42, yet_anoter => 1337 }
diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl
index 67d668f650..52b2da05f7 100644
--- a/lib/compiler/test/match_SUITE.erl
+++ b/lib/compiler/test/match_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,12 +21,12 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- pmatch/1,mixed/1,aliases/1,match_in_call/1,
- untuplify/1,shortcut_boolean/1,letify_guard/1,
+ pmatch/1,mixed/1,aliases/1,non_matching_aliases/1,
+ match_in_call/1,untuplify/1,shortcut_boolean/1,letify_guard/1,
selectify/1,underscore/1,match_map/1,map_vars_used/1,
- coverage/1]).
+ coverage/1,grab_bag/1,literal_binary/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -36,9 +36,11 @@ all() ->
groups() ->
[{p,[parallel],
- [pmatch,mixed,aliases,match_in_call,untuplify,
+ [pmatch,mixed,aliases,non_matching_aliases,
+ match_in_call,untuplify,
shortcut_boolean,letify_guard,selectify,
- underscore,match_map,map_vars_used,coverage]}].
+ underscore,match_map,map_vars_used,coverage,
+ grab_bag,literal_binary]}].
init_per_suite(Config) ->
@@ -55,10 +57,10 @@ end_per_group(_GroupName, Config) ->
pmatch(Config) when is_list(Config) ->
- ?line ok = doit(1),
- ?line ok = doit(2),
- ?line {error,baz} = doit(3),
- ?line {error,foobar} = doit(4),
+ ok = doit(1),
+ ok = doit(2),
+ {error,baz} = doit(3),
+ {error,foobar} = doit(4),
ok.
%% Thanks to Tobias Lindahl (HiPE).
@@ -78,13 +80,13 @@ doit(X) ->
end.
mixed(Config) when is_list(Config) ->
- ?line glufs = mixit(1),
- ?line klafs = mixit(2),
- ?line fnurra = mixit(3),
- ?line usch = mixit(4),
- ?line {error,blurf} = mixit(5),
- ?line {error,87987987} = mixit(6),
- ?line {error,{a,b,c}} = mixit(7),
+ glufs = mixit(1),
+ klafs = mixit(2),
+ fnurra = mixit(3),
+ usch = mixit(4),
+ {error,blurf} = mixit(5),
+ {error,87987987} = mixit(6),
+ {error,{a,b,c}} = mixit(7),
ok.
mixit(X) ->
@@ -93,9 +95,9 @@ mixit(X) ->
2 -> b;
3 -> 42;
4 -> 77;
- 5 -> blurf;
- 6 -> 87987987;
- 7 -> {a,b,c}
+ 4+1 -> blurf;
+ 5+1 -> 87987987;
+ 6+1 -> {a,b,c}
end of
a -> glufs;
b -> klafs;
@@ -106,48 +108,41 @@ mixit(X) ->
aliases(Config) when is_list(Config) ->
%% Lists/strings.
- ?line ok = str_alias("abc"),
- ?line ok = str_alias("def"),
- ?line ok = str_alias("ghi"),
- ?line ok = str_alias("klm"),
- ?line ok = str_alias("qrs"),
- ?line ok = str_alias("xy"),
- ?line ok = str_alias(""),
- ?line ok = str_alias([]),
- ?line error = str_alias("blurf"),
+ ok = str_alias("abc"),
+ ok = str_alias("def"),
+ ok = str_alias("ghi"),
+ ok = str_alias("klm"),
+ ok = str_alias("qrs"),
+ ok = str_alias("xy"),
+ ok = str_alias(""),
+ ok = str_alias([]),
+ error = str_alias("blurf"),
%% Characters/integers.
- ?line ok = char_alias($v),
- ?line ok = char_alias(118),
- ?line ok = char_alias($w),
- ?line ok = char_alias(119),
- ?line ok = char_alias(42),
- ?line ok = char_alias(3.0),
- ?line error = char_alias($_),
- ?line error = char_alias(0),
-
- ?line {42,42,42} = three(42),
-
- ?line {1,42,99,1,42,99} = tuple_alias({1,42,99}),
- ?line {-10,20,-10,20,-10,20} = tuple_alias({-10,20}),
- ?line 6 = tup_lit_alias({1,2,3}),
- ?line 6 = tup_lit_alias_rev({1,2,3}),
-
- ?line {42,42,42,42} = multiple_aliases_1(42),
- ?line {7,7,7} = multiple_aliases_2(7),
- ?line {{a,b},{a,b},{a,b}} = multiple_aliases_3({a,b}),
+ ok = char_alias($v),
+ ok = char_alias(118),
+ ok = char_alias($w),
+ ok = char_alias(119),
+ ok = char_alias(42),
+ ok = char_alias(3.0),
+ error = char_alias($_),
+ error = char_alias(0),
+
+ {42,42,42} = three(42),
+
+ {1,42,99,1,42,99} = tuple_alias({1,42,99}),
+ {-10,20,-10,20,-10,20} = tuple_alias({-10,20}),
+ 6 = tup_lit_alias({1,2,3}),
+ 6 = tup_lit_alias_rev({1,2,3}),
+
+ {42,42,42,42} = multiple_aliases_1(42),
+ {7,7,7} = multiple_aliases_2(7),
+ {{a,b},{a,b},{a,b}} = multiple_aliases_3({a,b}),
%% Lists/literals.
- ?line {a,b} = list_alias1([a,b]),
- ?line {a,b} = list_alias2([a,b]),
- ?line {a,b} = list_alias3([a,b]),
-
- %% Non-matching aliases.
- none = mixed_aliases(<<42>>),
- none = mixed_aliases([b]),
- none = mixed_aliases([d]),
- none = mixed_aliases({a,42}),
- none = mixed_aliases(42),
+ {a,b} = list_alias1([a,b]),
+ {a,b} = list_alias2([a,b]),
+ {a,b} = list_alias3([a,b]),
ok.
@@ -252,23 +247,90 @@ list_alias2([X,Y]=[a,b]) ->
list_alias3([X,b]=[a,Y]) ->
{X,Y}.
+non_matching_aliases(_Config) ->
+ none = mixed_aliases(<<42>>),
+ none = mixed_aliases([b]),
+ none = mixed_aliases([d]),
+ none = mixed_aliases({a,42}),
+ none = mixed_aliases(42),
+
+ {'EXIT',{{badmatch,42},_}} = (catch nomatch_alias(42)),
+ {'EXIT',{{badmatch,job},_}} = (catch entirely()),
+ {'EXIT',{{badmatch,associates},_}} = (catch printer()),
+ {'EXIT',{{badmatch,borogoves},_}} = (catch tench()),
+
+ put(perch, 0),
+ {'EXIT',{{badmatch,{spine,42}},_}} = (catch perch(42)),
+ 1 = erase(perch),
+
+ put(salmon, 0),
+ {'EXIT',{{badmatch,mimsy},_}} = (catch salmon()),
+ 1 = erase(salmon),
+
+ put(shark, 0),
+ {'EXIT',{{badmatch,_},_}} = (catch shark()),
+ 1 = erase(shark),
+
+ {'EXIT',{{badmatch,_},_}} = (catch radio(research)),
+ ok.
+
mixed_aliases(<<X:8>> = x) -> {a,X};
mixed_aliases([b] = <<X:8>>) -> {b,X};
mixed_aliases(<<X:8>> = {a,X}) -> {c,X};
mixed_aliases([X] = <<X:8>>) -> {d,X};
mixed_aliases(_) -> none.
+nomatch_alias(I) ->
+ {ok={A,B}} = id(I),
+ {A,B}.
+
+entirely() ->
+ 0(((Voice = true) = cool) = job),
+ [receive _ -> Voice end || banking <- printer].
+
+printer() ->
+ {[Indoor] = [] = associates},
+ [ireland || Indoor <- Indoor].
+
+tench() ->
+ E = begin
+ [A] = [] = borogoves,
+ A + 1
+ end,
+ E + 7 * A.
+
+perch(X) ->
+ begin
+ put(perch, get(perch)+1),
+ [A] = [] = {spine,X}
+ end.
+
+salmon() ->
+ {put(salmon, get(salmon)+1),#{key:=([A]=[])}=mimsy,exit(fail)},
+ A + 10.
+
+shark() ->
+ (hello = there) = (catch shark(put(shark, get(shark)+1), a = b)).
+
+shark(_, _) ->
+ ok.
+
+radio(research) ->
+ (connection = proof) =
+ (catch erlang:trace_pattern(catch mechanisms + assist,
+ summary = mechanisms)).
+
%% OTP-7018.
match_in_call(Config) when is_list(Config) ->
- ?line mac_a(0),
- ?line mac_b(1),
- ?line mac_c(42),
- ?line mac_d(42),
- ?line mac_e({gurka,42}),
+ mac_a(0),
+ mac_b(1),
+ mac_c(42),
+ mac_d(42),
+ mac_e({gurka,42}),
- ?line [{2,2},{2,2}] = mac_lc([{2,any},{2,2}]),
- ?line {'EXIT',_} = (catch mac_lc([{1,1}])),
+ [{2,2},{2,2}] = mac_lc([{2,any},{2,2}]),
+ {'EXIT',_} = (catch mac_lc([{1,1}])),
ok.
@@ -313,8 +375,8 @@ gurka({gurka,X}, X) -> ok.
untuplify(Config) when is_list(Config) ->
%% We do this to cover sys_core_fold:unalias_pat/1.
- ?line {1,2,3,4,alias,{[1,2],{3,4},alias}} = untuplify_1([1,2], {3,4}, alias),
- ?line error = untuplify_1([1,2], {3,4}, 42),
+ {1,2,3,4,alias,{[1,2],{3,4},alias}} = untuplify_1([1,2], {3,4}, alias),
+ error = untuplify_1([1,2], {3,4}, 42),
ok.
untuplify_1(A, B, C) ->
@@ -329,11 +391,11 @@ untuplify_1(A, B, C) ->
%% Coverage of beam_dead:shortcut_boolean_label/4.
shortcut_boolean(Config) when is_list(Config) ->
- ?line false = shortcut_boolean_1([0]),
- ?line true = shortcut_boolean_1({42}),
- ?line maybe = shortcut_boolean_1(self()),
- ?line {'EXIT',_} = (catch shortcut_boolean_1([a,b])),
- ?line {'EXIT',_} = (catch shortcut_boolean_1({a,b})),
+ false = shortcut_boolean_1([0]),
+ true = shortcut_boolean_1({42}),
+ maybe = shortcut_boolean_1(self()),
+ {'EXIT',_} = (catch shortcut_boolean_1([a,b])),
+ {'EXIT',_} = (catch shortcut_boolean_1({a,b})),
ok.
shortcut_boolean_1(X) ->
@@ -352,8 +414,8 @@ shortcut_boolean_1(X) ->
%% Test sys_core_fold:letify_guard/3.
letify_guard(Config) when is_list(Config) ->
- ?line {-15,a} = letify_guard(-15, a),
- ?line 5 = letify_guard(2, 3),
+ {-15,a} = letify_guard(-15, a),
+ 5 = letify_guard(2, 3),
ok.
letify_guard(A, B) ->
@@ -369,18 +431,18 @@ letify_guard(A, B) ->
%% instructions in beam_dead and beam_peep.
selectify(Config) when is_list(Config) ->
- ?line integer = sel_different_types({r,42}),
- ?line atom = sel_different_types({r,forty_two}),
- ?line none = sel_different_types({r,18}),
- ?line {'EXIT',_} = (catch sel_different_types([a,b,c])),
-
- ?line integer = sel_same_value({r,42}),
- ?line error = sel_same_value({r,100}),
- ?line error = sel_same_value(a),
-
- ?line integer42 = sel_same_value2(42),
- ?line integer43 = sel_same_value2(43),
- ?line error = sel_same_value2(44),
+ integer = sel_different_types({r,42}),
+ atom = sel_different_types({r,forty_two}),
+ none = sel_different_types({r,18}),
+ {'EXIT',_} = (catch sel_different_types([a,b,c])),
+
+ integer = sel_same_value({r,42}),
+ error = sel_same_value({r,100}),
+ error = sel_same_value(a),
+
+ integer42 = sel_same_value2(42),
+ integer43 = sel_same_value2(43),
+ error = sel_same_value2(44),
ok.
sel_different_types({r,_}=T) when element(2, T) =:= forty_two ->
@@ -449,7 +511,10 @@ do_map_vars_used(X, Y, Map) ->
coverage(Config) when is_list(Config) ->
%% Cover beam_dead.
ok = coverage_1(x, a),
- ok = coverage_1(x, b).
+ ok = coverage_1(x, b),
+
+ %% Cover sys_pre_expand.
+ ok = coverage_3("abc").
coverage_1(B, Tag) ->
case Tag of
@@ -460,4 +525,72 @@ coverage_1(B, Tag) ->
coverage_2(1, a, x) -> ok;
coverage_2(2, b, x) -> ok.
+coverage_3([$a]++[]++"bc") -> ok.
+
+grab_bag(_Config) ->
+ [_|T] = id([a,b,c]),
+ [b,c] = id(T),
+
+ T1 = fun() ->
+ [_|_] = x
+ end,
+ {'EXIT',_} = (catch T1()),
+
+ T2 = fun(A, B) ->
+ case {{element(1, A),element(2, B)},
+ {element(2, A),element(2, B)}} of
+ {Same,Same} -> ok;
+ {{0,1},{up,X}} -> id(X);
+ {_,{X,_}} -> id(X)
+ end
+ end,
+ ok = T2({a,a,z,z}, {z,a,z}),
+ 1 = T2({0,up}, {zzz,1}),
+ y = T2({x,y}, {a,z,z}),
+
+ %% OTP-5244.
+ L = [{stretch,0,0},
+ {bad,[]},
+ {bad,atom},
+ {bad,0},
+ {bad,16#AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA},
+ {bad,16#555555555555555555555555555555555555555555555555555}],
+ ok = grab_bag_remove_failure(L, unit, 0),
+
+ ok.
+
+grab_bag_remove_failure([], _Unit, _MaxFailure) ->
+ ok;
+grab_bag_remove_failure([{bad,Bad}|_], _Unit, _MaxFailure) ->
+ Bad;
+grab_bag_remove_failure([{stretch,_,Mi}=Stretch | Specs], Unit, _MaxFailure) ->
+ {MinMax,NewMaxFailure} = id({min,1}),
+ case {MinMax,grab_bag_remove_failure(Specs, Unit, NewMaxFailure)} of
+ {min,{NewMaxFailure,Rest}} ->
+ {done,[{fixed,Mi} | Rest]};
+ {min,_} when Specs =/= [] ->
+ grab_bag_remove_failure([Stretch|tl(Specs)], Unit, NewMaxFailure);
+ {min,_} ->
+ ok
+ end.
+
+%% Regression in 19.0, reported by Alexei Sholik
+literal_binary(_Config) ->
+ 3 = literal_binary_match(bar, <<"y">>),
+
+ %% While we are at it, also test the remaining code paths
+ %% in literal_binary_match/2.
+ 1 = literal_binary_match(bar, <<"x">>),
+ 2 = literal_binary_match(foo, <<"x">>),
+ 3 = literal_binary_match(foo, <<"y">>),
+ fail = literal_binary_match(bar, <<"z">>),
+ fail = literal_binary_match(foo, <<"z">>),
+ ok.
+
+literal_binary_match(bar, <<"x">>) -> 1;
+literal_binary_match(_, <<"x">>) -> 2;
+literal_binary_match(_, <<"y">>) -> 3;
+literal_binary_match(_, _) -> fail.
+
+
id(I) -> I.
diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl
index 8606935504..4bd884d86b 100644
--- a/lib/compiler/test/misc_SUITE.erl
+++ b/lib/compiler/test/misc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,9 +23,10 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
tobias/1,empty_string/1,md5/1,silly_coverage/1,
- confused_literals/1,integer_encoding/1,override_bif/1]).
+ confused_literals/1,integer_encoding/0,integer_encoding/1,
+ override_bif/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
%% For the override_bif testcase.
%% NB, no other testcases in this testsuite can use these without erlang:prefix!
@@ -38,22 +39,25 @@
-compile({no_auto_import,[byte_size/1]}).
-import(erlang,[byte_size/1]).
-
+%% Cover the code for callback handling.
+-callback must_define_this_one() -> 'ok'.
+-callback do_something_strange(atom()) -> 'ok'.
+-optional_callbacks([do_something_strange/1]).
+-optional_callbacks([ignore_me]). %Invalid; ignored.
%% Include an opaque declaration to cover the stripping of
%% opaque types from attributes in v3_kernel.
-opaque misc_SUITE_test_cases() :: [atom()].
init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = test_server:timetrap(?t:minutes(10)),
- [{watchdog,Dog}|Config].
+ Config.
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
ok.
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,10}}].
-spec all() -> misc_SUITE_test_cases().
all() ->
@@ -88,32 +92,27 @@ abs(_N) ->
binary_part(_,_,_) ->
dummy_bp.
-% Make sure that auto-imported BIF's are overridden correctly
-
-override_bif(suite) ->
- [];
-override_bif(doc) ->
- ["Test dat local functions and imports override auto-imported BIFs."];
+%% Test that local functions and imports override auto-imported BIFs.
override_bif(Config) when is_list(Config) ->
- ?line dummy_abs = abs(1),
- ?line dummy_bp = binary_part(<<"hello">>,1,1),
- ?line dummy = binary_part(<<"hello">>,{1,1}),
- ?line 1 = erlang:abs(1),
- ?line <<"e">> = erlang:binary_part(<<"hello">>,1,1),
- ?line <<"e">> = erlang:binary_part(<<"hello">>,{1,1}),
+ dummy_abs = abs(1),
+ dummy_bp = binary_part(<<"hello">>,1,1),
+ dummy = binary_part(<<"hello">>,{1,1}),
+ 1 = erlang:abs(1),
+ <<"e">> = erlang:binary_part(<<"hello">>,1,1),
+ <<"e">> = erlang:binary_part(<<"hello">>,{1,1}),
F = fun(X) when byte_size(X) =:= 4 ->
four;
(X) ->
byte_size(X)
end,
- ?line four = F(<<1,2,3,4>>),
- ?line 5 = F(<<1,2,3,4,5>>),
+ four = F(<<1,2,3,4>>),
+ 5 = F(<<1,2,3,4,5>>),
ok.
%% A bug reported by Tobias Lindahl for a development version of R11B.
tobias(Config) when is_list(Config) ->
- ?line 1 = tobias_1([1,2,3]),
+ 1 = tobias_1([1,2,3]),
ok.
tobias_1([H|_T]) ->
@@ -134,7 +133,7 @@ tobias_2(_, _) ->
-record(r, {s = ""}).
empty_string(Config) when is_list(Config) ->
- ?line #r{s="x"} = empty_string_1(#r{}),
+ #r{s="x"} = empty_string_1(#r{}),
ok.
empty_string_1(T) ->
@@ -149,26 +148,27 @@ md5(Config) when is_list(Config) ->
end.
md5() ->
- ?line Dir = filename:dirname(code:which(?MODULE)),
- ?line Beams = filelib:wildcard(filename:join(Dir, "*.beam")),
- ?line io:format("Found ~w beam files", [length(Beams)]),
- ?line lists:foreach(fun md5_1/1, Beams).
+ Dir = filename:dirname(code:which(?MODULE)),
+ Beams = filelib:wildcard(filename:join(Dir, "*.beam")),
+ io:format("Found ~w beam files", [length(Beams)]),
+ lists:foreach(fun md5_1/1, Beams).
md5_1(Beam) ->
- ?line {ok,{Mod,[Vsn]}} = beam_lib:version(Beam),
- ?line {ok,Code} = file:read_file(Beam),
- ?line {Mod,<<Vsn:128>>} = {Mod,code:module_md5(Code)}.
+ {ok,{Mod,[Vsn]}} = beam_lib:version(Beam),
+ {ok,Code} = file:read_file(Beam),
+ {Mod,<<Vsn:128>>} = {Mod,code:module_md5(Code)}.
%% Cover some code that handles internal errors.
silly_coverage(Config) when is_list(Config) ->
- %% sys_core_fold, sys_core_setel, v3_kernel
+ %% sys_core_fold, sys_core_bsm, sys_core_setel, v3_kernel
BadCoreErlang = {c_module,[],
name,[],[],
[{{c_var,[],{foo,2}},seriously_bad_body}]},
- ?line expect_error(fun() -> sys_core_fold:module(BadCoreErlang, []) end),
- ?line expect_error(fun() -> sys_core_dsetel:module(BadCoreErlang, []) end),
- ?line expect_error(fun() -> v3_kernel:module(BadCoreErlang, []) end),
+ expect_error(fun() -> sys_core_fold:module(BadCoreErlang, []) end),
+ expect_error(fun() -> sys_core_bsm:module(BadCoreErlang, []) end),
+ expect_error(fun() -> sys_core_dsetel:module(BadCoreErlang, []) end),
+ expect_error(fun() -> v3_kernel:module(BadCoreErlang, []) end),
%% v3_life
BadKernel = {k_mdef,[],?MODULE,
@@ -178,11 +178,11 @@ silly_coverage(Config) when is_list(Config) ->
{k,[],[],[]},
f,0,[],
seriously_bad_body}]},
- ?line expect_error(fun() -> v3_life:module(BadKernel, []) end),
+ expect_error(fun() -> v3_life:module(BadKernel, []) end),
%% v3_codegen
CodegenInput = {?MODULE,[{foo,0}],[],[{function,foo,0,[a|b],a,b,[]}]},
- ?line expect_error(fun() -> v3_codegen:module(CodegenInput, []) end),
+ expect_error(fun() -> v3_codegen:module(CodegenInput, []) end),
%% beam_a
BeamAInput = {?MODULE,[{foo,0}],[],
@@ -192,13 +192,25 @@ silly_coverage(Config) when is_list(Config) ->
{label,2}|non_proper_list]}],99},
expect_error(fun() -> beam_a:module(BeamAInput, []) end),
+ %% beam_reorder
+ BlockInput = {?MODULE,[{foo,0}],[],
+ [{function,foo,0,2,
+ [{label,1},
+ {func_info,{atom,?MODULE},{atom,foo},0},
+ {label,2}|non_proper_list]}],99},
+ expect_error(fun() -> beam_reorder:module(BlockInput, []) end),
+
%% beam_block
BlockInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
[{label,1},
{func_info,{atom,?MODULE},{atom,foo},0},
{label,2}|non_proper_list]}],99},
- ?line expect_error(fun() -> beam_block:module(BlockInput, []) end),
+ expect_error(fun() -> beam_block:module(BlockInput, []) end),
+
+ %% beam_bs
+ BsInput = BlockInput,
+ expect_error(fun() -> beam_bs:module(BsInput, []) end),
%% beam_type
TypeInput = {?MODULE,[{foo,0}],[],
@@ -218,14 +230,6 @@ silly_coverage(Config) when is_list(Config) ->
{label,2}|non_proper_list]}],99},
expect_error(fun() -> beam_except:module(ExceptInput, []) end),
- %% beam_bool
- BoolInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2}|non_proper_list]}],99},
- ?line expect_error(fun() -> beam_bool:module(BoolInput, []) end),
-
%% beam_dead. This is tricky. Our function must look OK to
%% beam_utils:clean_labels/1, but must crash beam_dead.
DeadInput = {?MODULE,[{foo,0}],[],
@@ -243,15 +247,18 @@ silly_coverage(Config) when is_list(Config) ->
{func_info,{atom,?MODULE},{atom,foo},0},
{label,2},
{jump,{f,42}}]}],99},
- ?line expect_error(fun() -> beam_clean:module(CleanInput, []) end),
+ expect_error(fun() -> beam_clean:module(CleanInput, []) end),
- %% beam_peep
+ %% beam_peep. This is tricky. Use a select instruction with
+ %% an odd number of elements in the list to crash
+ %% prune_redundant_values/2 but not beam_clean:clean_labels/1.
PeepInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
[{label,1},
{func_info,{atom,?MODULE},{atom,foo},0},
- {label,2}|non_proper_list]}],99},
- ?line expect_error(fun() -> beam_peep:module(PeepInput, []) end),
+ {label,2},{select,op,r,{f,2},[{f,2}]}]}],
+ 2},
+ expect_error(fun() -> beam_peep:module(PeepInput, []) end),
%% beam_bsm. This is tricky. Our function must be sane enough to not crash
%% btb_index/1, but must crash the main optimization pass.
@@ -262,7 +269,7 @@ silly_coverage(Config) when is_list(Config) ->
{label,2},
{test,bs_get_binary2,{f,99},0,[{x,0},{atom,all},1,[]],{x,0}},
{block,[a|b]}]}],0},
- ?line expect_error(fun() -> beam_bsm:module(BsmInput, []) end),
+ expect_error(fun() -> beam_bsm:module(BsmInput, []) end),
%% beam_receive.
ReceiveInput = {?MODULE,[{foo,0}],[],
@@ -272,7 +279,24 @@ silly_coverage(Config) when is_list(Config) ->
{label,2},
{call_ext,0,{extfunc,erlang,make_ref,0}},
{block,[a|b]}]}],0},
- ?line expect_error(fun() -> beam_receive:module(ReceiveInput, []) end),
+ expect_error(fun() -> beam_receive:module(ReceiveInput, []) end),
+
+ %% beam_record.
+ RecordInput = {?MODULE,[{foo,0}],[],
+ [{function,foo,1,2,
+ [{label,1},
+ {func_info,{atom,?MODULE},{atom,foo},1},
+ {label,2},
+ {test,is_tuple,{f,1},[{x,0}]},
+ {test,test_arity,{f,1},[{x,0},3]},
+ {block,[{set,[{x,1}],[{x,0}],{get_tuple_element,0}}]},
+ {test,is_eq_exact,{f,1},[{x,1},{atom,bar}]},
+ {block,[{set,[{x,2}],[{x,0}],{get_tuple_element,1}}|a]},
+ {test,is_eq_exact,{f,1},[{x,2},{integer,1}]},
+ {block,[{set,[{x,0}],[{atom,ok}],move}]},
+ return]}],0},
+
+ expect_error(fun() -> beam_record:module(RecordInput, []) end),
BeamZInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
@@ -295,27 +319,30 @@ expect_error(Fun) ->
try Fun() of
Any ->
io:format("~p", [Any]),
- ?t:fail(call_was_supposed_to_fail)
+ ct:fail(call_was_supposed_to_fail)
catch
Class:Reason ->
Stk = erlang:get_stacktrace(),
io:format("~p:~p\n~p\n", [Class,Reason,Stk]),
case {Class,Reason} of
{error,undef} ->
- ?t:fail(not_supposed_to_fail_with_undef);
+ ct:fail(not_supposed_to_fail_with_undef);
{_,_} ->
ok
end
end.
confused_literals(Config) when is_list(Config) ->
- ?line {0,infinity} = confused_literals_1(int),
- ?line {0.0,infinity} = confused_literals_1(float),
+ {0,infinity} = confused_literals_1(int),
+ {0.0,infinity} = confused_literals_1(float),
ok.
confused_literals_1(int) -> {0,infinity};
confused_literals_1(float) -> {0.0,infinity}.
+integer_encoding() ->
+ [{timetrap,{minutes,4}}].
+
integer_encoding(Config) when is_list(Config) ->
case ?MODULE of
misc_SUITE -> integer_encoding_1(Config);
@@ -323,22 +350,21 @@ integer_encoding(Config) when is_list(Config) ->
end.
integer_encoding_1(Config) ->
- Dog = test_server:timetrap(?t:minutes(4)),
- ?line PrivDir = ?config(priv_dir, Config),
- ?line SrcFile = filename:join(PrivDir, "misc_SUITE_integer_encoding.erl"),
- ?line DataFile = filename:join(PrivDir, "integer_encoding.data"),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ SrcFile = filename:join(PrivDir, "misc_SUITE_integer_encoding.erl"),
+ DataFile = filename:join(PrivDir, "integer_encoding.data"),
Mod = misc_SUITE_integer_encoding,
%% Create files.
- ?line {ok,Src} = file:open(SrcFile, [write]),
- ?line {ok,Data} = file:open(DataFile, [write]),
+ {ok,Src} = file:open(SrcFile, [write]),
+ {ok,Data} = file:open(DataFile, [write]),
io:format(Src, "-module(~s).\n", [Mod]),
io:put_chars(Src, "-export([t/1]).\n"),
io:put_chars(Src, "t(Last) ->[\n"),
io:put_chars(Data, "[\n"),
- ?line do_integer_encoding(-(id(1) bsl 10000), Src, Data),
- ?line do_integer_encoding(id(1) bsl 10000, Src, Data),
+ do_integer_encoding(-(id(1) bsl 10000), Src, Data),
+ do_integer_encoding(id(1) bsl 10000, Src, Data),
do_integer_encoding(1024, 0, Src, Data),
_ = [begin
B = 1 bsl I,
@@ -350,32 +376,31 @@ integer_encoding_1(Config) ->
do_integer_encoding(B+1, Src, Data)
end || I <- lists:seq(1, 128)],
io:put_chars(Src, "Last].\n\n"),
- ?line ok = file:close(Src),
+ ok = file:close(Src),
io:put_chars(Data, "0].\n\n"),
- ?line ok = file:close(Data),
+ ok = file:close(Data),
%% Compile and load Erlang module.
- ?line SrcRoot = filename:rootname(SrcFile),
- ?line {ok,Mod,Binary} = compile:file(SrcRoot, [binary,report]),
- ?line {module,Mod} = code:load_binary(Mod, SrcRoot, Binary),
+ SrcRoot = filename:rootname(SrcFile),
+ {ok,Mod,Binary} = compile:file(SrcRoot, [binary,report]),
+ {module,Mod} = code:load_binary(Mod, SrcRoot, Binary),
%% Compare lists.
- ?line List = Mod:t(0),
- ?line {ok,[List]} = file:consult(DataFile),
+ List = Mod:t(0),
+ {ok,[List]} = file:consult(DataFile),
OneBsl10000 = id(1) bsl 10000,
- ?line [-(1 bsl 10000),OneBsl10000|_] = List,
+ [-(1 bsl 10000),OneBsl10000|_] = List,
%% Cleanup.
- ?line file:delete(SrcFile),
- ?line file:delete(DataFile),
- ?t:timetrap_cancel(Dog),
+ file:delete(SrcFile),
+ file:delete(DataFile),
ok.
do_integer_encoding(0, _, _, _) -> ok;
do_integer_encoding(N, I0, Src, Data) ->
- I1 = (I0 bsl 5) bor (random:uniform(32) - 1),
+ I1 = (I0 bsl 5) bor (rand:uniform(32) - 1),
do_integer_encoding(I1, Src, Data),
- I2 = -(I1 bxor (random:uniform(32) - 1)),
+ I2 = -(I1 bxor (rand:uniform(32) - 1)),
do_integer_encoding(I2, Src, Data),
do_integer_encoding(N-1, I1, Src, Data).
diff --git a/lib/compiler/test/num_bif_SUITE.erl b/lib/compiler/test/num_bif_SUITE.erl
deleted file mode 100644
index d54fa203f0..0000000000
--- a/lib/compiler/test/num_bif_SUITE.erl
+++ /dev/null
@@ -1,285 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2011. 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(num_bif_SUITE).
-
--include_lib("test_server/include/test_server.hrl").
-
-%% Tests optimization of the BIFs:
-%% abs/1
-%% float/1
-%% float_to_list/1
-%% integer_to_list/1
-%% list_to_float/1
-%% list_to_integer/1
-%% round/1
-%% trunc/1
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2, t_abs/1, t_float/1,
- t_float_to_list/1, t_integer_to_list/1,
- t_list_to_integer/1,
- t_list_to_float_safe/1, t_list_to_float_risky/1,
- t_round/1, t_trunc/1]).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- test_lib:recompile(?MODULE),
- [t_abs, t_float, t_float_to_list, t_integer_to_list,
- {group, t_list_to_float}, t_list_to_integer, t_round,
- t_trunc].
-
-groups() ->
- [{t_list_to_float, [],
- [t_list_to_float_safe, t_list_to_float_risky]}].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-t_abs(Config) when is_list(Config) ->
- %% Floats.
- ?line 5.5 = abs(5.5),
- ?line 0.0 = abs(0.0),
- ?line 100.0 = abs(-100.0),
-
- %% Integers.
- ?line 5 = abs(5),
- ?line 0 = abs(0),
- ?line 100 = abs(-100),
-
- %% The largest smallnum. OTP-3190.
- ?line X = (1 bsl 27) - 1,
- ?line X = abs(X),
- ?line X = abs(X-1)+1,
- ?line X = abs(X+1)-1,
- ?line X = abs(-X),
- ?line X = abs(-X-1)-1,
- ?line X = abs(-X+1)+1,
-
- %% Bignums.
- BigNum = 13984792374983749,
- ?line BigNum = abs(BigNum),
- ?line BigNum = abs(-BigNum),
- ok.
-
-t_float(Config) when is_list(Config) ->
- ?line 0.0 = float(0),
- ?line 2.5 = float(2.5),
- ?line 0.0 = float(0.0),
- ?line -100.55 = float(-100.55),
- ?line 42.0 = float(42),
- ?line -100.0 = float(-100),
-
- %% Bignums.
- ?line 4294967305.0 = float(4294967305),
- ?line -4294967305.0 = float(-4294967305),
-
- %% Extremly big bignums.
- ?line Big = list_to_integer(lists:duplicate(2000, $1)),
- ?line {'EXIT', {badarg, _}} = (catch float(Big)),
-
- %% Invalid types and lists.
- ?line {'EXIT', {badarg, _}} = (catch list_to_integer(atom)),
- ?line {'EXIT', {badarg, _}} = (catch list_to_integer(123)),
- ?line {'EXIT', {badarg, _}} = (catch list_to_integer([$1, [$2]])),
- ?line {'EXIT', {badarg, _}} = (catch list_to_integer("1.2")),
- ?line {'EXIT', {badarg, _}} = (catch list_to_integer("a")),
- ?line {'EXIT', {badarg, _}} = (catch list_to_integer("")),
- ok.
-
-
-%% Tests float_to_list/1.
-
-t_float_to_list(Config) when is_list(Config) ->
- ?line test_ftl("0.0e+0", 0.0),
- ?line test_ftl("2.5e+1", 25.0),
- ?line test_ftl("2.5e+0", 2.5),
- ?line test_ftl("2.5e-1", 0.25),
- ?line test_ftl("-3.5e+17", -350.0e15),
- ok.
-
-test_ftl(Expect, Float) ->
- %% No ?line on the next line -- we want the line number from t_float_to_list.
- Expect = remove_zeros(lists:reverse(float_to_list(Float)), []).
-
-%% Removes any non-significant zeros in a floating point number.
-%% Example: 2.500000e+01 -> 2.5e+1
-
-remove_zeros([$+, $e|Rest], [$0, X|Result]) ->
- remove_zeros([$+, $e|Rest], [X|Result]);
-remove_zeros([$-, $e|Rest], [$0, X|Result]) ->
- remove_zeros([$-, $e|Rest], [X|Result]);
-remove_zeros([$0, $.|Rest], [$e|Result]) ->
- remove_zeros(Rest, [$., $0, $e|Result]);
-remove_zeros([$0|Rest], [$e|Result]) ->
- remove_zeros(Rest, [$e|Result]);
-remove_zeros([Char|Rest], Result) ->
- remove_zeros(Rest, [Char|Result]);
-remove_zeros([], Result) ->
- Result.
-
-%% Tests integer_to_list/1.
-
-t_integer_to_list(Config) when is_list(Config) ->
- ?line "0" = integer_to_list(0),
- ?line "42" = integer_to_list(42),
- ?line "-42" = integer_to_list(-42),
- ?line "-42" = integer_to_list(-42),
- ?line "32768" = integer_to_list(32768),
- ?line "268435455" = integer_to_list(268435455),
- ?line "-268435455" = integer_to_list(-268435455),
- ?line "123456932798748738738" = integer_to_list(123456932798748738738),
- ?line Big_List = lists:duplicate(2000, $1),
- ?line Big = list_to_integer(Big_List),
- ?line Big_List = integer_to_list(Big),
- ok.
-
-%% Tests list_to_float/1.
-
-
-t_list_to_float_safe(Config) when is_list(Config) ->
- ?line 0.0 = list_to_float("0.0"),
- ?line 0.0 = list_to_float("-0.0"),
- ?line 0.5 = list_to_float("0.5"),
- ?line -0.5 = list_to_float("-0.5"),
- ?line 100.0 = list_to_float("1.0e2"),
- ?line 127.5 = list_to_float("127.5"),
- ?line -199.5 = list_to_float("-199.5"),
-
- ?line {'EXIT', {badarg, _}} = (catch list_to_float("0")),
- ?line {'EXIT', {badarg, _}} = (catch list_to_float("0..0")),
- ?line {'EXIT', {badarg, _}} = (catch list_to_float("0e12")),
- ?line {'EXIT', {badarg, _}} = (catch list_to_float("--0.0")),
-%% ?line {'EXIT', {badarg, _}} = (catch list_to_float("0.0e+99999999")),
-
- ok.
-
-%% This might crash the emulator...
-%% (Known to crash the Unix version of Erlang 4.4.1)
-
-t_list_to_float_risky(Config) when is_list(Config) ->
- ?line Many_Ones = lists:duplicate(25000, $1),
- ?line _ = list_to_float("2."++Many_Ones),
- ?line {'EXIT', {badarg, _}} = (catch list_to_float("2"++Many_Ones)),
- ok.
-
-%% Tests list_to_integer/1.
-
-t_list_to_integer(Config) when is_list(Config) ->
- ?line 0 = list_to_integer("0"),
- ?line 0 = list_to_integer("00"),
- ?line 0 = list_to_integer("-0"),
- ?line 1 = list_to_integer("1"),
- ?line -1 = list_to_integer("-1"),
- ?line 42 = list_to_integer("42"),
- ?line -12 = list_to_integer("-12"),
- ?line 32768 = list_to_integer("32768"),
- ?line 268435455 = list_to_integer("268435455"),
- ?line -268435455 = list_to_integer("-268435455"),
-
- %% Bignums.
- ?line 123456932798748738738 = list_to_integer("123456932798748738738"),
- ?line _ = list_to_integer(lists:duplicate(2000, $1)),
- ok.
-
-%% Tests round/1.
-
-t_round(Config) when is_list(Config) ->
- ?line 0 = round(0.0),
- ?line 0 = round(0.4),
- ?line 1 = round(0.5),
- ?line 0 = round(-0.4),
- ?line -1 = round(-0.5),
- ?line 255 = round(255.3),
- ?line 256 = round(255.6),
- ?line -1033 = round(-1033.3),
- ?line -1034 = round(-1033.6),
-
- % OTP-3722:
- ?line X = (1 bsl 27) - 1,
- ?line MX = -X,
- ?line MXm1 = -X-1,
- ?line MXp1 = -X+1,
- ?line F = X + 0.0,
- ?line X = round(F),
- ?line X = round(F+1)-1,
- ?line X = round(F-1)+1,
- ?line MX = round(-F),
- ?line MXm1 = round(-F-1),
- ?line MXp1 = round(-F+1),
-
- ?line X = round(F+0.1),
- ?line X = round(F+1+0.1)-1,
- ?line X = round(F-1+0.1)+1,
- ?line MX = round(-F+0.1),
- ?line MXm1 = round(-F-1+0.1),
- ?line MXp1 = round(-F+1+0.1),
-
- ?line X = round(F-0.1),
- ?line X = round(F+1-0.1)-1,
- ?line X = round(F-1-0.1)+1,
- ?line MX = round(-F-0.1),
- ?line MXm1 = round(-F-1-0.1),
- ?line MXp1 = round(-F+1-0.1),
-
- ?line 0.5 = abs(round(F+0.5)-(F+0.5)),
- ?line 0.5 = abs(round(F-0.5)-(F-0.5)),
- ?line 0.5 = abs(round(-F-0.5)-(-F-0.5)),
- ?line 0.5 = abs(round(-F+0.5)-(-F+0.5)),
-
- %% Bignums.
- ?line 4294967296 = round(4294967296.1),
- ?line 4294967297 = round(4294967296.9),
- ?line -4294967296 = -round(4294967296.1),
- ?line -4294967297 = -round(4294967296.9),
- ok.
-
-t_trunc(Config) when is_list(Config) ->
- ?line 0 = trunc(0.0),
- ?line 5 = trunc(5.3333),
- ?line -10 = trunc(-10.978987),
- % The largest smallnum, converted to float (OTP-3722):
- ?line X = (1 bsl 27) - 1,
- ?line F = X + 0.0,
- io:format("X = ~p/~w/~w, F = ~p/~w/~w, trunc(F) = ~p/~w/~w~n",
- [X, X, binary_to_list(term_to_binary(X)),
- F, F, binary_to_list(term_to_binary(F)),
- trunc(F), trunc(F), binary_to_list(term_to_binary(trunc(F)))]),
- ?line X = trunc(F),
- ?line X = trunc(F+1)-1,
- ?line X = trunc(F-1)+1,
- ?line X = -trunc(-F),
- ?line X = -trunc(-F-1)-1,
- ?line X = -trunc(-F+1)+1,
-
- %% Bignums.
- ?line 4294967305 = trunc(4294967305.7),
- ?line -4294967305 = trunc(-4294967305.7),
- ok.
diff --git a/lib/compiler/test/overridden_bif_SUITE.erl b/lib/compiler/test/overridden_bif_SUITE.erl
new file mode 100644
index 0000000000..ce18916515
--- /dev/null
+++ b/lib/compiler/test/overridden_bif_SUITE.erl
@@ -0,0 +1,101 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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(overridden_bif_SUITE).
+-compile({no_auto_import,[is_reference/1,size/1]}).
+
+-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ init_per_testcase/2,end_per_testcase/2,
+ overridden_bif/1]).
+
+-include_lib("common_test/include/ct.hrl").
+
+%% Used by overridden_bif/1.
+-import(gb_sets, [size/1]).
+-import(test_lib, [binary/1]).
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,1}}].
+
+all() ->
+ test_lib:recompile(?MODULE),
+ [{group,p}].
+
+groups() ->
+ [{p,test_lib:parallel(),
+ [overridden_bif
+ ]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
+ Config.
+
+end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
+ ok.
+
+overridden_bif(_Config) ->
+ L = [-3,-2,-1,0,1,2,3,4],
+ [-3,0,3] = do_overridden_bif_1(L),
+ [-2,0,2,4] = do_overridden_bif_2(L),
+ [3] = do_overridden_bif_3(L),
+ [2,4] = do_overridden_bif_4(L),
+
+ Set = gb_sets:from_list(L),
+ [Set] = do_overridden_bif_5([gb_sets:singleton(42),Set]),
+
+ [100,0] = do_overridden_bif_6([100|L]),
+ ok.
+
+do_overridden_bif_1(L) ->
+ [E || E <- L, is_reference(E)].
+
+do_overridden_bif_2(L) ->
+ [E || E <- L, port(E)].
+
+do_overridden_bif_3(L) ->
+ [E || E <- L, (is_reference(E) andalso E > 0)].
+
+do_overridden_bif_4(L) ->
+ [E || E <- L, (port(E) andalso E > 0)].
+
+do_overridden_bif_5(L) ->
+ [E || E <- L, size(E) > 1].
+
+do_overridden_bif_6(L) ->
+ [E || E <- L, binary(E)].
+
+is_reference(N) ->
+ N rem 3 =:= 0.
+
+port(N) ->
+ N rem 2 =:= 0.
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index 4016fac0b5..8304672558 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,18 +27,17 @@
export/1,recv/1,coverage/1,otp_7980/1,ref_opt/1,
wait/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
init_per_testcase(_Case, Config) ->
- ?line Dog = test_server:timetrap(test_server:minutes(2)),
- [{watchdog, Dog}|Config].
+ Config.
-end_per_testcase(_Case, Config) ->
- Dog=?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
+end_per_testcase(_Case, _Config) ->
ok.
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,2}}].
all() ->
test_lib:recompile(?MODULE),
@@ -64,21 +63,21 @@ end_per_group(_GroupName, Config) ->
-record(state, {ena = true}).
recv(Config) when is_list(Config) ->
- ?line Pid = spawn_link(fun() -> loop(#state{}) end),
+ Pid = spawn_link(fun() -> loop(#state{}) end),
Self = self(),
- ?line Pid ! {Self,test},
+ Pid ! {Self,test},
receive
{ok,test} -> ok;
{error,Other} ->
io:format("Got unpexected ~p", [Other]),
- ?line ?t:fail()
+ ct:fail(unexpected)
after 10000 ->
- ?line ?t:fail(no_answer)
+ ct:fail(no_answer)
end,
receive
X ->
io:format("Unexpected extra message: ~p", [X]),
- ?line ?t:fail()
+ ct:fail(unexpected)
after 10 ->
ok
end,
@@ -116,11 +115,17 @@ coverage(Config) when is_list(Config) ->
self() ! 17,
self() ! 19,
- ?line 59 = tuple_to_values(infinity, x),
- ?line 61 = tuple_to_values(999999, x),
- ?line 0 = tuple_to_values(1, x),
+ 59 = tuple_to_values(infinity, x),
+ 61 = tuple_to_values(999999, x),
+ 0 = tuple_to_values(1, x),
+
+ {'EXIT',{{badmap,[]},_}} = (catch monitor_plus_badmap(self())),
+
ok.
+monitor_plus_badmap(Pid) ->
+ monitor(process, Pid) + []#{}.
+
receive_all() ->
receive
Any ->
@@ -188,8 +193,8 @@ ref_opt(Config) when is_list(Config) ->
end.
ref_opt_1(Config) ->
- DataDir = ?config(data_dir, Config),
- PrivDir = ?config(priv_dir, Config),
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
Sources = filelib:wildcard(filename:join([DataDir,"ref_opt","*.{erl,S}"])),
test_lib:p_run(fun(Src) ->
do_ref_opt(Src, PrivDir)
@@ -257,9 +262,9 @@ cover_recv_instructions() ->
export(Config) when is_list(Config) ->
Ref = make_ref(),
- ?line self() ! {result,Ref,42},
- ?line 42 = export_1(Ref),
- ?line {error,timeout} = export_1(Ref),
+ self() ! {result,Ref,42},
+ 42 = export_1(Ref),
+ {error,timeout} = export_1(Ref),
ok.
export_1(Reference) ->
diff --git a/lib/compiler/test/record_SUITE.erl b/lib/compiler/test/record_SUITE.erl
index 2ef379e43f..5546765f26 100644
--- a/lib/compiler/test/record_SUITE.erl
+++ b/lib/compiler/test/record_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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.
@@ -21,25 +21,24 @@
-module(record_SUITE).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
errors/1,record_test_2/1,record_test_3/1,record_access_in_guards/1,
guard_opt/1,eval_once/1,foobar/1,missing_test_heap/1,
- nested_access/1,coverage/1]).
+ nested_access/1,coverage/1,grab_bag/1]).
init_per_testcase(_Case, Config) ->
- ?line Dog = test_server:timetrap(test_server:minutes(2)),
- [{watchdog,Dog}|Config].
+ Config.
-end_per_testcase(_Case, Config) ->
- Dog = ?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
+end_per_testcase(_Case, _Config) ->
ok.
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,2}}].
all() ->
test_lib:recompile(?MODULE),
@@ -49,7 +48,7 @@ groups() ->
[{p,test_lib:parallel(),
[errors,record_test_2,record_test_3,
record_access_in_guards,guard_opt,eval_once,foobar,
- missing_test_heap,nested_access,coverage]}].
+ missing_test_heap,nested_access,coverage,grab_bag]}].
init_per_suite(Config) ->
@@ -71,18 +70,18 @@ end_per_group(_GroupName, Config) ->
errors(Config) when is_list(Config) ->
Foo = #foo{a=1,b=2,c=3,d=4},
- ?line #foo{a=19,b=42,c=3,d=4} = update_foo(Foo, 19, 42),
-
- ?line {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19)),
- ?line {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19, 35)),
- ?line {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19, 35, 17)),
- ?line {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19, 35, 17, 42)),
-
- ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19)),
- ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 35)),
- ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 35, 17)),
- ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 35, 17, 42)),
- ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19,
+ #foo{a=19,b=42,c=3,d=4} = update_foo(Foo, 19, 42),
+
+ {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19)),
+ {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19, 35)),
+ {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19, 35, 17)),
+ {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19, 35, 17, 42)),
+
+ {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19)),
+ {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 35)),
+ {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 35, 17)),
+ {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 35, 17, 42)),
+ {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19,
35, 17, 42, -2)),
ok.
@@ -118,72 +117,72 @@ update_foo_barf(#foo{}=R, A, _B, C, D, E) ->
R#barf{a=A,b=A,c=C,d=D,e=E}.
--define(TrueGuard(Expr), if Expr -> ok; true -> ?t:fail() end).
--define(FalseGuard(Expr), if Expr -> ?t:fail(); true -> ok end).
+-define(TrueGuard(Expr), if Expr -> ok; true -> ct:fail(failed) end).
+-define(FalseGuard(Expr), if Expr -> ct:fail(failed); true -> ok end).
record_test_2(Config) when is_list(Config) ->
- ?line true = is_record(#foo{}, foo),
- ?line false = is_record(#foo{}, barf),
- ?line false = is_record({foo}, foo),
+ true = is_record(#foo{}, foo),
+ false = is_record(#foo{}, barf),
+ false = is_record({foo}, foo),
- ?line true = erlang:is_record(#foo{}, foo),
- ?line false = erlang:is_record(#foo{}, barf),
- ?line false = erlang:is_record({foo}, foo),
+ true = erlang:is_record(#foo{}, foo),
+ false = erlang:is_record(#foo{}, barf),
+ false = erlang:is_record({foo}, foo),
- ?line false = is_record([], foo),
- ?line false = is_record(Config, foo),
+ false = is_record([], foo),
+ false = is_record(Config, foo),
- ?line ?TrueGuard(is_record(#foo{}, foo)),
- ?line ?FalseGuard(is_record(#foo{}, barf)),
- ?line ?FalseGuard(is_record({foo}, foo)),
+ ?TrueGuard(is_record(#foo{}, foo)),
+ ?FalseGuard(is_record(#foo{}, barf)),
+ ?FalseGuard(is_record({foo}, foo)),
- ?line ?TrueGuard(erlang:is_record(#foo{}, foo)),
- ?line ?FalseGuard(erlang:is_record(#foo{}, barf)),
- ?line ?FalseGuard(erlang:is_record({foo}, foo)),
+ ?TrueGuard(erlang:is_record(#foo{}, foo)),
+ ?FalseGuard(erlang:is_record(#foo{}, barf)),
+ ?FalseGuard(erlang:is_record({foo}, foo)),
- ?line ?FalseGuard(is_record([], foo)),
- ?line ?FalseGuard(is_record(Config, foo)),
+ ?FalseGuard(is_record([], foo)),
+ ?FalseGuard(is_record(Config, foo)),
%% 'not is_record/2' to test guard optimization.
- ?line ?FalseGuard(not is_record(#foo{}, foo)),
- ?line ?TrueGuard(not is_record(#foo{}, barf)),
- ?line ?TrueGuard(not is_record({foo}, foo)),
+ ?FalseGuard(not is_record(#foo{}, foo)),
+ ?TrueGuard(not is_record(#foo{}, barf)),
+ ?TrueGuard(not is_record({foo}, foo)),
- ?line ?FalseGuard(not erlang:is_record(#foo{}, foo)),
- ?line ?TrueGuard(not erlang:is_record(#foo{}, barf)),
- ?line ?TrueGuard(not erlang:is_record({foo}, foo)),
+ ?FalseGuard(not erlang:is_record(#foo{}, foo)),
+ ?TrueGuard(not erlang:is_record(#foo{}, barf)),
+ ?TrueGuard(not erlang:is_record({foo}, foo)),
Foo = id(#foo{}),
- ?line ?FalseGuard(not erlang:is_record(Foo, foo)),
- ?line ?TrueGuard(not erlang:is_record(Foo, barf)),
+ ?FalseGuard(not erlang:is_record(Foo, foo)),
+ ?TrueGuard(not erlang:is_record(Foo, barf)),
- ?line ?TrueGuard(not is_record(Config, foo)),
+ ?TrueGuard(not is_record(Config, foo)),
- ?line ?TrueGuard(not is_record(a, foo)),
- ?line ?TrueGuard(not is_record([], foo)),
+ ?TrueGuard(not is_record(a, foo)),
+ ?TrueGuard(not is_record([], foo)),
%% Pass non-literal first argument.
- ?line true = is_record(id(#foo{}), foo),
- ?line false = is_record(id(#foo{}), barf),
- ?line false = is_record(id({foo}), foo),
+ true = is_record(id(#foo{}), foo),
+ false = is_record(id(#foo{}), barf),
+ false = is_record(id({foo}), foo),
- ?line true = erlang:is_record(id(#foo{}), foo),
- ?line false = erlang:is_record(id(#foo{}), barf),
- ?line false = erlang:is_record(id({foo}), foo),
+ true = erlang:is_record(id(#foo{}), foo),
+ false = erlang:is_record(id(#foo{}), barf),
+ false = erlang:is_record(id({foo}), foo),
NoRec1 = id(blurf),
NoRec2 = id([]),
- ?line ?TrueGuard(not is_record(NoRec1, foo)),
- ?line ?TrueGuard(not is_record(NoRec2, foo)),
+ ?TrueGuard(not is_record(NoRec1, foo)),
+ ?TrueGuard(not is_record(NoRec2, foo)),
%% The optimizer attempts to move expressions to guards,
%% but it must not move an is_record/2 call that is not
%% allowed in a guard in the first place.
- ?line ok = case is_record(id({a}), id(a)) of
+ ok = case is_record(id({a}), id(a)) of
true -> ok;
false -> error
end,
@@ -191,61 +190,61 @@ record_test_2(Config) when is_list(Config) ->
%% Force the use of guard bifs by using the 'xor' operation.
False = id(false),
- ?line ?TrueGuard(is_record(#foo{}, foo) xor False),
- ?line ?FalseGuard(is_record(#foo{}, barf) xor False),
- ?line ?FalseGuard(is_record({foo}, foo) xor False ),
+ ?TrueGuard(is_record(#foo{}, foo) xor False),
+ ?FalseGuard(is_record(#foo{}, barf) xor False),
+ ?FalseGuard(is_record({foo}, foo) xor False ),
- ?line ?TrueGuard(is_record(Foo, foo) xor False),
- ?line ?FalseGuard(is_record(Foo, barf) xor False),
+ ?TrueGuard(is_record(Foo, foo) xor False),
+ ?FalseGuard(is_record(Foo, barf) xor False),
%% Implicit guards by using a list comprehension.
List = id([1,#foo{a=2},3,#bar{d=4},5,#foo{a=6},7]),
- ?line [#foo{a=2},#foo{a=6}] = [X || X <- List, is_record(X, foo)],
- ?line [#bar{d=4}] = [X || X <- List, is_record(X, bar)],
- ?line [1,#foo{a=2},3,5,#foo{a=6},7] =
+ [#foo{a=2},#foo{a=6}] = [X || X <- List, is_record(X, foo)],
+ [#bar{d=4}] = [X || X <- List, is_record(X, bar)],
+ [1,#foo{a=2},3,5,#foo{a=6},7] =
[X || X <- List, not is_record(X, bar)],
- ?line [1,3,5,7] =
+ [1,3,5,7] =
[X || X <- List, ((not is_record(X, bar)) and (not is_record(X, foo)))],
- ?line [#foo{a=2},#bar{d=4},#foo{a=6}] =
+ [#foo{a=2},#bar{d=4},#foo{a=6}] =
[X || X <- List, ((is_record(X, bar)) or (is_record(X, foo)))],
- ?line [1,3,#bar{d=4}] =
+ [1,3,#bar{d=4}] =
[X || X <- List, ((is_record(X, bar)) or (X < 5))],
- ?line MyList = [#foo{a=3},x,[],{a,b}],
- ?line [#foo{a=3}] = [X || X <- MyList, is_record(X, foo)],
- ?line [x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo)],
- ?line [#foo{a=3}] = [X || X <- MyList, begin is_record(X, foo) end],
- ?line [x,[],{a,b}] = [X || X <- MyList, begin not is_record(X, foo) end],
- ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, is_record(X, foo) or
- not is_binary(X)],
- ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo) or
- not is_binary(X)],
- ?line [#foo{a=3}] = [X || X <- MyList, is_record(X, foo) or is_reference(X)],
- ?line [x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo) or
- is_reference(X)],
- ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList,
- begin is_record(X, foo) or
- not is_binary(X) end],
- ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList,
- begin not is_record(X, foo) or
- not is_binary(X) end],
- ?line [#foo{a=3}] = [X || X <- MyList,
- begin is_record(X, foo) or is_reference(X) end],
- ?line [x,[],{a,b}] = [X || X <- MyList,
- begin not is_record(X, foo) or
- is_reference(X) end],
+ MyList = [#foo{a=3},x,[],{a,b}],
+ [#foo{a=3}] = [X || X <- MyList, is_record(X, foo)],
+ [x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo)],
+ [#foo{a=3}] = [X || X <- MyList, begin is_record(X, foo) end],
+ [x,[],{a,b}] = [X || X <- MyList, begin not is_record(X, foo) end],
+ [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, is_record(X, foo) or
+ not is_binary(X)],
+ [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo) or
+ not is_binary(X)],
+ [#foo{a=3}] = [X || X <- MyList, is_record(X, foo) or is_reference(X)],
+ [x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo) or
+ is_reference(X)],
+ [#foo{a=3},x,[],{a,b}] = [X || X <- MyList,
+ begin is_record(X, foo) or
+ not is_binary(X) end],
+ [#foo{a=3},x,[],{a,b}] = [X || X <- MyList,
+ begin not is_record(X, foo) or
+ not is_binary(X) end],
+ [#foo{a=3}] = [X || X <- MyList,
+ begin is_record(X, foo) or is_reference(X) end],
+ [x,[],{a,b}] = [X || X <- MyList,
+ begin not is_record(X, foo) or
+ is_reference(X) end],
%% Call is_record/2 with illegal arguments.
- ?line [] = [X || X <- [], is_record(t, id(X))],
- ?line {'EXIT',{badarg,_}} = (catch [X || X <- [1], is_record(t, id(X))]),
+ [] = [X || X <- [], is_record(t, id(X))],
+ {'EXIT',{badarg,_}} = (catch [X || X <- [1], is_record(t, id(X))]),
%% Update several fields with a string literal.
- ?line #barf{} = Barf0 = id(#barf{}),
- ?line Barf = update_barf(Barf0),
- ?line #barf{a="abc",b=1} = id(Barf),
+ #barf{} = Barf0 = id(#barf{}),
+ Barf = update_barf(Barf0),
+ #barf{a="abc",b=1} = id(Barf),
%% Test optimization of is_record/3.
false = case id({a,b}) of
@@ -258,125 +257,125 @@ record_test_2(Config) when is_list(Config) ->
ok.
record_test_3(Config) when is_list(Config) ->
- ?line true = is_record(#foo{}, foo, 5),
- ?line false = is_record(#foo{}, barf, 5),
- ?line false = is_record(#foo{}, barf, 6),
- ?line false = is_record({foo}, foo, 5),
+ true = is_record(#foo{}, foo, 5),
+ false = is_record(#foo{}, barf, 5),
+ false = is_record(#foo{}, barf, 6),
+ false = is_record({foo}, foo, 5),
- ?line true = erlang:is_record(#foo{}, foo, 5),
- ?line false = erlang:is_record(#foo{}, barf, 5),
- ?line false = erlang:is_record({foo}, foo, 5),
+ true = erlang:is_record(#foo{}, foo, 5),
+ false = erlang:is_record(#foo{}, barf, 5),
+ false = erlang:is_record({foo}, foo, 5),
- ?line false = is_record([], foo),
- ?line false = is_record(Config, foo),
+ false = is_record([], foo),
+ false = is_record(Config, foo),
- ?line ?TrueGuard(is_record(#foo{}, foo, 5)),
- ?line ?FalseGuard(is_record(#foo{}, barf, 5)),
- ?line ?FalseGuard(is_record(#foo{}, barf, 6)),
- ?line ?FalseGuard(is_record({foo}, foo, 5)),
+ ?TrueGuard(is_record(#foo{}, foo, 5)),
+ ?FalseGuard(is_record(#foo{}, barf, 5)),
+ ?FalseGuard(is_record(#foo{}, barf, 6)),
+ ?FalseGuard(is_record({foo}, foo, 5)),
- ?line ?TrueGuard(erlang:is_record(#foo{}, foo, 5)),
- ?line ?FalseGuard(erlang:is_record(#foo{}, barf, 5)),
- ?line ?FalseGuard(erlang:is_record(#foo{}, barf, 6)),
- ?line ?FalseGuard(erlang:is_record({foo}, foo, 5)),
+ ?TrueGuard(erlang:is_record(#foo{}, foo, 5)),
+ ?FalseGuard(erlang:is_record(#foo{}, barf, 5)),
+ ?FalseGuard(erlang:is_record(#foo{}, barf, 6)),
+ ?FalseGuard(erlang:is_record({foo}, foo, 5)),
- ?line ?FalseGuard(is_record([], foo, 5)),
- ?line ?FalseGuard(is_record(Config, foo, 5)),
+ ?FalseGuard(is_record([], foo, 5)),
+ ?FalseGuard(is_record(Config, foo, 5)),
%% 'not is_record/2' to test guard optimization.
- ?line ?FalseGuard(not is_record(#foo{}, foo, 5)),
- ?line ?TrueGuard(not is_record(#foo{}, barf, 6)),
- ?line ?TrueGuard(not is_record({foo}, foo, 5)),
+ ?FalseGuard(not is_record(#foo{}, foo, 5)),
+ ?TrueGuard(not is_record(#foo{}, barf, 6)),
+ ?TrueGuard(not is_record({foo}, foo, 5)),
- ?line ?FalseGuard(not erlang:is_record(#foo{}, foo, 5)),
- ?line ?TrueGuard(not erlang:is_record(#foo{}, barf, 5)),
- ?line ?TrueGuard(not erlang:is_record({foo}, foo, 5)),
+ ?FalseGuard(not erlang:is_record(#foo{}, foo, 5)),
+ ?TrueGuard(not erlang:is_record(#foo{}, barf, 5)),
+ ?TrueGuard(not erlang:is_record({foo}, foo, 5)),
Foo = id(#foo{}),
- ?line ?FalseGuard(not erlang:is_record(Foo, foo, 5)),
- ?line ?TrueGuard(not erlang:is_record(Foo, barf, 6)),
+ ?FalseGuard(not erlang:is_record(Foo, foo, 5)),
+ ?TrueGuard(not erlang:is_record(Foo, barf, 6)),
- ?line ?TrueGuard(not is_record(Config, foo, 5)),
+ ?TrueGuard(not is_record(Config, foo, 5)),
- ?line ?TrueGuard(not is_record(a, foo, 5)),
- ?line ?TrueGuard(not is_record([], foo, 5)),
+ ?TrueGuard(not is_record(a, foo, 5)),
+ ?TrueGuard(not is_record([], foo, 5)),
%% Pass non-literal first argument.
- ?line true = is_record(id(#foo{}), foo, 5),
- ?line false = is_record(id(#foo{}), barf, 6),
- ?line false = is_record(id({foo}), foo, 5),
+ true = is_record(id(#foo{}), foo, 5),
+ false = is_record(id(#foo{}), barf, 6),
+ false = is_record(id({foo}), foo, 5),
- ?line true = erlang:is_record(id(#foo{}), foo, 5),
- ?line false = erlang:is_record(id(#foo{}), barf, 6),
- ?line false = erlang:is_record(id({foo}), foo, 5),
+ true = erlang:is_record(id(#foo{}), foo, 5),
+ false = erlang:is_record(id(#foo{}), barf, 6),
+ false = erlang:is_record(id({foo}), foo, 5),
NoRec1 = id(blurf),
NoRec2 = id([]),
- ?line ?TrueGuard(not is_record(NoRec1, foo, 5)),
- ?line ?TrueGuard(not is_record(NoRec2, foo, 5)),
+ ?TrueGuard(not is_record(NoRec1, foo, 5)),
+ ?TrueGuard(not is_record(NoRec2, foo, 5)),
%% Force the use of guard bifs by using the 'xor' operation.
False = id(false),
- ?line ?TrueGuard(is_record(#foo{}, foo, 5) xor False),
- ?line ?FalseGuard(is_record(#foo{}, barf, 6) xor False),
- ?line ?FalseGuard(is_record({foo}, foo, 5) xor False ),
+ ?TrueGuard(is_record(#foo{}, foo, 5) xor False),
+ ?FalseGuard(is_record(#foo{}, barf, 6) xor False),
+ ?FalseGuard(is_record({foo}, foo, 5) xor False ),
- ?line ?TrueGuard(is_record(Foo, foo, 5) xor False),
- ?line ?FalseGuard(is_record(Foo, barf, 6) xor False),
+ ?TrueGuard(is_record(Foo, foo, 5) xor False),
+ ?FalseGuard(is_record(Foo, barf, 6) xor False),
%% Implicit guards by using a list comprehension.
List = id([1,#foo{a=2},3,#bar{d=4},5,#foo{a=6},7]),
- ?line [#foo{a=2},#foo{a=6}] = [X || X <- List, is_record(X, foo, 5)],
- ?line [#bar{d=4}] = [X || X <- List, is_record(X, bar, 5)],
- ?line [1,#foo{a=2},3,5,#foo{a=6},7] =
+ [#foo{a=2},#foo{a=6}] = [X || X <- List, is_record(X, foo, 5)],
+ [#bar{d=4}] = [X || X <- List, is_record(X, bar, 5)],
+ [1,#foo{a=2},3,5,#foo{a=6},7] =
[X || X <- List, not is_record(X, bar, 5)],
- ?line [1,3,5,7] =
+ [1,3,5,7] =
[X || X <- List, ((not is_record(X, bar, 5)) and (not is_record(X, foo, 5)))],
- ?line [#foo{a=2},#bar{d=4},#foo{a=6}] =
+ [#foo{a=2},#bar{d=4},#foo{a=6}] =
[X || X <- List, ((is_record(X, bar, 5)) or (is_record(X, foo, 5)))],
- ?line [1,3,#bar{d=4}] =
+ [1,3,#bar{d=4}] =
[X || X <- List, ((is_record(X, bar, 5)) or (X < 5))],
- ?line MyList = [#foo{a=3},x,[],{a,b}],
- ?line [#foo{a=3}] = [X || X <- MyList, is_record(X, foo, 5)],
- ?line [x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo, 5)],
- ?line [#foo{a=3}] = [X || X <- MyList, begin is_record(X, foo, 5) end],
- ?line [x,[],{a,b}] = [X || X <- MyList, begin not is_record(X, foo, 5) end],
- ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, is_record(X, foo, 5) or
- not is_binary(X)],
- ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo, 5) or
- not is_binary(X)],
- ?line [#foo{a=3}] = [X || X <- MyList, is_record(X, foo) or is_reference(X)],
- ?line [x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo) or
- is_reference(X)],
- ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList,
- begin is_record(X, foo, 5) or
- not is_binary(X) end],
- ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList,
- begin not is_record(X, foo, 5) or
- not is_binary(X) end],
- ?line [#foo{a=3}] = [X || X <- MyList,
- begin is_record(X, foo, 5) or is_reference(X) end],
- ?line [x,[],{a,b}] = [X || X <- MyList,
- begin not is_record(X, foo, 5) or
- is_reference(X) end],
+ MyList = [#foo{a=3},x,[],{a,b}],
+ [#foo{a=3}] = [X || X <- MyList, is_record(X, foo, 5)],
+ [x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo, 5)],
+ [#foo{a=3}] = [X || X <- MyList, begin is_record(X, foo, 5) end],
+ [x,[],{a,b}] = [X || X <- MyList, begin not is_record(X, foo, 5) end],
+ [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, is_record(X, foo, 5) or
+ not is_binary(X)],
+ [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo, 5) or
+ not is_binary(X)],
+ [#foo{a=3}] = [X || X <- MyList, is_record(X, foo) or is_reference(X)],
+ [x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo) or
+ is_reference(X)],
+ [#foo{a=3},x,[],{a,b}] = [X || X <- MyList,
+ begin is_record(X, foo, 5) or
+ not is_binary(X) end],
+ [#foo{a=3},x,[],{a,b}] = [X || X <- MyList,
+ begin not is_record(X, foo, 5) or
+ not is_binary(X) end],
+ [#foo{a=3}] = [X || X <- MyList,
+ begin is_record(X, foo, 5) or is_reference(X) end],
+ [x,[],{a,b}] = [X || X <- MyList,
+ begin not is_record(X, foo, 5) or
+ is_reference(X) end],
%% Update several fields with a string literal.
- ?line #barf{} = Barf0 = id(#barf{}),
- ?line Barf = update_barf(Barf0),
- ?line #barf{a="abc",b=1} = id(Barf),
+ #barf{} = Barf0 = id(#barf{}),
+ Barf = update_barf(Barf0),
+ #barf{a="abc",b=1} = id(Barf),
%% Non-literal arguments.
- ?line true = is_record(id(#barf{}), id(barf), id(6)),
- ?line false = is_record(id(#barf{}), id(barf), id(42)),
- ?line false = is_record(id(#barf{}), id(foo), id(6)),
+ true = is_record(id(#barf{}), id(barf), id(6)),
+ false = is_record(id(#barf{}), id(barf), id(42)),
+ false = is_record(id(#barf{}), id(foo), id(6)),
Rec = id(#barf{}),
Good = id(barf),
@@ -389,15 +388,15 @@ record_test_3(Config) when is_list(Config) ->
ok.
record_access_in_guards(Config) when is_list(Config) ->
- ?line Priv = ?config(priv_dir, Config),
- ?line file:set_cwd(test_lib:get_data_dir(Config)),
- ?line Opts0 = [{outdir,Priv},report_errors|test_lib:opt_opts(?MODULE)],
+ Priv = proplists:get_value(priv_dir, Config),
+ file:set_cwd(test_lib:get_data_dir(Config)),
+ Opts0 = [{outdir,Priv},report_errors|test_lib:opt_opts(?MODULE)],
M = record_access_in_guards,
Opts = [strict_record_tests|Opts0],
- ?line io:format("Options: ~p\n", [Opts]),
- ?line {ok,M} = c:c(M, Opts),
- ?line ok = M:t(),
+ io:format("Options: ~p\n", [Opts]),
+ {ok,M} = c:c(M, Opts),
+ ok = M:t(),
ok.
@@ -487,19 +486,19 @@ update_barf(R) ->
R#barf{a="abc",b=1}.
eval_once(Config) when is_list(Config) ->
- ?line once(fun(GetRec) ->
+ once(fun(GetRec) ->
true = erlang:is_record(GetRec(), foo)
end, #foo{}),
- ?line once(fun(GetRec) ->
+ once(fun(GetRec) ->
(GetRec())#foo{a=1}
end, #foo{}),
- ?line once(fun(GetRec) ->
+ once(fun(GetRec) ->
(GetRec())#foo{a=1,b=2}
end, #foo{}),
- ?line once(fun(GetRec) ->
+ once(fun(GetRec) ->
(GetRec())#foo{a=1,b=2,c=3}
end, #foo{}),
- ?line once(fun(GetRec) ->
+ once(fun(GetRec) ->
(GetRec())#foo{a=1,b=2,c=3,d=4}
end, #foo{}),
ok.
@@ -515,7 +514,7 @@ once(Test, Record) ->
1 -> ok;
N ->
io:format("Evaluated ~w times\n", [N]),
- ?t:fail()
+ ct:fail(more_than_once)
end,
Result.
@@ -571,21 +570,21 @@ nested_access(Config) when is_list(Config) ->
N0 = #nrec0{},
N1 = #nrec1{},
N2 = #nrec2{},
- ?line <<"nested0">> = N0#nrec0.name,
- ?line <<"nested1">> = N1#nrec1.name,
- ?line <<"nested2">> = N2#nrec2.name,
- ?line <<"nested0">> = N1#nrec1.nrec0#nrec0.name,
- ?line <<"nested0">> = N2#nrec2.nrec1#nrec1.nrec0#nrec0.name,
- ?line <<"nested1">> = N2#nrec2.nrec1#nrec1.name,
- ?line <<"nested0">> = ((N2#nrec2.nrec1)#nrec1.nrec0)#nrec0.name,
+ <<"nested0">> = N0#nrec0.name,
+ <<"nested1">> = N1#nrec1.name,
+ <<"nested2">> = N2#nrec2.name,
+ <<"nested0">> = N1#nrec1.nrec0#nrec0.name,
+ <<"nested0">> = N2#nrec2.nrec1#nrec1.nrec0#nrec0.name,
+ <<"nested1">> = N2#nrec2.nrec1#nrec1.name,
+ <<"nested0">> = ((N2#nrec2.nrec1)#nrec1.nrec0)#nrec0.name,
N1a = N2#nrec2.nrec1#nrec1{name = <<"nested1a">>},
- ?line <<"nested1a">> = N1a#nrec1.name,
+ <<"nested1a">> = N1a#nrec1.name,
N2a = N2#nrec2.nrec1#nrec1.nrec0#nrec0{name = <<"nested0a">>},
N2b = ((N2#nrec2.nrec1)#nrec1.nrec0)#nrec0{name = <<"nested0a">>},
- ?line <<"nested0a">> = N2a#nrec0.name,
- ?line N2a = N2b,
+ <<"nested0a">> = N2a#nrec0.name,
+ N2a = N2b,
ok.
-record(rr, {a,b,c}).
@@ -602,4 +601,60 @@ coverage(Config) when is_list(Config) ->
#rr{a=1,b=2,c=42} = id(R), %Test for correctness.
ok.
+
+-record(default_fun, {a = fun(X) -> X*X end}).
+
+%% compiler treats records with 1 and 2 fields differently...
+-record(gb_nil, {}).
+-record(gb_foo, {hello=1}).
+-record(gb_bar, {hello=2,there=3}).
+
+%% Taken from compilation_SUITE.
+grab_bag(_Config) ->
+ T1 = fun() ->
+ X = #foo{},
+ Y = #foo{},
+ {X#foo.a == Y#foo.a,X#foo.b}
+ end,
+ {true,undefined} = T1(),
+
+ T2 = fun(X, Y) ->
+ first_arg(X#foo.a =/= Y#foo.a, X#foo.b =/= X#foo.b)
+ end,
+ true = T2(#foo{a=x,b=z}, #foo{a=y,b=z}),
+
+ T3 = fun() ->
+ #default_fun{a=Fun} = id(#default_fun{}),
+ 9 = Fun(3)
+ end,
+ T3(),
+
+ %% Stupid code, but the compiler used to crash.
+ T4 = fun() ->
+ F0 = fun() ->
+ R1 = #gb_nil{},
+ R2 = R1#gb_nil{},
+ R1 = R2
+ end,
+ F1 = fun() ->
+ R1 = #gb_foo{},
+ R2 = R1#gb_foo{},
+ R1 = R2
+ end,
+
+ F2 = fun() ->
+ R1 = #gb_bar{},
+ R2 = R1#gb_bar{},
+ R1 = R2
+ end,
+ F0(),
+ F1(),
+ F2()
+ end,
+ T4(),
+
+ ok.
+
+first_arg(First, _) -> First.
+
id(I) -> I.
diff --git a/lib/compiler/test/record_SUITE_data/record_access_in_guards.erl b/lib/compiler/test/record_SUITE_data/record_access_in_guards.erl
index fb3d7d3ae4..dbd2419ad2 100644
--- a/lib/compiler/test/record_SUITE_data/record_access_in_guards.erl
+++ b/lib/compiler/test/record_SUITE_data/record_access_in_guards.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,12 +27,12 @@
-record(r3, {a = fun(_) -> #r1{} end(1), b}).
t() ->
- foo = fun(A) when A#r1.a > A#r1.b -> foo end(#r1{b = 2}),
- 0 = fun(A) when A#r2.a -> 0 end(#r2{a = true}),
+ foo = rec_call(fun(A) when A#r1.a > A#r1.b -> foo end, #r1{b = 2}),
+ 0 = rec_call(fun(A) when A#r2.a -> 0 end, #r2{a = true}),
1 = fun(A) when (#r1{a = A})#r1.a > 2 -> 1 end(3),
2 = fun(N) when ((#r2{a = #r{a = 4}, b = length([a,b,c])})#r2.a)#r.a > N ->
- 2 end(2),
- 3 = fun(A) when (A#r2.a)#r1.a =:= 3 -> 3 end(#r2{a = #r1{a = 3}}),
+ 2 end(2),
+ 3 = rec_call(fun(A) when (A#r2.a)#r1.a =:= 3 -> 3 end, #r2{a = #r1{a = 3}}),
ok = fun() ->
F = fun(A) when record(A#r.a, r1) -> 4;
(A) when record(A#r1.a, r1) -> 5
@@ -41,9 +41,9 @@ t() ->
4 = F(#r{a = #r1{}}),
ok
end(),
- 3 = fun(A) when record(A#r1.a, r),
- (A#r1.a)#r.a > 3 -> 3
- end(#r1{a = #r{a = 4}}),
+ 3 = rec_call(fun(A) when record(A#r1.a, r),
+ (A#r1.a)#r.a > 3 -> 3
+ end, #r1{a = #r{a = 4}}),
7 = fun(A) when record(A#r3.a, r1) -> 7 end(#r3{}),
[#r1{a = 2,b = 1}] =
fun() ->
@@ -71,9 +71,10 @@ t() ->
(_) -> p
end(#r1{a = 2}),
- 3 = fun(A) when A#r1.a > 3,
- record(A, r1) -> 3
- end(#r1{a = 5}),
+ o = rec_call(fun(A) when (A#r1.a =:= 2) orelse (A#r2.a =:= 1) -> o end, #r1{a = 2}),
+ o = rec_call(fun(A) when A#r1.a =:= 2; A#r2.a =:= 1 -> o end, #r2{a = 1}),
+
+ 3 = rec_call(fun(A) when A#r1.a > 3, record(A, r1) -> 3 end, #r1{a = 5}),
ok = fun() ->
F = fun(A) when (A#r2.a =:= 1) orelse (A#r2.a) -> 2;
@@ -93,6 +94,8 @@ t() ->
(_) -> b
end(#r1{a = 1}),
+ a = rec_call(fun(A) when not (A#r.a =:= 1) or false -> a end, #r{a = 42}),
+
ok = fun() ->
F = fun(A) when not (A#r.a =:= 1) -> yes;
(_) -> no
@@ -103,14 +106,14 @@ t() ->
ok
end(),
- a = fun(A) when record(A, r),
- A#r.a =:= 1,
- A#r.b =:= 2 ->a
- end(#r{a = 1, b = 2}),
- a = fun(A) when erlang:is_record(A, r),
- A#r.a =:= 1,
- A#r.b =:= 2 -> a
- end(#r{a = 1, b = 2}),
+ a = rec_call(fun(A) when record(A, r),
+ A#r.a =:= 1,
+ A#r.b =:= 2 -> a
+ end, #r{a = 1, b = 2}),
+ a = rec_call(fun(A) when erlang:is_record(A, r),
+ A#r.a =:= 1,
+ A#r.b =:= 2 -> a
+ end, #r{a = 1, b = 2}),
a = fun(A) when is_record(A, r),
A#r.a =:= 1,
A#r.b =:= 2 -> a
@@ -144,8 +147,7 @@ t() ->
ok
end(),
- both = fun(A) when A#r.a, A#r.b -> both
- end(#r{a = true, b = true}),
+ both = rec_call(fun(A) when A#r.a, A#r.b -> both end, #r{a = true, b = true}),
ok = fun() ->
F = fun(A, B) when ((A#r1.a) orelse (B#r2.a))
@@ -176,3 +178,24 @@ t() ->
ok.
+rec_call(F, Rec) ->
+ Corrupted1 = setelement(1, Rec, wrong),
+ Corrupted2 = erlang:append_element(Rec, extra),
+ Corrupted3 = erlang:append_element(Corrupted1, extra),
+ fc(F, Corrupted1),
+ fc(F, Corrupted2),
+ fc(F, Corrupted3),
+ F(Rec).
+
+fc(F, Term) ->
+ try
+ F(Term),
+ error(expected_to_fail)
+ catch
+ error:function_clause ->
+ ok;
+ error:{case_clause,_} ->
+ Comp = ?MODULE:module_info(compile),
+ {_,Opts} = lists:keyfind(options, 1, Comp),
+ true = lists:member(inline, Opts)
+ end.
diff --git a/lib/compiler/test/regressions_SUITE.erl b/lib/compiler/test/regressions_SUITE.erl
index 716a9693ed..7a6fe08c73 100644
--- a/lib/compiler/test/regressions_SUITE.erl
+++ b/lib/compiler/test/regressions_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,29 +19,26 @@
%% Test specific code snippets that has crashed the compiler in the past.
-module(regressions_SUITE).
--include_lib("test_server/include/test_server.hrl").
-
--export([all/0, groups/0, init_per_testcase/2,end_per_testcase/2]).
+-include_lib("common_test/include/ct.hrl").
+-export([all/0,groups/0,init_per_testcase/2,end_per_testcase/2,suite/0]).
-export([maps/1]).
-groups() ->
+groups() ->
[{p,test_lib:parallel(),
[maps]}].
-% Default timetrap timeout (set in init_per_testcase).
--define(default_timeout, ?t:minutes(2)).
-
init_per_testcase(_Case, Config) ->
- ?line Dog = ?t:timetrap(?default_timeout),
- [{watchdog, Dog} | Config].
+ Config.
-end_per_testcase(_Case, Config) ->
- Dog = ?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
+end_per_testcase(_Case, _Config) ->
ok.
-all() ->
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,2}}].
+
+all() ->
test_lib:recompile(?MODULE),
[{group,p}].
@@ -51,7 +48,18 @@ maps(Config) when is_list(Config) ->
Ts = [{beam_bool_get_elements,
<<"century(#{ron := operator}, _century) ->
if 0.0; _century, _century, _century -> _century end.
- ">>}],
+ ">>},
+ {empty_map_clauses,
+ <<"politics(#{}, researchers) -> concerned;
+ politics(#{[] := _}, workers) -> dot;
+ politics(#{[] := ct}, counsel) -> calls.
+ ">>},
+ {empty_map_clauses_variable,
+ <<"georgia(#{a := effectively}, ratio, is, eventually) -> teens;
+ georgia(#{a := government}, knowledge, poker, partly) -> signed;
+ georgia(#{}, recording, bring, vital) -> divided;
+ georgia(#{0 := 0}, articles, brought, #{true := true, a := There}) -> There.
+ ">>}],
ok = run(Config, Ts),
ok.
@@ -61,8 +69,9 @@ run(Config, Tests) ->
F = fun({N,P}) ->
io:format("Compiling test for: ~w~n", [N]),
case catch run_test(Config, P) of
- {'EXIT', Reason} ->
- ?t:format("~nTest ~p failed.~nReason: ~p~n", [N, Reason]),
+ {'EXIT', Reason} ->
+ io:format("~nTest ~p failed.~nReason: ~p~n",
+ [N, Reason]),
fail();
_ -> ok
end
@@ -73,7 +82,7 @@ run(Config, Tests) ->
run_test(Conf, Test0) ->
Module = "regressions_"++test_lib:uniq(),
Filename = Module ++ ".erl",
- DataDir = ?config(priv_dir, Conf),
+ DataDir = proplists:get_value(priv_dir, Conf),
Test = ["-module(", Module, "). ", Test0],
File = filename:join(DataDir, Filename),
Def = [binary,export_all,return],
@@ -94,5 +103,4 @@ run_test(Conf, Test0) ->
ok.
fail() ->
- io:format("failed~n"),
- ?t:fail().
+ ct:fail(failed).
diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl
index 09ec8f3c81..8954a9f5fb 100644
--- a/lib/compiler/test/test_lib.erl
+++ b/lib/compiler/test/test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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.
@@ -19,10 +19,13 @@
%%
-module(test_lib).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
-compile({no_auto_import,[binary_part/2]}).
-export([id/1,recompile/1,parallel/0,uniq/0,opt_opts/1,get_data_dir/1,
- smoke_disasm/1,p_run/2,binary_part/2]).
+ is_cloned_mod/1,smoke_disasm/1,p_run/2]).
+
+%% Used by test case that override BIFs.
+-export([binary_part/2,binary/1]).
id(I) -> I.
@@ -52,7 +55,7 @@ smoke_disasm(File) when is_list(File) ->
%% be slower than running them sequentially.
parallel() ->
- case ?t:is_cover() orelse erlang:system_info(schedulers) =:= 1 of
+ case test_server:is_cover() orelse erlang:system_info(schedulers) =:= 1 of
true -> [];
false -> [parallel]
end.
@@ -66,7 +69,7 @@ uniq() ->
opt_opts(Mod) ->
Comp = Mod:module_info(compile),
- {value,{options,Opts}} = lists:keysearch(options, 1, Comp),
+ {options,Opts} = lists:keyfind(options, 1, Comp),
lists:filter(fun(no_copt) -> true;
(no_postopt) -> true;
(no_float_opt) -> true;
@@ -85,18 +88,29 @@ opt_opts(Mod) ->
%% This function retrieves the path to the original data directory.
get_data_dir(Config) ->
- Data0 = ?config(data_dir, Config),
+ Data0 = proplists:get_value(data_dir, Config),
Opts = [{return,list}],
Data1 = re:replace(Data0, "_no_opt_SUITE", "_SUITE", Opts),
Data = re:replace(Data1, "_post_opt_SUITE", "_SUITE", Opts),
re:replace(Data, "_inline_SUITE", "_SUITE", Opts).
+is_cloned_mod(Mod) ->
+ is_cloned_mod_1(atom_to_list(Mod)).
+
+%% Test whether Mod is a cloned module.
+
+is_cloned_mod_1("no_opt_SUITE") -> true;
+is_cloned_mod_1("post_opt_SUITE") -> true;
+is_cloned_mod_1("inline_SUITE") -> true;
+is_cloned_mod_1([_|T]) -> is_cloned_mod_1(T);
+is_cloned_mod_1([]) -> false.
+
%% p_run(fun(Data) -> ok|error, List) -> ok
%% Will fail the test case if there were any errors.
p_run(Test, List) ->
S = erlang:system_info(schedulers),
- N = case ?t:is_cover() of
+ N = case test_server:is_cover() of
false ->
S + 1;
true ->
@@ -106,8 +120,9 @@ p_run(Test, List) ->
%% slightly faster than using 3. Using more than
%% 4 would not buy us much and could actually be
%% slower.
- max(S, 4)
+ min(S, 4)
end,
+ io:format("p_run: ~p parallel processes\n", [N]),
p_run_loop(Test, List, N, [], 0, 0).
p_run_loop(_, [], _, [], Errors, Ws) ->
@@ -118,7 +133,8 @@ p_run_loop(_, [], _, [], Errors, Ws) ->
1 -> {comment,"1 warning"};
N -> {comment,integer_to_list(N)++" warnings"}
end;
- N -> ?t:fail({N,errors})
+ N ->
+ ct:fail({N,errors})
end;
p_run_loop(Test, [H|T], N, Refs, Errors, Ws) when length(Refs) < N ->
{_,Ref} = erlang:spawn_monitor(fun() -> exit(Test(H)) end),
@@ -138,3 +154,7 @@ p_run_loop(Test, List, N, Refs0, Errors0, Ws0) ->
%% This is for the misc_SUITE:override_bif testcase
binary_part(_A,_B) ->
dummy.
+
+%% This is for overridden_bif_SUITE.
+binary(N) ->
+ N rem 10 =:= 0.
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl
index adcab8ef67..a591d6cc93 100644
--- a/lib/compiler/test/trycatch_SUITE.erl
+++ b/lib/compiler/test/trycatch_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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.
@@ -26,9 +26,9 @@
nested_of/1,nested_catch/1,nested_after/1,
nested_horrid/1,last_call_optimization/1,bool/1,
plain_catch_coverage/1,andalso_orelse/1,get_in_try/1,
- hockey/1]).
+ hockey/1,handle_info/1,catch_in_catch/1,grab_bag/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -42,7 +42,7 @@ groups() ->
after_oops,eclectic,rethrow,nested_of,nested_catch,
nested_after,nested_horrid,last_call_optimization,
bool,plain_catch_coverage,andalso_orelse,get_in_try,
- hockey]}].
+ hockey,handle_info,catch_in_catch,grab_bag]}].
init_per_suite(Config) ->
@@ -60,32 +60,32 @@ end_per_group(_GroupName, Config) ->
basic(Conf) when is_list(Conf) ->
- ?line 2 =
+ 2 =
try my_div(4, 2)
catch
Class:Reason -> {Class,Reason}
end,
- ?line error =
+ error =
try my_div(1, 0)
catch
error:badarith -> error
end,
- ?line error =
+ error =
try 1.0 / zero()
catch
error:badarith -> error
end,
- ?line ok =
+ ok =
try my_add(53, atom)
catch
error:badarith -> ok
end,
- ?line exit_nisse =
+ exit_nisse =
try exit(nisse)
catch
exit:nisse -> exit_nisse
end,
- ?line ok =
+ ok =
try throw(kalle)
catch
kalle -> ok
@@ -94,27 +94,27 @@ basic(Conf) when is_list(Conf) ->
%% Try some stuff where the compiler will optimize away the try.
V = id({a,variable}),
- ?line V = try V catch nisse -> error end,
- ?line 42 = try 42 catch nisse -> error end,
- ?line [V] = try [V] catch nisse -> error end,
- ?line {ok,V} = try {ok,V} catch nisse -> error end,
+ V = try V catch nisse -> error end,
+ 42 = try 42 catch nisse -> error end,
+ [V] = try [V] catch nisse -> error end,
+ {ok,V} = try {ok,V} catch nisse -> error end,
%% Same idea, but use an after too.
- ?line V = try V catch nisse -> error after after_call() end,
- ?line after_clean(),
- ?line 42 = try 42 after after_call() end,
- ?line after_clean(),
- ?line [V] = try [V] catch nisse -> error after after_call() end,
- ?line after_clean(),
- ?line {ok,V} = try {ok,V} after after_call() end,
+ V = try V catch nisse -> error after after_call() end,
+ after_clean(),
+ 42 = try 42 after after_call() end,
+ after_clean(),
+ [V] = try [V] catch nisse -> error after after_call() end,
+ after_clean(),
+ {ok,V} = try {ok,V} after after_call() end,
%% Try/of
- ?line ok = try V of
- {a,variable} -> ok
- catch nisse -> erro
- end,
-
+ ok = try V of
+ {a,variable} -> ok
+ catch nisse -> erro
+ end,
+
ok.
after_call() ->
@@ -125,24 +125,24 @@ after_clean() ->
lean_throw(Conf) when is_list(Conf) ->
- ?line {throw,kalle} =
+ {throw,kalle} =
try throw(kalle)
catch
Kalle -> {throw,Kalle}
end,
- ?line {exit,kalle} =
+ {exit,kalle} =
try exit(kalle)
catch
Throw1 -> {throw,Throw1};
exit:Reason1 -> {exit,Reason1}
end,
- ?line {exit,kalle} =
+ {exit,kalle} =
try exit(kalle)
catch
exit:Reason2 -> {exit,Reason2};
Throw2 -> {throw,Throw2}
end,
- ?line {exit,kalle} =
+ {exit,kalle} =
try try exit(kalle)
catch
Throw3 -> {throw,Throw3}
@@ -155,25 +155,25 @@ lean_throw(Conf) when is_list(Conf) ->
try_of(Conf) when is_list(Conf) ->
- ?line {ok,{some,content}} =
+ {ok,{some,content}} =
try_of_1({value,{good,{some,content}}}),
- ?line {error,[other,content]} =
+ {error,[other,content]} =
try_of_1({value,{bad,[other,content]}}),
- ?line {caught,{exit,{ex,it,[reason]}}} =
+ {caught,{exit,{ex,it,[reason]}}} =
try_of_1({exit,{ex,it,[reason]}}),
- ?line {caught,{throw,[term,{in,a,{tuple}}]}} =
+ {caught,{throw,[term,{in,a,{tuple}}]}} =
try_of_1({throw,[term,{in,a,{tuple}}]}),
- ?line {caught,{error,[bad,arg]}} =
+ {caught,{error,[bad,arg]}} =
try_of_1({error,[bad,arg]}),
- ?line {caught,{error,badarith}} =
+ {caught,{error,badarith}} =
try_of_1({'div',{1,0}}),
- ?line {caught,{error,badarith}} =
+ {caught,{error,badarith}} =
try_of_1({'add',{a,0}}),
- ?line {caught,{error,badarg}} =
+ {caught,{error,badarg}} =
try_of_1({'abs',x}),
- ?line {caught,{error,function_clause}} =
+ {caught,{error,function_clause}} =
try_of_1(illegal),
- ?line {error,{try_clause,{some,other_garbage}}} =
+ {error,{try_clause,{some,other_garbage}}} =
try try_of_1({value,{some,other_garbage}})
catch error:Reason -> {error,Reason}
end,
@@ -191,29 +191,29 @@ try_of_1(X) ->
try_after(Conf) when is_list(Conf) ->
- ?line {{ok,[some,value],undefined},finalized} =
+ {{ok,[some,value],undefined},finalized} =
try_after_1({value,{ok,[some,value]}},finalized),
- ?line {{error,badarith,undefined},finalized} =
+ {{error,badarith,undefined},finalized} =
try_after_1({'div',{1,0}},finalized),
- ?line {{error,badarith,undefined},finalized} =
+ {{error,badarith,undefined},finalized} =
try_after_1({'add',{1,a}},finalized),
- ?line {{error,badarg,undefined},finalized} =
+ {{error,badarg,undefined},finalized} =
try_after_1({'abs',a},finalized),
- ?line {{error,[the,{reason}],undefined},finalized} =
+ {{error,[the,{reason}],undefined},finalized} =
try_after_1({error,[the,{reason}]},finalized),
- ?line {{throw,{thrown,[reason]},undefined},finalized} =
+ {{throw,{thrown,[reason]},undefined},finalized} =
try_after_1({throw,{thrown,[reason]}},finalized),
- ?line {{exit,{exited,{reason}},undefined},finalized} =
+ {{exit,{exited,{reason}},undefined},finalized} =
try_after_1({exit,{exited,{reason}}},finalized),
- ?line {{error,function_clause,undefined},finalized} =
+ {{error,function_clause,undefined},finalized} =
try_after_1(function_clause,finalized),
- ?line ok =
+ ok =
try try_after_1({'add',{1,1}}, finalized)
catch
error:{try_clause,2} -> ok
end,
- ?line finalized = erase(try_after),
- ?line ok =
+ finalized = erase(try_after),
+ ok =
try try foo({exit,[reaso,{n}]})
after put(try_after, finalized)
end
@@ -242,7 +242,7 @@ try_after_1(X, Y) ->
after_bind(Conf) when is_list(Conf) ->
V = [make_ref(),self()|value],
- ?line {value,{value,V}} =
+ {value,{value,V}} =
after_bind_1({value,V}, V, {value,V}),
ok.
@@ -269,12 +269,12 @@ after_bind_1(X, V, Y) ->
catch_oops(Conf) when is_list(Conf) ->
V = {v,[a,l|u],{e},self()},
- ?line {value,V} = catch_oops_1({value,V}),
- ?line {value,1} = catch_oops_1({'div',{1,1}}),
- ?line {error,badarith} = catch_oops_1({'div',{1,0}}),
- ?line {error,function_clause} = catch_oops_1(function_clause),
- ?line {throw,V} = catch_oops_1({throw,V}),
- ?line {exit,V} = catch_oops_1({exit,V}),
+ {value,V} = catch_oops_1({value,V}),
+ {value,1} = catch_oops_1({'div',{1,1}}),
+ {error,badarith} = catch_oops_1({'div',{1,0}}),
+ {error,function_clause} = catch_oops_1(function_clause),
+ {throw,V} = catch_oops_1({throw,V}),
+ {exit,V} = catch_oops_1({exit,V}),
ok.
catch_oops_1(X) ->
@@ -293,10 +293,10 @@ catch_oops_1(X) ->
after_oops(Conf) when is_list(Conf) ->
V = {self(),make_ref()},
- ?line {{value,V},V} = after_oops_1({value,V}, {value,V}),
- ?line {{exit,V},V} = after_oops_1({exit,V}, {value,V}),
- ?line {{error,V},undefined} = after_oops_1({value,V}, {error,V}),
- ?line {{error,function_clause},undefined} =
+ {{value,V},V} = after_oops_1({value,V}, {value,V}),
+ {{exit,V},V} = after_oops_1({exit,V}, {value,V}),
+ {{error,V},undefined} = after_oops_1({value,V}, {error,V}),
+ {{error,function_clause},undefined} =
after_oops_1({exit,V}, function_clause),
ok.
@@ -317,39 +317,39 @@ after_oops_1(X, Y) ->
eclectic(Conf) when is_list(Conf) ->
V = {make_ref(),3.1415926535,[[]|{}]},
- ?line {{value,{value,V},V},V} =
+ {{value,{value,V},V},V} =
eclectic_1({foo,{value,{value,V}}}, undefined, {value,V}),
- ?line {{'EXIT',{V,[{?MODULE,foo,1,_}|_]}},V} =
+ {{'EXIT',{V,[{?MODULE,foo,1,_}|_]}},V} =
eclectic_1({catch_foo,{error,V}}, undefined, {value,V}),
- ?line {{error,{exit,V},{'EXIT',V}},V} =
+ {{error,{exit,V},{'EXIT',V}},V} =
eclectic_1({foo,{error,{exit,V}}}, error, {value,V}),
- ?line {{value,{value,V},V},
+ {{value,{value,V},V},
{'EXIT',{badarith,[{?MODULE,my_add,2,_}|_]}}} =
eclectic_1({foo,{value,{value,V}}}, undefined, {'add',{0,a}}),
- ?line {{'EXIT',V},V} =
+ {{'EXIT',V},V} =
eclectic_1({catch_foo,{exit,V}}, undefined, {throw,V}),
- ?line {{error,{'div',{1,0}},{'EXIT',{badarith,[{?MODULE,my_div,2,_}|_]}}},
+ {{error,{'div',{1,0}},{'EXIT',{badarith,[{?MODULE,my_div,2,_}|_]}}},
{'EXIT',V}} =
eclectic_1({foo,{error,{'div',{1,0}}}}, error, {exit,V}),
- ?line {{{error,V},{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},
+ {{{error,V},{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},
{'EXIT',V}} =
eclectic_1({catch_foo,{throw,{error,V}}}, undefined, {exit,V}),
%%
- ?line {{value,{value,{value,V},V}},V} =
+ {{value,{value,{value,V},V}},V} =
eclectic_2({value,{value,V}}, undefined, {value,V}),
- ?line {{value,{throw,{value,V},V}},V} =
+ {{value,{throw,{value,V},V}},V} =
eclectic_2({throw,{value,V}}, throw, {value,V}),
- ?line {{caught,{'EXIT',V}},undefined} =
+ {{caught,{'EXIT',V}},undefined} =
eclectic_2({value,{value,V}}, undefined, {exit,V}),
- ?line {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
+ {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
eclectic_2({error,{value,V}}, throw, {error,V}),
- ?line {{caught,{'EXIT',{badarg,[{erlang,abs,[V],_}|_]}}},V} =
+ {{caught,{'EXIT',{badarg,[{erlang,abs,[V],_}|_]}}},V} =
eclectic_2({value,{'abs',V}}, undefined, {value,V}),
- ?line {{caught,{'EXIT',{badarith,[{?MODULE,my_add,2,_}|_]}}},V} =
+ {{caught,{'EXIT',{badarith,[{?MODULE,my_add,2,_}|_]}}},V} =
eclectic_2({exit,{'add',{0,a}}}, exit, {value,V}),
- ?line {{caught,{'EXIT',V}},undefined} =
+ {{caught,{'EXIT',V}},undefined} =
eclectic_2({value,{error,V}}, undefined, {exit,V}),
- ?line {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
+ {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
eclectic_2({throw,{'div',{1,0}}}, throw, {error,V}),
ok.
@@ -377,44 +377,44 @@ eclectic_2(X, C, Y) ->
Catch =
case
catch
- {Done,
- try foo(X) of
- V -> {value,V,foo(V)}
- catch
- C:D -> {C,D,foo(D)}
- after
- put(eclectic, foo(Y))
- end} of
- {Done,Z} -> {value,Z};
- Z -> {caught,Z}
- end,
+ {Done,
+ try foo(X) of
+ V -> {value,V,foo(V)}
+ catch
+ C:D -> {C,D,foo(D)}
+ after
+ put(eclectic, foo(Y))
+ end} of
+ {Done,Z} -> {value,Z};
+ Z -> {caught,Z}
+ end,
{Catch,erase(eclectic)}.
rethrow(Conf) when is_list(Conf) ->
V = {a,[b,{c,self()},make_ref]},
- ?line {value2,value1} =
+ {value2,value1} =
rethrow_1({value,V}, V),
- ?line {caught2,{error,V}} =
+ {caught2,{error,V}} =
rethrow_2({error,V}, undefined),
- ?line {caught2,{exit,V}} =
+ {caught2,{exit,V}} =
rethrow_1({exit,V}, error),
- ?line {caught2,{throw,V}} =
+ {caught2,{throw,V}} =
rethrow_1({throw,V}, undefined),
- ?line {caught2,{throw,V}} =
+ {caught2,{throw,V}} =
rethrow_2({throw,V}, undefined),
- ?line {caught2,{error,badarith}} =
+ {caught2,{error,badarith}} =
rethrow_1({'add',{0,a}}, throw),
- ?line {caught2,{error,function_clause}} =
+ {caught2,{error,function_clause}} =
rethrow_2(function_clause, undefined),
- ?line {caught2,{error,{try_clause,V}}} =
+ {caught2,{error,{try_clause,V}}} =
rethrow_1({value,V}, exit),
- ?line {value2,{caught1,V}} =
+ {value2,{caught1,V}} =
rethrow_1({error,V}, error),
- ?line {value2,{caught1,V}} =
+ {value2,{caught1,V}} =
rethrow_1({exit,V}, exit),
- ?line {value2,caught1} =
+ {value2,caught1} =
rethrow_2({throw,V}, V),
ok.
@@ -444,91 +444,91 @@ rethrow_2(X, C1) ->
nested_of(Conf) when is_list(Conf) ->
V = {[self()|make_ref()],1.4142136},
- ?line {{value,{value1,{V,x2}}},
- {V,x3},
- {V,x4},
- finalized} =
+ {{value,{value1,{V,x2}}},
+ {V,x3},
+ {V,x4},
+ finalized} =
nested_of_1({{value,{V,x1}},void,{V,x1}},
{value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{throw,{V,x2}}},
- {V,x3},
- {V,x4},
- finalized} =
+ {{caught,{throw,{V,x2}}},
+ {V,x3},
+ {V,x4},
+ finalized} =
nested_of_1({{value,{V,x1}},void,{V,x1}},
{throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{error,badarith}},
- undefined,
- {V,x4},
- finalized} =
+ {{caught,{error,badarith}},
+ undefined,
+ {V,x4},
+ finalized} =
nested_of_1({{value,{V,x1}},void,{V,x1}},
{throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}),
- ?line {{caught,{error,badarith}},
- undefined,
- undefined,
- finalized} =
+ {{caught,{error,badarith}},
+ undefined,
+ undefined,
+ finalized} =
nested_of_1({{value,{V,x1}},void,{V,x1}},
{throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}),
%%
- ?line {{caught,{error,{try_clause,{V,x1}}}},
- {V,x3},
- {V,x4},
- finalized} =
+ {{caught,{error,{try_clause,{V,x1}}}},
+ {V,x3},
+ {V,x4},
+ finalized} =
nested_of_1({{value,{V,x1}},void,try_clause},
void, {value,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{exit,{V,x3}}},
- undefined,
- {V,x4},
- finalized} =
+ {{caught,{exit,{V,x3}}},
+ undefined,
+ {V,x4},
+ finalized} =
nested_of_1({{value,{V,x1}},void,try_clause},
void, {exit,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{throw,{V,x4}}},
- undefined,
- undefined,
- finalized} =
+ {{caught,{throw,{V,x4}}},
+ undefined,
+ undefined,
+ finalized} =
nested_of_1({{value,{V,x1}},void,try_clause},
void, {exit,{V,x3}}, {throw,{V,x4}}),
%%
- ?line {{value,{caught1,{V,x2}}},
- {V,x3},
- {V,x4},
- finalized} =
+ {{value,{caught1,{V,x2}}},
+ {V,x3},
+ {V,x4},
+ finalized} =
nested_of_1({{error,{V,x1}},error,{V,x1}},
{value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{error,badarith}},
- {V,x3},
- {V,x4},
- finalized} =
+ {{caught,{error,badarith}},
+ {V,x3},
+ {V,x4},
+ finalized} =
nested_of_1({{error,{V,x1}},error,{V,x1}},
{'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{error,badarith}},
- undefined,
- {V,x4},
- finalized} =
+ {{caught,{error,badarith}},
+ undefined,
+ {V,x4},
+ finalized} =
nested_of_1({{error,{V,x1}},error,{V,x1}},
{'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}),
- ?line {{caught,{error,badarg}},
- undefined,
- undefined,
- finalized} =
+ {{caught,{error,badarg}},
+ undefined,
+ undefined,
+ finalized} =
nested_of_1({{error,{V,x1}},error,{V,x1}},
{'add',{1,c}}, {'div',{17,0}}, {'abs',V}),
%%
- ?line {{caught,{error,badarith}},
- {V,x3},
- {V,x4},
- finalized} =
+ {{caught,{error,badarith}},
+ {V,x3},
+ {V,x4},
+ finalized} =
nested_of_1({{'add',{2,c}},rethrow,void},
void, {value,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{error,badarg}},
- undefined,
- {V,x4},
- finalized} =
+ {{caught,{error,badarg}},
+ undefined,
+ {V,x4},
+ finalized} =
nested_of_1({{'add',{2,c}},rethrow,void},
void, {'abs',V}, {value,{V,x4}}),
- ?line {{caught,{error,function_clause}},
- undefined,
- undefined,
- finalized} =
+ {{caught,{error,function_clause}},
+ undefined,
+ undefined,
+ finalized} =
nested_of_1({{'add',{2,c}},rethrow,void},
void, {'abs',V}, function_clause),
ok.
@@ -569,93 +569,93 @@ nested_of_1({X1,C1,V1},
nested_catch(Conf) when is_list(Conf) ->
V = {[make_ref(),1.4142136,self()]},
- ?line {{value,{value1,{V,x2}}},
- {V,x3},
- {V,x4},
- finalized} =
+ {{value,{value1,{V,x2}}},
+ {V,x3},
+ {V,x4},
+ finalized} =
nested_catch_1({{value,{V,x1}},void,{V,x1}},
- {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{throw,{V,x2}}},
- {V,x3},
- {V,x4},
- finalized} =
+ {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
+ {{caught,{throw,{V,x2}}},
+ {V,x3},
+ {V,x4},
+ finalized} =
nested_catch_1({{value,{V,x1}},void,{V,x1}},
- {throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{error,badarith}},
- undefined,
- {V,x4},
- finalized} =
+ {throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
+ {{caught,{error,badarith}},
+ undefined,
+ {V,x4},
+ finalized} =
nested_catch_1({{value,{V,x1}},void,{V,x1}},
- {throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}),
- ?line {{caught,{error,badarith}},
- undefined,
- undefined,
- finalized} =
+ {throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}),
+ {{caught,{error,badarith}},
+ undefined,
+ undefined,
+ finalized} =
nested_catch_1({{value,{V,x1}},void,{V,x1}},
- {throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}),
+ {throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}),
%%
- ?line {{caught,{error,{try_clause,{V,x1}}}},
- {V,x3},
- {V,x4},
- finalized} =
+ {{caught,{error,{try_clause,{V,x1}}}},
+ {V,x3},
+ {V,x4},
+ finalized} =
nested_catch_1({{value,{V,x1}},void,try_clause},
- void, {value,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{exit,{V,x3}}},
- undefined,
- {V,x4},
- finalized} =
+ void, {value,{V,x3}}, {value,{V,x4}}),
+ {{caught,{exit,{V,x3}}},
+ undefined,
+ {V,x4},
+ finalized} =
nested_catch_1({{value,{V,x1}},void,try_clause},
- void, {exit,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{throw,{V,x4}}},
- undefined,
- undefined,
- finalized} =
+ void, {exit,{V,x3}}, {value,{V,x4}}),
+ {{caught,{throw,{V,x4}}},
+ undefined,
+ undefined,
+ finalized} =
nested_catch_1({{value,{V,x1}},void,try_clause},
- void, {exit,{V,x3}}, {throw,{V,x4}}),
+ void, {exit,{V,x3}}, {throw,{V,x4}}),
%%
- ?line {{value,{caught1,{V,x2}}},
- {V,x3},
- {V,x4},
- finalized} =
+ {{value,{caught1,{V,x2}}},
+ {V,x3},
+ {V,x4},
+ finalized} =
nested_catch_1({{error,{V,x1}},error,{V,x1}},
- {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{error,badarith}},
- {V,x3},
- {V,x4},
- finalized} =
+ {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
+ {{caught,{error,badarith}},
+ {V,x3},
+ {V,x4},
+ finalized} =
nested_catch_1({{error,{V,x1}},error,{V,x1}},
- {'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{error,badarith}},
- undefined,
- {V,x4},
- finalized} =
+ {'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}),
+ {{caught,{error,badarith}},
+ undefined,
+ {V,x4},
+ finalized} =
nested_catch_1({{error,{V,x1}},error,{V,x1}},
- {'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}),
- ?line {{caught,{error,badarg}},
- undefined,
- undefined,
- finalized} =
+ {'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}),
+ {{caught,{error,badarg}},
+ undefined,
+ undefined,
+ finalized} =
nested_catch_1({{error,{V,x1}},error,{V,x1}},
- {'add',{1,c}}, {'div',{17,0}}, {'abs',V}),
+ {'add',{1,c}}, {'div',{17,0}}, {'abs',V}),
%%
- ?line {{caught,{error,badarith}},
- {V,x3},
- {V,x4},
- finalized} =
+ {{caught,{error,badarith}},
+ {V,x3},
+ {V,x4},
+ finalized} =
nested_catch_1({{'add',{2,c}},rethrow,void},
- void, {value,{V,x3}}, {value,{V,x4}}),
- ?line {{caught,{error,badarg}},
- undefined,
- {V,x4},
- finalized} =
+ void, {value,{V,x3}}, {value,{V,x4}}),
+ {{caught,{error,badarg}},
+ undefined,
+ {V,x4},
+ finalized} =
nested_catch_1({{'add',{2,c}},rethrow,void},
- void, {'abs',V}, {value,{V,x4}}),
- ?line {{caught,{error,function_clause}},
- undefined,
- undefined,
- finalized} =
+ void, {'abs',V}, {value,{V,x4}}),
+ {{caught,{error,function_clause}},
+ undefined,
+ undefined,
+ finalized} =
nested_catch_1({{'add',{2,c}},rethrow,void},
- void, {'abs',V}, function_clause),
+ void, {'abs',V}, function_clause),
ok.
nested_catch_1({X1,C1,V1},
@@ -694,64 +694,64 @@ nested_catch_1({X1,C1,V1},
nested_after(Conf) when is_list(Conf) ->
V = [{make_ref(),1.4142136,self()}],
- ?line {value,
+ {value,
{V,x3},
{value1,{V,x2}},
finalized} =
nested_after_1({{value,{V,x1}},void,{V,x1}},
{value,{V,x2}}, {value,{V,x3}}),
- ?line {{caught,{error,{V,x2}}},
+ {{caught,{error,{V,x2}}},
{V,x3},
undefined,
finalized} =
nested_after_1({{value,{V,x1}},void,{V,x1}},
{error,{V,x2}}, {value,{V,x3}}),
- ?line {{caught,{exit,{V,x3}}},
+ {{caught,{exit,{V,x3}}},
undefined,
undefined,
finalized} =
nested_after_1({{value,{V,x1}},void,{V,x1}},
{error,{V,x2}}, {exit,{V,x3}}),
%%
- ?line {{caught,{error,{try_clause,{V,x1}}}},
+ {{caught,{error,{try_clause,{V,x1}}}},
{V,x3},
undefined,
finalized} =
nested_after_1({{value,{V,x1}},void,try_clause},
void, {value,{V,x3}}),
- ?line {{caught,{error,badarith}},
+ {{caught,{error,badarith}},
undefined,
undefined,
finalized} =
nested_after_1({{value,{V,x1}},void,try_clause},
void, {'div',{17,0}}),
%%
- ?line {value,
+ {value,
{V,x3},
{caught1,{V,x2}},
finalized} =
nested_after_1({{throw,{V,x1}},throw,{V,x1}},
{value,{V,x2}}, {value,{V,x3}}),
- ?line {{caught,{error,badarith}},
+ {{caught,{error,badarith}},
{V,x3},
undefined,
finalized} =
nested_after_1({{throw,{V,x1}},throw,{V,x1}},
{'add',{a,b}}, {value,{V,x3}}),
- ?line {{caught,{error,badarg}},
+ {{caught,{error,badarg}},
undefined,
undefined,
finalized} =
nested_after_1({{throw,{V,x1}},throw,{V,x1}},
{'add',{a,b}}, {'abs',V}),
%%
- ?line {{caught,{throw,{V,x1}}},
+ {{caught,{throw,{V,x1}}},
{V,x3},
undefined,
finalized} =
nested_after_1({{throw,{V,x1}},rethrow,void},
void, {value,{V,x3}}),
- ?line {{caught,{error,badarith}},
+ {{caught,{error,badarith}},
undefined,
undefined,
finalized} =
@@ -843,12 +843,12 @@ my_abs(X) -> abs(X).
last_call_optimization(Config) when is_list(Config) ->
- ?line error = in_tail(dum),
- ?line StkSize0 = in_tail(0),
- ?line StkSize = in_tail(50000),
+ error = in_tail(dum),
+ StkSize0 = in_tail(0),
+ StkSize = in_tail(50000),
io:format("StkSize0 = ~p", [StkSize0]),
io:format("StkSize = ~p", [StkSize]),
- ?line StkSize = StkSize0,
+ StkSize = StkSize0,
ok.
in_tail(E) ->
@@ -891,20 +891,20 @@ do_bool(A0, B) ->
plain_catch_coverage(Config) when is_list(Config) ->
%% Cover some code in beam_block:alloc_may_pass/1.
- ?line {a,[42]} = do_plain_catch_list(42).
+ {a,[42]} = do_plain_catch_list(42).
do_plain_catch_list(X) ->
B = [X],
catch id({a,B}).
andalso_orelse(Config) when is_list(Config) ->
- ?line {2,{a,42}} = andalso_orelse_1(true, {a,42}),
- ?line {b,{b}} = andalso_orelse_1(false, {b}),
- ?line {catched,no_tuple} = andalso_orelse_1(false, no_tuple),
+ {2,{a,42}} = andalso_orelse_1(true, {a,42}),
+ {b,{b}} = andalso_orelse_1(false, {b}),
+ {catched,no_tuple} = andalso_orelse_1(false, no_tuple),
- ?line ok = andalso_orelse_2({type,[a]}),
- ?line also_ok = andalso_orelse_2({type,[]}),
- ?line also_ok = andalso_orelse_2({type,{a}}),
+ ok = andalso_orelse_2({type,[a]}),
+ also_ok = andalso_orelse_2({type,[]}),
+ also_ok = andalso_orelse_2({type,{a}}),
ok.
andalso_orelse_1(A, B) ->
@@ -919,8 +919,6 @@ andalso_orelse_1(A, B) ->
catched
end,B}.
-id(I) -> I.
-
andalso_orelse_2({Type,Keyval}) ->
try
if is_atom(Type) andalso length(Keyval) > 0 -> ok;
@@ -957,3 +955,89 @@ hockey() ->
receive _ -> (b = fun() -> ok end)
+ hockey, +x after 0 -> ok end, try (a = fun() -> ok end) + hockey, +
y catch _ -> ok end.
+
+
+-record(state, {foo}).
+
+handle_info(_Config) ->
+ do_handle_info({foo}, #state{}),
+ ok.
+
+do_handle_info({_}, State) ->
+ handle_info_ok(),
+ State#state{foo = bar},
+ case ok of
+ _ ->
+ case catch handle_info_ok() of
+ ok ->
+ {stop, State}
+ end
+ end;
+do_handle_info(_, State) ->
+ (catch begin
+ handle_info_ok(),
+ State#state{foo = bar}
+ end),
+ case ok of
+ _ ->
+ case catch handle_info_ok() of
+ ok ->
+ {stop, State}
+ end
+ end.
+
+handle_info_ok() -> ok.
+
+'catch_in_catch'(_Config) ->
+ process_flag(trap_exit, true),
+ Pid = spawn_link(fun() ->
+ catch_in_catch_init(x),
+ exit(good_exit)
+ end),
+ receive
+ {'EXIT',Pid,good_exit} ->
+ ok;
+ Other ->
+ io:format("Unexpected: ~p\n", [Other]),
+ error
+ after 32000 ->
+ io:format("No message received\n"),
+ error
+ end.
+
+'catch_in_catch_init'(Param) ->
+ process_flag(trap_exit, true),
+ %% The catches were improperly nested, causing a "No catch found" crash.
+ (catch begin
+ id(Param),
+ (catch exit(bar))
+ end
+ ),
+ ignore.
+
+grab_bag(_Config) ->
+ %% Thanks to Martin Bjorklund.
+ _ = fun() -> ok end,
+ try
+ fun() -> ok end
+ after
+ fun({A, B}) -> A + B end
+ end,
+
+ %% Thanks to Tim Rath.
+ A = {6},
+ try
+ io:fwrite("")
+ after
+ fun () ->
+ fun () -> {_} = A end
+ end
+ end,
+
+ %% Unnecessary catch.
+ 22 = (catch 22),
+
+ ok.
+
+
+id(I) -> I.
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index a964afe5a1..857995b6a6 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2017. 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.
@@ -27,9 +27,9 @@
-define(privdir, "warnings_SUITE_priv").
-define(t, test_server).
-else.
--include_lib("test_server/include/test_server.hrl").
--define(datadir, ?config(data_dir, Conf)).
--define(privdir, ?config(priv_dir, Conf)).
+-include_lib("common_test/include/ct.hrl").
+-define(datadir, proplists:get_value(data_dir, Conf)).
+-define(privdir, proplists:get_value(priv_dir, Conf)).
-endif.
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
@@ -41,21 +41,18 @@
files/1,effect/1,bin_opt_info/1,bin_construction/1,
comprehensions/1,maps/1,maps_bin_opt_info/1,
redundant_boolean_clauses/1,
- latin1_fallback/1,underscore/1,no_warnings/1]).
-
-% Default timetrap timeout (set in init_per_testcase).
--define(default_timeout, ?t:minutes(2)).
+ latin1_fallback/1,underscore/1,no_warnings/1,
+ bit_syntax/1,inlining/1]).
init_per_testcase(_Case, Config) ->
- ?line Dog = ?t:timetrap(?default_timeout),
- [{watchdog, Dog} | Config].
+ Config.
-end_per_testcase(_Case, Config) ->
- Dog = ?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
+end_per_testcase(_Case, _Config) ->
ok.
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,2}}].
all() ->
test_lib:recompile(?MODULE),
@@ -68,7 +65,7 @@ groups() ->
bin_opt_info,bin_construction,comprehensions,maps,
maps_bin_opt_info,
redundant_boolean_clauses,latin1_fallback,
- underscore,no_warnings]}].
+ underscore,no_warnings,bit_syntax,inlining]}].
init_per_suite(Config) ->
Config.
@@ -103,7 +100,7 @@ pattern(Config) when is_list(Config) ->
[{2,v3_core,nomatch},
{6,v3_core,nomatch},
{11,v3_core,nomatch} ] }}],
- ?line [] = run(Config, Ts),
+ [] = run(Config, Ts),
ok.
pattern2(Config) when is_list(Config) ->
@@ -127,7 +124,7 @@ pattern2(Config) when is_list(Config) ->
{4,sys_core_fold,no_clause_match},
{5,sys_core_fold,nomatch_clause_type},
{6,sys_core_fold,nomatch_clause_type}]}}],
- ?line [] = run(Config, Ts),
+ [] = run(Config, Ts),
%% Disable Core Erlang optimizations. v3_kernel should produce
%% a warning for the clause that didn't match.
@@ -136,7 +133,7 @@ pattern2(Config) when is_list(Config) ->
[nowarn_unused_vars,no_copt],
{warnings,
[{2,v3_kernel,{nomatch_shadow,1}}]}}],
- ?line [] = run(Config, Ts2),
+ [] = run(Config, Ts2),
ok.
pattern3(Config) when is_list(Config) ->
@@ -152,7 +149,7 @@ pattern3(Config) when is_list(Config) ->
[nowarn_unused_vars],
{warnings,
[{4,v3_kernel,{nomatch_shadow,2}}]}}],
- ?line [] = run(Config, Ts),
+ [] = run(Config, Ts),
ok.
@@ -213,7 +210,7 @@ pattern4(Config) when is_list(Config) ->
{23,sys_core_fold,no_clause_match},
{33,sys_core_fold,no_clause_match}
]}}],
- ?line [] = run(Config, Ts),
+ [] = run(Config, Ts),
ok.
@@ -256,7 +253,7 @@ guard(Config) when is_list(Config) ->
{11,sys_core_fold,nomatch_guard},
{11,sys_core_fold,{eval_failure,badarg}}
]}}],
- ?line [] = run(Config, Ts),
+ [] = run(Config, Ts),
ok.
@@ -284,7 +281,6 @@ bad_arith(Config) when is_list(Config) ->
{3,sys_core_fold,{eval_failure,badarith}},
{9,sys_core_fold,nomatch_guard},
{9,sys_core_fold,{eval_failure,badarith}},
- {9,sys_core_fold,{no_effect,{erlang,is_integer,1}}},
{10,sys_core_fold,nomatch_guard},
{10,sys_core_fold,{eval_failure,badarith}},
{15,sys_core_fold,{eval_failure,badarith}}
@@ -321,7 +317,7 @@ bool_cases(Config) when is_list(Config) ->
[{6,sys_core_fold,nomatch_shadow},
{13,sys_core_fold,nomatch_shadow},
{18,sys_core_fold,nomatch_clause_type} ]} }],
- ?line [] = run(Config, Ts),
+ [] = run(Config, Ts),
ok.
bad_apply(Config) when is_list(Config) ->
@@ -340,11 +336,11 @@ bad_apply(Config) when is_list(Config) ->
{4,v3_kernel,bad_call},
{5,v3_kernel,bad_call},
{6,v3_kernel,bad_call}]}}],
- ?line [] = run(Config, Ts),
+ [] = run(Config, Ts),
%% Also verify that the generated code generates the correct error.
- ?line try erlang:42() of
- _ -> ?line ?t:fail()
+ try erlang:42() of
+ _ -> ct:fail(should_fail)
catch
error:badarg -> ok
end,
@@ -368,7 +364,7 @@ files(Config) when is_list(Config) ->
[{"file1",[{17,sys_core_fold,{eval_failure,badarith}}]},
{"file2",[{10,sys_core_fold,{eval_failure,badarith}}]}]}}],
- ?line [] = run(Config, Ts),
+ [] = run(Config, Ts),
ok.
%% Test warnings for term construction and BIF calls in effect context.
@@ -514,7 +510,7 @@ effect(Config) when is_list(Config) ->
{28,sys_core_fold,useless_building},
{36,sys_core_fold,{no_effect,{erlang,'=:=',2}}},
{38,sys_core_fold,{no_effect,{erlang,get_cookie,0}}}]}}],
- ?line [] = run(Config, Ts),
+ [] = run(Config, Ts),
ok.
bin_opt_info(Config) when is_list(Config) ->
@@ -533,18 +529,18 @@ bin_opt_info(Config) when is_list(Config) ->
Code,
[bin_opt_info],
{warnings,
- [{4,sys_core_fold,orig_bin_var_used_in_guard},
+ [{4,sys_core_bsm,orig_bin_var_used_in_guard},
{5,beam_bsm,{no_bin_opt,{{t1,1},no_suitable_bs_start_match}}},
{9,beam_bsm,{no_bin_opt,
{binary_used_in,{extfunc,erlang,split_binary,2}}}} ]}}],
- ?line [] = run(Config, Ts1),
+ [] = run(Config, Ts1),
%% For coverage: don't give the bin_opt_info option.
Ts2 = [{bsm2,
Code,
[],
[]}],
- ?line [] = run(Config, Ts2),
+ [] = run(Config, Ts2),
ok.
bin_construction(Config) when is_list(Config) ->
@@ -561,7 +557,7 @@ bin_construction(Config) when is_list(Config) ->
[],
{warnings,[{4,sys_core_fold,embedded_binary_size},
{8,sys_core_fold,{embedded_unit,8,28}}]}}],
- ?line [] = run(Config, Ts),
+ [] = run(Config, Ts),
ok.
@@ -632,7 +628,112 @@ maps(Config) when is_list(Config) ->
id(I) -> I.
">>,
[],
- []}],
+ []},
+ {repeated_keys1,
+ <<"
+ foo1() ->
+ #{a=>1,
+ b=> 2,
+ a=>3}.
+
+ bar1(M) ->
+ M#{a=>1, b=> 2, a:=3}.
+
+ baz1(M) ->
+ M#{a=>1, b=> 2, a:=3}.
+
+ foo2() ->
+ #{\"a\"=>1, \"b\"=> 2, \"a\"=>3}.
+
+ bar2(M) ->
+ M#{\"a\"=>1, \"b\"=> 2, \"a\":=3}.
+
+ baz2(M) ->
+ M#{\"a\"=>1, \"b\"=> 2, \"a\":=3}.
+
+ foo3() ->
+ #{\"a\"=>1,
+ \"b\"=> 2,
+ \"a\"=>3}.
+
+ bar3(M) ->
+ M#{\"a\"=>1, \"b\"=> 2, \"a\":=3}.
+
+ baz3(M) ->
+ M#{<<\"a\">>=>1, <<\"b\">>=> 2, <<\"a\">>:=3}.
+ ">>,
+ [],
+ {warnings,[{3,v3_core,{map_key_repeated,a}},
+ {8,v3_core,{map_key_repeated,a}},
+ {11,v3_core,{map_key_repeated,a}},
+ {14,v3_core,{map_key_repeated,"a"}},
+ {17,v3_core,{map_key_repeated,"a"}},
+ {20,v3_core,{map_key_repeated,"a"}},
+ {23,v3_core,{map_key_repeated,"a"}},
+ {28,v3_core,{map_key_repeated,"a"}},
+ {31,v3_core,{map_key_repeated,<<"a">>}}]}},
+ {repeated_keys2,
+ <<"
+ foo4(K) ->
+ #{\"a\"=>1, K => 1, \"b\"=> 2, \"a\"=>3, K=>2}.
+
+ bar4(M,K) ->
+ M#{a=>1, K =>1, b=> 2, a:=3, K=>2}.
+
+ baz4(M,K) ->
+ M#{<<\"a\">>=>1,
+ K => 1, <<\"b\">>=> 2,
+ <<\"a\">>:=3, K=>2}.
+
+ foo5(K) ->
+ #{{\"a\",1}=>1, K => 1, \"b\"=> 2, {\"a\",1}=>3, K=>2}.
+
+ bar5(M,K) ->
+ M#{{\"a\",<<\"b\">>}=>1, K =>1,
+ \"b\"=> 2, {\"a\",<<\"b\">>}:=3, K=>2}.
+
+ baz5(M,K) ->
+ M#{{<<\"a\">>,1}=>1, K => 1,
+ <<\"b\">>=> 2, {<<\"a\">>,1}:=3,K=>2}.
+
+ foo6(K) ->
+ #{#{\"a\"=>1}=>1, K => 1, \"b\"=> 2, #{\"a\"=>1}=>3, K=>2}.
+
+ bar6(M,K) ->
+ M#{#{\"a\"=><<\"b\">>}=>1, K =>1,
+ \"b\"=> 2, #{\"a\"=><<\"b\">>}:=3, K=>2}.
+
+ baz6(M,K) ->
+ M#{#{<<\"a\">>=>1}=>1,
+ K => 1,
+ <<\"b\">>=> 2,
+ #{<<\"a\">>=>1}:=3,K=>2}.
+
+ foo7(K) ->
+ M1 = #{#{\"a\"=>1}=>1, K => 1, \"b\"=> 2},
+ M1#{#{\"a\"=>1}=>3, K=>2}.
+
+ bar7(M,K) ->
+ M1 = M#{#{\"a\"=><<\"b\">>}=>1, K =>1, \"b\"=> 2},
+ M1#{#{\"a\"=><<\"b\">>}:=3, K=>2}.
+
+ baz7(M,K) ->
+ M1 = M#{#{<<\"a\">>=>1}=>1,
+ K => 1,
+ <<\"b\">>=> 2},
+ M1#{#{<<\"a\">>=>1}:=3,K=>2}.
+ ">>,
+ [],
+ {warnings,[{3,v3_core,{map_key_repeated,"a"}},
+ {6,v3_core,{map_key_repeated,a}},
+ {9,v3_core,{map_key_repeated,<<"a">>}},
+ {14,v3_core,{map_key_repeated,{"a",1}}},
+ {17,v3_core,{map_key_repeated,{"a",<<"b">>}}},
+ {21,v3_core,{map_key_repeated,{<<"a">>,1}}},
+ {25,v3_core,{map_key_repeated,#{"a" => 1}}},
+ {28,v3_core,{map_key_repeated,#{"a" => <<"b">>}}},
+ {32,v3_core,{map_key_repeated,#{<<"a">> => 1}}}]}}
+ ],
run(Config, Ts),
ok.
@@ -783,6 +884,74 @@ no_warnings(Config) when is_list(Config) ->
run(Config, Ts),
ok.
+bit_syntax(Config) ->
+ Ts = [{?FUNCTION_NAME,
+ <<"a(<<-1>>) -> ok;
+ a(<<1023>>) -> ok;
+ a(<<777/signed>>) -> ok;
+ a(<<a/binary>>) -> ok;
+ a(<<a/integer>>) -> ok;
+ a(<<a/float>>) -> ok;
+ a(<<a/utf8>>) -> ok;
+ a(<<a/utf16>>) -> ok;
+ a(<<a/utf32>>) -> ok;
+ a(<<a/utf32>>) -> ok.
+ b(Bin) -> Sz = bad, <<42:Sz>> = Bin.
+ c(Sz, Bin) ->
+ case Bin of
+ <<-42:Sz/unsigned>> -> ok;
+ <<42:Sz/float>> -> ok;
+ <<42:Sz/binary>> -> ok
+ end.
+ ">>,
+ [],
+ {warnings,[{1,sys_core_fold,no_clause_match},
+ {1,sys_core_fold,{nomatch_bit_syntax_unsigned,-1}},
+ {2,sys_core_fold,{nomatch_bit_syntax_truncated,
+ unsigned,1023,8}},
+ {3,sys_core_fold,{nomatch_bit_syntax_truncated,
+ signed,777,8}},
+ {4,sys_core_fold,{nomatch_bit_syntax_type,a,binary}},
+ {5,sys_core_fold,{nomatch_bit_syntax_type,a,integer}},
+ {6,sys_core_fold,{nomatch_bit_syntax_type,a,float}},
+ {7,sys_core_fold,{nomatch_bit_syntax_type,a,utf8}},
+ {8,sys_core_fold,{nomatch_bit_syntax_type,a,utf16}},
+ {9,sys_core_fold,{nomatch_bit_syntax_type,a,utf32}},
+ {10,sys_core_fold,{nomatch_bit_syntax_type,a,utf32}},
+ {11,sys_core_fold,no_clause_match},
+ {11,sys_core_fold,{nomatch_bit_syntax_size,bad}},
+ {14,sys_core_fold,{nomatch_bit_syntax_unsigned,-42}},
+ {16,sys_core_fold,{nomatch_bit_syntax_type,42,binary}}
+ ]}
+ }],
+ run(Config, Ts),
+ ok.
+
+inlining(Config) ->
+ %% Make sure that no spurious warnings are generated
+ %% when inlining.
+ Ts = [{inlining_1,
+ <<"-compile(inline).
+ compute1(X) -> add(X, 0).
+ add(1, 0) -> 1;
+ add(1, Y) -> 1 + Y;
+ add(X, Y) -> X + Y.
+ ">>,
+ [],
+ []},
+ {inlining_2,
+ <<"-compile({inline,[add/2]}).
+ compute1(X) -> add(X, 0).
+ add(1, 0) -> 1;
+ add(1, Y) -> 1 + Y;
+ add(X, Y) -> X + Y.
+ ">>,
+ [],
+ []}
+ ],
+ run(Config, Ts),
+ ok.
+
%%%
%%% End of test cases.
%%%
@@ -793,7 +962,7 @@ run(Config, Tests) ->
E ->
BadL;
Bad ->
- ?t:format("~nTest ~p failed. Expected~n ~p~n"
+ io:format("~nTest ~p failed. Expected~n ~p~n"
"but got~n ~p~n", [N, E, Bad]),
fail()
end
@@ -806,33 +975,32 @@ run(Config, Tests) ->
run_test(Conf, Test0, Warnings) ->
Module = "warnings_"++test_lib:uniq(),
Filename = Module ++ ".erl",
- ?line DataDir = ?privdir,
+ DataDir = ?privdir,
Test = ["-module(", Module, "). ", Test0],
- ?line File = filename:join(DataDir, Filename),
- ?line Opts = [binary,export_all,return|Warnings],
- ?line ok = file:write_file(File, Test),
+ File = filename:join(DataDir, Filename),
+ Opts = [binary,export_all,return|Warnings],
+ ok = file:write_file(File, Test),
%% Compile once just to print all warnings.
- ?line compile:file(File, [binary,export_all,report|Warnings]),
+ compile:file(File, [binary,export_all,report|Warnings]),
%% Test result of compilation.
- ?line Res = case compile:file(File, Opts) of
- {ok, _M, Bin, []} when is_binary(Bin) ->
- [];
- {ok, _M, Bin, Ws0} when is_binary(Bin) ->
- %% We are not interested in warnings from
- %% erl_lint here.
- WsL = [{F,[W || {_,Mod,_}=W <- Ws,
- Mod =/= erl_lint]} ||
- {F,Ws} <- Ws0],
- case WsL of
- [{_File,Ws}] -> {warnings, Ws};
- _ -> list_to_tuple([warnings, WsL])
- end
- end,
+ Res = case compile:file(File, Opts) of
+ {ok, _M, Bin, []} when is_binary(Bin) ->
+ [];
+ {ok, _M, Bin, Ws0} when is_binary(Bin) ->
+ %% We are not interested in warnings from
+ %% erl_lint here.
+ WsL = [{F,[W || {_,Mod,_}=W <- Ws,
+ Mod =/= erl_lint]} ||
+ {F,Ws} <- Ws0],
+ case WsL of
+ [{_File,Ws}] -> {warnings, Ws};
+ _ -> list_to_tuple([warnings, WsL])
+ end
+ end,
file:delete(File),
Res.
fail() ->
- io:format("failed~n"),
- ?t:fail().
+ ct:fail(failed).
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index 187de0ca47..435a57aac2 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 6.0.3.1
+COMPILER_VSN = 7.1.3